Merge lp:~ipython-dev/ipython/kernel-config into lp:ipython/0.11

Proposed by Brian Granger
Status: Merged
Merged at revision: not available
Proposed branch: lp:~ipython-dev/ipython/kernel-config
Merge into: lp:ipython/0.11
Diff against target: 11644 lines (+6503/-3129)
79 files modified
IPython/config/api.py (+0/-102)
IPython/config/default/ipcluster_config.py (+184/-0)
IPython/config/default/ipcontroller_config.py (+136/-0)
IPython/config/default/ipengine_config.py (+90/-0)
IPython/config/default/ipython_config.py (+4/-4)
IPython/config/loader.py (+9/-2)
IPython/config/profile/ipython_config_cluster.py (+24/-0)
IPython/core/application.py (+125/-61)
IPython/core/builtin_trap.py (+1/-0)
IPython/core/component.py (+24/-3)
IPython/core/crashhandler.py (+1/-1)
IPython/core/debugger.py (+76/-121)
IPython/core/display_trap.py (+5/-5)
IPython/core/embed.py (+2/-10)
IPython/core/ipapi.py (+4/-1)
IPython/core/ipapp.py (+70/-72)
IPython/core/iplib.py (+43/-25)
IPython/core/magic.py (+56/-29)
IPython/core/oldusersetup.py (+0/-219)
IPython/core/prefilter.py (+1/-1)
IPython/core/tests/test_iplib.py (+1/-24)
IPython/core/usage.py (+7/-7)
IPython/extensions/parallelmagic.py (+181/-147)
IPython/frontend/wx/ipythonx.py (+2/-3)
IPython/gui/wx/wxIPython.py (+2/-2)
IPython/kernel/asyncclient.py (+13/-12)
IPython/kernel/client.py (+35/-43)
IPython/kernel/clientconnector.py (+735/-112)
IPython/kernel/clusterdir.py (+475/-0)
IPython/kernel/config/__init__.py (+0/-126)
IPython/kernel/configobjfactory.py (+79/-0)
IPython/kernel/core/config/__init__.py (+0/-25)
IPython/kernel/engineconnector.py (+79/-32)
IPython/kernel/error.py (+8/-6)
IPython/kernel/fcutil.py (+230/-26)
IPython/kernel/ipclusterapp.py (+471/-0)
IPython/kernel/ipcontrollerapp.py (+275/-0)
IPython/kernel/ipengineapp.py (+248/-0)
IPython/kernel/launcher.py (+869/-0)
IPython/kernel/multiengine.py (+2/-3)
IPython/kernel/multiengineclient.py (+11/-3)
IPython/kernel/scripts/ipcluster (+10/-14)
IPython/kernel/scripts/ipcluster.py (+0/-813)
IPython/kernel/scripts/ipcontroller (+10/-12)
IPython/kernel/scripts/ipcontroller.py (+0/-416)
IPython/kernel/scripts/ipengine (+11/-11)
IPython/kernel/scripts/ipengine.py (+0/-193)
IPython/kernel/twistedutil.py (+34/-9)
IPython/kernel/winhpcjob.py (+318/-0)
IPython/lib/inputhookwx.py (+73/-62)
IPython/lib/irunner.py (+3/-3)
IPython/quarantine/InterpreterExec.py (+1/-1)
IPython/quarantine/ipy_fsops.py (+2/-2)
IPython/utils/genutils.py (+95/-86)
IPython/utils/notification.py (+86/-68)
IPython/utils/tests/test_notification.py (+72/-79)
IPython/utils/traitlets.py (+34/-4)
docs/Makefile (+2/-0)
docs/autogen_api.py (+1/-0)
docs/examples/core/new-embed.py (+17/-0)
docs/examples/kernel/fractal.py (+90/-0)
docs/examples/kernel/mcdriver.py (+54/-54)
docs/examples/kernel/mcpricer.py (+42/-40)
docs/examples/kernel/parallelpi.py (+54/-0)
docs/examples/kernel/pidigits.py (+144/-0)
docs/examples/kernel/wordfreq.py (+48/-5)
docs/man/ipcluster.1 (+1/-1)
docs/man/ipython.1 (+6/-6)
docs/source/conf.py (+8/-5)
docs/source/config/overview.txt (+4/-4)
docs/source/development/index.txt (+1/-0)
docs/source/development/ipgraph.txt (+59/-0)
docs/source/interactive/reference.txt (+9/-9)
docs/source/parallel/index.txt (+2/-0)
docs/source/parallel/parallel_demos.txt (+282/-0)
docs/source/parallel/parallel_winhpc.txt (+333/-0)
docs/source/parallel/winhpc_index.txt (+14/-0)
setup.py (+3/-3)
setupbase.py (+2/-2)
To merge this branch: bzr merge lp:~ipython-dev/ipython/kernel-config
Reviewer Review Type Date Requested Status
Fernando Perez Approve
Vishal Vatsa Pending
Review via email: mp+14900@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Brian Granger (ellisonbg) wrote :

This is the result of a massive effort to refactor IPython.kernel to use the new config system. This also includes an improved ipcluster/ipcontroller/ipengine command line programs. Here are the main files that should be reviewed:

IPython.kernel:

* clusterdir.py
* ipcontrollerapp.py
* ipengineapp.py
* launcher.py
* ipclusterapp.py

IPython.config.default:

* ipcontroller_config.py
* ipengine_config.py
* ipcluster_config.py

I have also fixed a number of bugs and problems in IPython itself:

* The command line options use a new style.
* %debug is fixed.
* New magics %load_ext/%unload_ext/%reload_ext/%install_profiles/%install_default_config.

Enjoy!

1269. By Brian Granger

Added better documentation to command line programs.

1270. By Brian Granger

Initial draft of Windows HPC documentation.

1271. By Brian Granger

Work in the documentation.

1272. By bgranger <bgranger@red>

Adding figures for options pricing example.

1273. By Brian Granger

Final work on the Win HPC whitepaper.

Revision history for this message
Fernando Perez (fdo.perez) wrote :

Summary: Excellent work! Many thanks for all of this.

I'm not merging it now just in case you want to do it yourself tomorrow (12/30) first thing or have some other little change you'd like to put in. But if you don't merge it I'll go ahead and do it, and will begin adding code I have (like testing stuff) so we can push towards 0.11. We still have cleanups and things to do, but all of that is best done on top of a more functional trunk, which this branch helps LOT with.

Per-commit comments:

-r1264: ok

-r1265: in kernel/ipclusterapp.py, should we output something visible to the user indicating the 4s pause at shutdown? I won't add it myself, as I'm not sure this should go in; most of our output is now via logging, right? Putting this in the log wouldn't be too useful, it would be strictly a convenience for the user.

-r1266: ok, just upstream

-r1267: great, more examples!

-r1268: good, these are changes we'd discussed over the phone.

-r1269: better docs, excellent...

-r1270, 71, 72, 73: this document is stellar, we'd reviewed it already.

review: Approve
Revision history for this message
Brian Granger (ellisonbg) wrote :

> I'm not merging it now just in case you want to do it yourself tomorrow (12/30) first thing or have some other little change you'd like to put in.  But if you don't merge it I'll go ahead and do it, and will begin adding code I have (like testing stuff) so we can push towards 0.11.  We still have cleanups and things to do, but all of that is best done on top of a more functional trunk, which this branch helps LOT with.

Thanks for the review. Go ahead and do the merge, I am working on
other things right now.

> Per-commit comments:
>
> -r1264: ok
>
> -r1265: in kernel/ipclusterapp.py, should we output something visible to the user indicating the 4s pause at shutdown?  I won't add it myself, as I'm not sure this should go in; most of our output is now via logging, right?  Putting this in the log wouldn't be too useful, it would be strictly a convenience for the user.

Yes, I can add a message about this to the logs.

> -r1266: ok, just upstream
>
> -r1267: great, more examples!
>
> -r1268: good, these are changes we'd discussed over the phone.
>
> -r1269: better docs, excellent...
>
> -r1270, 71, 72, 73: this document is stellar, we'd reviewed it already.
>
> --
> https://code.launchpad.net/~ipython-dev/ipython/kernel-config/+merge/14900
> You proposed lp:~ipython-dev/ipython/kernel-config for merging.
>

--
Brian E. Granger, Ph.D.
Assistant Professor of Physics
Cal Poly State University, San Luis Obispo
<email address hidden>
<email address hidden>

Revision history for this message
Fernando Perez (fdo.perez) wrote :

On Wed, Dec 30, 2009 at 8:39 AM, Brian Granger <email address hidden> wrote:
>
> Thanks for the review.  Go ahead and do the merge, I am working on
> other things right now

Done, merged and pushed with an extra tiny fix. Thanks again, great job!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== removed file 'IPython/config/api.py'
--- IPython/config/api.py 2009-07-02 02:49:32 +0000
+++ IPython/config/api.py 1970-01-01 00:00:00 +0000
@@ -1,102 +0,0 @@
1# encoding: utf-8
2
3"""This is the official entry point to IPython's configuration system. """
4
5__docformat__ = "restructuredtext en"
6
7#-------------------------------------------------------------------------------
8# Copyright (C) 2008 The IPython Development Team
9#
10# Distributed under the terms of the BSD License. The full license is in
11# the file COPYING, distributed as part of this software.
12#-------------------------------------------------------------------------------
13
14#-------------------------------------------------------------------------------
15# Imports
16#-------------------------------------------------------------------------------
17
18import os
19from os.path import join as pjoin
20
21from IPython.utils.genutils import get_home_dir, get_ipython_dir
22from IPython.external.configobj import ConfigObj
23
24
25class ConfigObjManager(object):
26
27 def __init__(self, configObj, filename):
28 self.current = configObj
29 self.current.indent_type = ' '
30 self.filename = filename
31 # self.write_default_config_file()
32
33 def get_config_obj(self):
34 return self.current
35
36 def update_config_obj(self, newConfig):
37 self.current.merge(newConfig)
38
39 def update_config_obj_from_file(self, filename):
40 newConfig = ConfigObj(filename, file_error=False)
41 self.current.merge(newConfig)
42
43 def update_config_obj_from_default_file(self, ipythondir=None):
44 fname = self.resolve_file_path(self.filename, ipythondir)
45 self.update_config_obj_from_file(fname)
46
47 def write_config_obj_to_file(self, filename):
48 f = open(filename, 'w')
49 self.current.write(f)
50 f.close()
51
52 def write_default_config_file(self):
53 ipdir = get_ipython_dir()
54 fname = pjoin(ipdir, self.filename)
55 if not os.path.isfile(fname):
56 print "Writing the configuration file to: " + fname
57 self.write_config_obj_to_file(fname)
58
59 def _import(self, key):
60 package = '.'.join(key.split('.')[0:-1])
61 obj = key.split('.')[-1]
62 execString = 'from %s import %s' % (package, obj)
63 exec execString
64 exec 'temp = %s' % obj
65 return temp
66
67 def resolve_file_path(self, filename, ipythondir = None):
68 """Resolve filenames into absolute paths.
69
70 This function looks in the following directories in order:
71
72 1. In the current working directory or by absolute path with ~ expanded
73 2. In ipythondir if that is set
74 3. In the IPYTHONDIR environment variable if it exists
75 4. In the ~/.ipython directory
76
77 Note: The IPYTHONDIR is also used by the trunk version of IPython so
78 changing it will also affect it was well.
79 """
80
81 # In cwd or by absolute path with ~ expanded
82 trythis = os.path.expanduser(filename)
83 if os.path.isfile(trythis):
84 return trythis
85
86 # In ipythondir if it is set
87 if ipythondir is not None:
88 trythis = pjoin(ipythondir, filename)
89 if os.path.isfile(trythis):
90 return trythis
91
92 trythis = pjoin(get_ipython_dir(), filename)
93 if os.path.isfile(trythis):
94 return trythis
95
96 return None
97
98
99
100
101
102
1030
=== added file 'IPython/config/default/ipcluster_config.py'
--- IPython/config/default/ipcluster_config.py 1970-01-01 00:00:00 +0000
+++ IPython/config/default/ipcluster_config.py 2009-11-21 00:11:10 +0000
@@ -0,0 +1,184 @@
1import os
2
3c = get_config()
4
5#-----------------------------------------------------------------------------
6# Select which launchers to use
7#-----------------------------------------------------------------------------
8
9# This allows you to control what method is used to start the controller
10# and engines. The following methods are currently supported:
11# - Start as a regular process on localhost.
12# - Start using mpiexec.
13# - Start using the Windows HPC Server 2008 scheduler
14# - Start using PBS
15# - Start using SSH (currently broken)
16
17
18# The selected launchers can be configured below.
19
20# Options are:
21# - LocalControllerLauncher
22# - MPIExecControllerLauncher
23# - PBSControllerLauncher
24# - WindowsHPCControllerLauncher
25# c.Global.controller_launcher = 'IPython.kernel.launcher.LocalControllerLauncher'
26
27# Options are:
28# - LocalEngineSetLauncher
29# - MPIExecEngineSetLauncher
30# - PBSEngineSetLauncher
31# - WindowsHPCEngineSetLauncher
32# c.Global.engine_launcher = 'IPython.kernel.launcher.LocalEngineSetLauncher'
33
34#-----------------------------------------------------------------------------
35# Global configuration
36#-----------------------------------------------------------------------------
37
38# The default number of engines that will be started. This is overridden by
39# the -n command line option: "ipcluster start -n 4"
40# c.Global.n = 2
41
42# Log to a file in cluster_dir/log, otherwise just log to sys.stdout.
43# c.Global.log_to_file = False
44
45# Remove old logs from cluster_dir/log before starting.
46# c.Global.clean_logs = True
47
48# The working directory for the process. The application will use os.chdir
49# to change to this directory before starting.
50# c.Global.work_dir = os.getcwd()
51
52
53#-----------------------------------------------------------------------------
54# Local process launchers
55#-----------------------------------------------------------------------------
56
57# The command line arguments to call the controller with.
58# c.LocalControllerLauncher.controller_args = \
59# ['--log-to-file','--log-level', '40']
60
61# The working directory for the controller
62# c.LocalEngineSetLauncher.work_dir = u''
63
64# Command line argument passed to the engines.
65# c.LocalEngineSetLauncher.engine_args = ['--log-to-file','--log-level', '40']
66
67#-----------------------------------------------------------------------------
68# MPIExec launchers
69#-----------------------------------------------------------------------------
70
71# The mpiexec/mpirun command to use in started the controller.
72# c.MPIExecControllerLauncher.mpi_cmd = ['mpiexec']
73
74# Additional arguments to pass to the actual mpiexec command.
75# c.MPIExecControllerLauncher.mpi_args = []
76
77# The command line argument to call the controller with.
78# c.MPIExecControllerLauncher.controller_args = \
79# ['--log-to-file','--log-level', '40']
80
81
82# The mpiexec/mpirun command to use in started the controller.
83# c.MPIExecEngineSetLauncher.mpi_cmd = ['mpiexec']
84
85# Additional arguments to pass to the actual mpiexec command.
86# c.MPIExecEngineSetLauncher.mpi_args = []
87
88# Command line argument passed to the engines.
89# c.MPIExecEngineSetLauncher.engine_args = ['--log-to-file','--log-level', '40']
90
91# The default number of engines to start if not given elsewhere.
92# c.MPIExecEngineSetLauncher.n = 1
93
94#-----------------------------------------------------------------------------
95# SSH launchers
96#-----------------------------------------------------------------------------
97
98# Todo
99
100
101#-----------------------------------------------------------------------------
102# Unix batch (PBS) schedulers launchers
103#-----------------------------------------------------------------------------
104
105# The command line program to use to submit a PBS job.
106# c.PBSControllerLauncher.submit_command = 'qsub'
107
108# The command line program to use to delete a PBS job.
109# c.PBSControllerLauncher.delete_command = 'qdel'
110
111# A regular expression that takes the output of qsub and find the job id.
112# c.PBSControllerLauncher.job_id_regexp = r'\d+'
113
114# The batch submission script used to start the controller. This is where
115# environment variables would be setup, etc. This string is interpolated using
116# the Itpl module in IPython.external. Basically, you can use ${n} for the
117# number of engine and ${cluster_dir} for the cluster_dir.
118# c.PBSControllerLauncher.batch_template = """"""
119
120# The name of the instantiated batch script that will actually be used to
121# submit the job. This will be written to the cluster directory.
122# c.PBSControllerLauncher.batch_file_name = u'pbs_batch_script_controller'
123
124
125# The command line program to use to submit a PBS job.
126# c.PBSEngineSetLauncher.submit_command = 'qsub'
127
128# The command line program to use to delete a PBS job.
129# c.PBSEngineSetLauncher.delete_command = 'qdel'
130
131# A regular expression that takes the output of qsub and find the job id.
132# c.PBSEngineSetLauncher.job_id_regexp = r'\d+'
133
134# The batch submission script used to start the engines. This is where
135# environment variables would be setup, etc. This string is interpolated using
136# the Itpl module in IPython.external. Basically, you can use ${n} for the
137# number of engine and ${cluster_dir} for the cluster_dir.
138# c.PBSEngineSetLauncher.batch_template = """"""
139
140# The name of the instantiated batch script that will actually be used to
141# submit the job. This will be written to the cluster directory.
142# c.PBSEngineSetLauncher.batch_file_name = u'pbs_batch_script_engines'
143
144#-----------------------------------------------------------------------------
145# Windows HPC Server 2008 launcher configuration
146#-----------------------------------------------------------------------------
147
148# c.IPControllerJob.job_name = 'IPController'
149# c.IPControllerJob.is_exclusive = False
150# c.IPControllerJob.username = r'USERDOMAIN\USERNAME'
151# c.IPControllerJob.priority = 'Highest'
152# c.IPControllerJob.requested_nodes = ''
153# c.IPControllerJob.project = 'MyProject'
154
155# c.IPControllerTask.task_name = 'IPController'
156# c.IPControllerTask.controller_cmd = [u'ipcontroller.exe']
157# c.IPControllerTask.controller_args = ['--log-to-file', '--log-level', '40']
158# c.IPControllerTask.environment_variables = {}
159
160# c.WindowsHPCControllerLauncher.scheduler = 'HEADNODE'
161# c.WindowsHPCControllerLauncher.job_file_name = u'ipcontroller_job.xml'
162
163
164# c.IPEngineSetJob.job_name = 'IPEngineSet'
165# c.IPEngineSetJob.is_exclusive = False
166# c.IPEngineSetJob.username = r'USERDOMAIN\USERNAME'
167# c.IPEngineSetJob.priority = 'Highest'
168# c.IPEngineSetJob.requested_nodes = ''
169# c.IPEngineSetJob.project = 'MyProject'
170
171# c.IPEngineTask.task_name = 'IPEngine'
172# c.IPEngineTask.engine_cmd = [u'ipengine.exe']
173# c.IPEngineTask.engine_args = ['--log-to-file', '--log-level', '40']
174# c.IPEngineTask.environment_variables = {}
175
176# c.WindowsHPCEngineSetLauncher.scheduler = 'HEADNODE'
177# c.WindowsHPCEngineSetLauncher.job_file_name = u'ipengineset_job.xml'
178
179
180
181
182
183
184
0185
=== added file 'IPython/config/default/ipcontroller_config.py'
--- IPython/config/default/ipcontroller_config.py 1970-01-01 00:00:00 +0000
+++ IPython/config/default/ipcontroller_config.py 2009-11-21 00:11:10 +0000
@@ -0,0 +1,136 @@
1from IPython.config.loader import Config
2
3c = get_config()
4
5#-----------------------------------------------------------------------------
6# Global configuration
7#-----------------------------------------------------------------------------
8
9# Basic Global config attributes
10
11# Start up messages are logged to stdout using the logging module.
12# These all happen before the twisted reactor is started and are
13# useful for debugging purposes. Can be (10=DEBUG,20=INFO,30=WARN,40=CRITICAL)
14# and smaller is more verbose.
15# c.Global.log_level = 20
16
17# Log to a file in cluster_dir/log, otherwise just log to sys.stdout.
18# c.Global.log_to_file = False
19
20# Remove old logs from cluster_dir/log before starting.
21# c.Global.clean_logs = True
22
23# A list of Python statements that will be run before starting the
24# controller. This is provided because occasionally certain things need to
25# be imported in the controller for pickling to work.
26# c.Global.import_statements = ['import math']
27
28# Reuse the controller's FURL files. If False, FURL files are regenerated
29# each time the controller is run. If True, they will be reused, *but*, you
30# also must set the network ports by hand. If set, this will override the
31# values set for the client and engine connections below.
32# c.Global.reuse_furls = True
33
34# Enable SSL encryption on all connections to the controller. If set, this
35# will override the values set for the client and engine connections below.
36# c.Global.secure = True
37
38# The working directory for the process. The application will use os.chdir
39# to change to this directory before starting.
40# c.Global.work_dir = os.getcwd()
41
42#-----------------------------------------------------------------------------
43# Configure the client services
44#-----------------------------------------------------------------------------
45
46# Basic client service config attributes
47
48# The network interface the controller will listen on for client connections.
49# This should be an IP address or hostname of the controller's host. The empty
50# string means listen on all interfaces.
51# c.FCClientServiceFactory.ip = ''
52
53# The TCP/IP port the controller will listen on for client connections. If 0
54# a random port will be used. If the controller's host has a firewall running
55# it must allow incoming traffic on this port.
56# c.FCClientServiceFactory.port = 0
57
58# The client learns how to connect to the controller by looking at the
59# location field embedded in the FURL. If this field is empty, all network
60# interfaces that the controller is listening on will be listed. To have the
61# client connect on a particular interface, list it here.
62# c.FCClientServiceFactory.location = ''
63
64# Use SSL encryption for the client connection.
65# c.FCClientServiceFactory.secure = True
66
67# Reuse the client FURL each time the controller is started. If set, you must
68# also pick a specific network port above (FCClientServiceFactory.port).
69# c.FCClientServiceFactory.reuse_furls = False
70
71#-----------------------------------------------------------------------------
72# Configure the engine services
73#-----------------------------------------------------------------------------
74
75# Basic config attributes for the engine services.
76
77# The network interface the controller will listen on for engine connections.
78# This should be an IP address or hostname of the controller's host. The empty
79# string means listen on all interfaces.
80# c.FCEngineServiceFactory.ip = ''
81
82# The TCP/IP port the controller will listen on for engine connections. If 0
83# a random port will be used. If the controller's host has a firewall running
84# it must allow incoming traffic on this port.
85# c.FCEngineServiceFactory.port = 0
86
87# The engine learns how to connect to the controller by looking at the
88# location field embedded in the FURL. If this field is empty, all network
89# interfaces that the controller is listening on will be listed. To have the
90# client connect on a particular interface, list it here.
91# c.FCEngineServiceFactory.location = ''
92
93# Use SSL encryption for the engine connection.
94# c.FCEngineServiceFactory.secure = True
95
96# Reuse the client FURL each time the controller is started. If set, you must
97# also pick a specific network port above (FCClientServiceFactory.port).
98# c.FCEngineServiceFactory.reuse_furls = False
99
100#-----------------------------------------------------------------------------
101# Developer level configuration attributes
102#-----------------------------------------------------------------------------
103
104# You shouldn't have to modify anything in this section. These attributes
105# are more for developers who want to change the behavior of the controller
106# at a fundamental level.
107
108# c.FCClientServiceFactory.cert_file = u'ipcontroller-client.pem'
109
110# default_client_interfaces = Config()
111# default_client_interfaces.Task.interface_chain = [
112# 'IPython.kernel.task.ITaskController',
113# 'IPython.kernel.taskfc.IFCTaskController'
114# ]
115#
116# default_client_interfaces.Task.furl_file = u'ipcontroller-tc.furl'
117#
118# default_client_interfaces.MultiEngine.interface_chain = [
119# 'IPython.kernel.multiengine.IMultiEngine',
120# 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine'
121# ]
122#
123# default_client_interfaces.MultiEngine.furl_file = u'ipcontroller-mec.furl'
124#
125# c.FCEngineServiceFactory.interfaces = default_client_interfaces
126
127# c.FCEngineServiceFactory.cert_file = u'ipcontroller-engine.pem'
128
129# default_engine_interfaces = Config()
130# default_engine_interfaces.Default.interface_chain = [
131# 'IPython.kernel.enginefc.IFCControllerBase'
132# ]
133#
134# default_engine_interfaces.Default.furl_file = u'ipcontroller-engine.furl'
135#
136# c.FCEngineServiceFactory.interfaces = default_engine_interfaces
0137
=== added file 'IPython/config/default/ipengine_config.py'
--- IPython/config/default/ipengine_config.py 1970-01-01 00:00:00 +0000
+++ IPython/config/default/ipengine_config.py 2009-11-21 00:11:10 +0000
@@ -0,0 +1,90 @@
1c = get_config()
2
3#-----------------------------------------------------------------------------
4# Global configuration
5#-----------------------------------------------------------------------------
6
7# Start up messages are logged to stdout using the logging module.
8# These all happen before the twisted reactor is started and are
9# useful for debugging purposes. Can be (10=DEBUG,20=INFO,30=WARN,40=CRITICAL)
10# and smaller is more verbose.
11# c.Global.log_level = 20
12
13# Log to a file in cluster_dir/log, otherwise just log to sys.stdout.
14# c.Global.log_to_file = False
15
16# Remove old logs from cluster_dir/log before starting.
17# c.Global.clean_logs = True
18
19# A list of strings that will be executed in the users namespace on the engine
20# before it connects to the controller.
21# c.Global.exec_lines = ['import numpy']
22
23# The engine will try to connect to the controller multiple times, to allow
24# the controller time to startup and write its FURL file. These parameters
25# control the number of retries (connect_max_tries) and the initial delay
26# (connect_delay) between attemps. The actual delay between attempts gets
27# longer each time by a factor of 1.5 (delay[i] = 1.5*delay[i-1])
28# those attemps.
29# c.Global.connect_delay = 0.1
30# c.Global.connect_max_tries = 15
31
32# By default, the engine will look for the controller's FURL file in its own
33# cluster directory. Sometimes, the FURL file will be elsewhere and this
34# attribute can be set to the full path of the FURL file.
35# c.Global.furl_file = u''
36
37# The working directory for the process. The application will use os.chdir
38# to change to this directory before starting.
39# c.Global.work_dir = os.getcwd()
40
41#-----------------------------------------------------------------------------
42# MPI configuration
43#-----------------------------------------------------------------------------
44
45# Upon starting the engine can be configured to call MPI_Init. This section
46# configures that.
47
48# Select which MPI section to execute to setup MPI. The value of this
49# attribute must match the name of another attribute in the MPI config
50# section (mpi4py, pytrilinos, etc.). This can also be set by the --mpi
51# command line option.
52# c.MPI.use = ''
53
54# Initialize MPI using mpi4py. To use this, set c.MPI.use = 'mpi4py' to use
55# --mpi=mpi4py at the command line.
56# c.MPI.mpi4py = """from mpi4py import MPI as mpi
57# mpi.size = mpi.COMM_WORLD.Get_size()
58# mpi.rank = mpi.COMM_WORLD.Get_rank()
59# """
60
61# Initialize MPI using pytrilinos. To use this, set c.MPI.use = 'pytrilinos'
62# to use --mpi=pytrilinos at the command line.
63# c.MPI.pytrilinos = """from PyTrilinos import Epetra
64# class SimpleStruct:
65# pass
66# mpi = SimpleStruct()
67# mpi.rank = 0
68# mpi.size = 0
69# """
70
71#-----------------------------------------------------------------------------
72# Developer level configuration attributes
73#-----------------------------------------------------------------------------
74
75# You shouldn't have to modify anything in this section. These attributes
76# are more for developers who want to change the behavior of the controller
77# at a fundamental level.
78
79# You should not have to change these attributes.
80
81# c.Global.shell_class = 'IPython.kernel.core.interpreter.Interpreter'
82
83# c.Global.furl_file_name = u'ipcontroller-engine.furl'
84
85
86
87
88
89
90
091
=== modified file 'IPython/config/default/ipython_config.py'
--- IPython/config/default/ipython_config.py 2009-09-28 05:57:44 +0000
+++ IPython/config/default/ipython_config.py 2009-11-21 00:11:10 +0000
@@ -13,7 +13,7 @@
1313
14# Set this to determine the detail of what is logged at startup.14# Set this to determine the detail of what is logged at startup.
15# The default is 30 and possible values are 0,10,20,30,40,50.15# The default is 30 and possible values are 0,10,20,30,40,50.
16c.Global.log_level = 2016# c.Global.log_level = 20
1717
18# This should be a list of importable Python modules that have an18# This should be a list of importable Python modules that have an
19# load_in_ipython(ip) method. This method gets called when the extension19# load_in_ipython(ip) method. This method gets called when the extension
@@ -35,7 +35,7 @@
35# These files are run in IPython in the user's namespace. Files with a .py35# These files are run in IPython in the user's namespace. Files with a .py
36# extension need to be pure Python. Files with a .ipy extension can have36# extension need to be pure Python. Files with a .ipy extension can have
37# custom IPython syntax (like magics, etc.). 37# custom IPython syntax (like magics, etc.).
38# These files need to be in the cwd, the ipythondir or be absolute paths.38# These files need to be in the cwd, the ipython_dir or be absolute paths.
39# c.Global.exec_files = [39# c.Global.exec_files = [
40# 'mycode.py',40# 'mycode.py',
41# 'fancy.ipy'41# 'fancy.ipy'
@@ -71,9 +71,9 @@
7171
72# c.InteractiveShell.logstart = True72# c.InteractiveShell.logstart = True
7373
74# c.InteractiveShell.logfile = 'ipython_log.py'74# c.InteractiveShell.logfile = u'ipython_log.py'
7575
76# c.InteractiveShell.logappend = 'mylog.py'76# c.InteractiveShell.logappend = u'mylog.py'
7777
78# c.InteractiveShell.object_info_string_level = 078# c.InteractiveShell.object_info_string_level = 0
7979
8080
=== modified file 'IPython/config/loader.py'
--- IPython/config/loader.py 2009-09-15 05:54:31 +0000
+++ IPython/config/loader.py 2009-11-21 00:11:10 +0000
@@ -244,8 +244,14 @@
244 # with the parents.244 # with the parents.
245 def load_subconfig(fname):245 def load_subconfig(fname):
246 loader = PyFileConfigLoader(fname, self.path)246 loader = PyFileConfigLoader(fname, self.path)
247 sub_config = loader.load_config()247 try:
248 self.config._merge(sub_config)248 sub_config = loader.load_config()
249 except IOError:
250 # Pass silently if the sub config is not there. This happens
251 # when a user us using a profile, but not the default config.
252 pass
253 else:
254 self.config._merge(sub_config)
249255
250 # Again, this needs to be a closure and should be used in config256 # Again, this needs to be a closure and should be used in config
251 # files to get the config being loaded.257 # files to get the config being loaded.
@@ -271,6 +277,7 @@
271class NoConfigDefault(object): pass277class NoConfigDefault(object): pass
272NoConfigDefault = NoConfigDefault()278NoConfigDefault = NoConfigDefault()
273279
280
274class ArgParseConfigLoader(CommandLineConfigLoader):281class ArgParseConfigLoader(CommandLineConfigLoader):
275 282
276 # arguments = [(('-f','--file'),dict(type=str,dest='file'))]283 # arguments = [(('-f','--file'),dict(type=str,dest='file'))]
277284
=== renamed file 'IPython/config/profile/__init_.py' => 'IPython/config/profile/__init__.py'
=== added file 'IPython/config/profile/ipython_config_cluster.py'
--- IPython/config/profile/ipython_config_cluster.py 1970-01-01 00:00:00 +0000
+++ IPython/config/profile/ipython_config_cluster.py 2009-11-21 00:11:10 +0000
@@ -0,0 +1,24 @@
1c = get_config()
2
3# This can be used at any point in a config file to load a sub config
4# and merge it into the current one.
5load_subconfig('ipython_config.py')
6
7lines = """
8from IPython.kernel.client import *
9"""
10
11# You have to make sure that attributes that are containers already
12# exist before using them. Simple assigning a new list will override
13# all previous values.
14if hasattr(c.Global, 'exec_lines'):
15 c.Global.exec_lines.append(lines)
16else:
17 c.Global.exec_lines = [lines]
18
19# Load the parallelmagic extension to enable %result, %px, %autopx magics.
20if hasattr(c.Global, 'extensions'):
21 c.Global.extensions.append('parallelmagic')
22else:
23 c.Global.extensions = ['parallelmagic']
24
025
=== modified file 'IPython/core/application.py'
--- IPython/core/application.py 2009-09-18 03:26:43 +0000
+++ IPython/core/application.py 2009-11-21 00:11:10 +0000
@@ -1,7 +1,13 @@
1#!/usr/bin/env python1#!/usr/bin/env python
2# encoding: utf-82# encoding: utf-8
3"""3"""
4An application for IPython4An application for IPython.
5
6All top-level applications should use the classes in this module for
7handling configuration and creating componenets.
8
9The job of an :class:`Application` is to create the master configuration
10object and then create the components, passing the config to them.
511
6Authors:12Authors:
713
@@ -26,10 +32,9 @@
26import logging32import logging
27import os33import os
28import sys34import sys
29import traceback
30from copy import deepcopy
3135
32from IPython.utils.genutils import get_ipython_dir, filefind36from IPython.core import release
37from IPython.utils.genutils import get_ipython_dir
33from IPython.config.loader import (38from IPython.config.loader import (
34 PyFileConfigLoader,39 PyFileConfigLoader,
35 ArgParseConfigLoader,40 ArgParseConfigLoader,
@@ -42,22 +47,27 @@
42#-----------------------------------------------------------------------------47#-----------------------------------------------------------------------------
4348
4449
45class IPythonArgParseConfigLoader(ArgParseConfigLoader):50class BaseAppArgParseConfigLoader(ArgParseConfigLoader):
46 """Default command line options for IPython based applications."""51 """Default command line options for IPython based applications."""
4752
48 def _add_other_arguments(self):53 def _add_other_arguments(self):
49 self.parser.add_argument('-ipythondir',dest='Global.ipythondir',type=str,54 self.parser.add_argument('--ipython-dir',
50 help='Set to override default location of Global.ipythondir.',55 dest='Global.ipython_dir',type=unicode,
56 help='Set to override default location of Global.ipython_dir.',
51 default=NoConfigDefault,57 default=NoConfigDefault,
52 metavar='Global.ipythondir')58 metavar='Global.ipython_dir')
53 self.parser.add_argument('-p','-profile',dest='Global.profile',type=str,59 self.parser.add_argument('-p', '--profile',
60 dest='Global.profile',type=unicode,
54 help='The string name of the ipython profile to be used.',61 help='The string name of the ipython profile to be used.',
55 default=NoConfigDefault,62 default=NoConfigDefault,
56 metavar='Global.profile')63 metavar='Global.profile')
57 self.parser.add_argument('-log_level',dest="Global.log_level",type=int,64 self.parser.add_argument('--log-level',
65 dest="Global.log_level",type=int,
58 help='Set the log level (0,10,20,30,40,50). Default is 30.',66 help='Set the log level (0,10,20,30,40,50). Default is 30.',
59 default=NoConfigDefault)67 default=NoConfigDefault,
60 self.parser.add_argument('-config_file',dest='Global.config_file',type=str,68 metavar='Global.log_level')
69 self.parser.add_argument('--config-file',
70 dest='Global.config_file',type=unicode,
61 help='Set the config file name to override default.',71 help='Set the config file name to override default.',
62 default=NoConfigDefault,72 default=NoConfigDefault,
63 metavar='Global.config_file')73 metavar='Global.config_file')
@@ -68,20 +78,24 @@
6878
6979
70class Application(object):80class Application(object):
71 """Load a config, construct an app and run it.81 """Load a config, construct components and set them running."""
72 """
7382
74 config_file_name = 'ipython_config.py'83 name = u'ipython'
75 name = 'ipython'84 description = 'IPython: an enhanced interactive Python shell.'
85 config_file_name = u'ipython_config.py'
86 default_log_level = logging.WARN
7687
77 def __init__(self):88 def __init__(self):
89 self._exiting = False
78 self.init_logger()90 self.init_logger()
91 # Track the default and actual separately because some messages are
92 # only printed if we aren't using the default.
79 self.default_config_file_name = self.config_file_name93 self.default_config_file_name = self.config_file_name
8094
81 def init_logger(self):95 def init_logger(self):
82 self.log = logging.getLogger(self.__class__.__name__)96 self.log = logging.getLogger(self.__class__.__name__)
83 # This is used as the default until the command line arguments are read.97 # This is used as the default until the command line arguments are read.
84 self.log.setLevel(logging.WARN)98 self.log.setLevel(self.default_log_level)
85 self._log_handler = logging.StreamHandler()99 self._log_handler = logging.StreamHandler()
86 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")100 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
87 self._log_handler.setFormatter(self._log_formatter)101 self._log_handler.setFormatter(self._log_formatter)
@@ -98,16 +112,24 @@
98 def start(self):112 def start(self):
99 """Start the application."""113 """Start the application."""
100 self.attempt(self.create_default_config)114 self.attempt(self.create_default_config)
115 self.log_default_config()
116 self.set_default_config_log_level()
101 self.attempt(self.pre_load_command_line_config)117 self.attempt(self.pre_load_command_line_config)
102 self.attempt(self.load_command_line_config, action='abort')118 self.attempt(self.load_command_line_config, action='abort')
119 self.set_command_line_config_log_level()
103 self.attempt(self.post_load_command_line_config)120 self.attempt(self.post_load_command_line_config)
104 self.attempt(self.find_ipythondir)121 self.log_command_line_config()
122 self.attempt(self.find_ipython_dir)
123 self.attempt(self.find_resources)
105 self.attempt(self.find_config_file_name)124 self.attempt(self.find_config_file_name)
106 self.attempt(self.find_config_file_paths)125 self.attempt(self.find_config_file_paths)
107 self.attempt(self.pre_load_file_config)126 self.attempt(self.pre_load_file_config)
108 self.attempt(self.load_file_config)127 self.attempt(self.load_file_config)
128 self.set_file_config_log_level()
109 self.attempt(self.post_load_file_config)129 self.attempt(self.post_load_file_config)
130 self.log_file_config()
110 self.attempt(self.merge_configs)131 self.attempt(self.merge_configs)
132 self.log_master_config()
111 self.attempt(self.pre_construct)133 self.attempt(self.pre_construct)
112 self.attempt(self.construct)134 self.attempt(self.construct)
113 self.attempt(self.post_construct)135 self.attempt(self.post_construct)
@@ -127,65 +149,89 @@
127 don't belong to a particular component.149 don't belong to a particular component.
128 """150 """
129 self.default_config = Config()151 self.default_config = Config()
130 self.default_config.Global.ipythondir = get_ipython_dir()152 self.default_config.Global.ipython_dir = get_ipython_dir()
153 self.default_config.Global.log_level = self.log_level
154
155 def log_default_config(self):
131 self.log.debug('Default config loaded:')156 self.log.debug('Default config loaded:')
132 self.log.debug(repr(self.default_config))157 self.log.debug(repr(self.default_config))
133158
159 def set_default_config_log_level(self):
160 try:
161 self.log_level = self.default_config.Global.log_level
162 except AttributeError:
163 # Fallback to the default_log_level class attribute
164 pass
165
134 def create_command_line_config(self):166 def create_command_line_config(self):
135 """Create and return a command line config loader."""167 """Create and return a command line config loader."""
136 return IPythonArgParseConfigLoader(description=self.name)168 return BaseAppArgParseConfigLoader(
169 description=self.description,
170 version=release.version
171 )
137172
138 def pre_load_command_line_config(self):173 def pre_load_command_line_config(self):
139 """Do actions just before loading the command line config."""174 """Do actions just before loading the command line config."""
140 pass175 pass
141176
142 def load_command_line_config(self):177 def load_command_line_config(self):
143 """Load the command line config.178 """Load the command line config."""
144
145 This method also sets ``self.debug``.
146 """
147
148 loader = self.create_command_line_config()179 loader = self.create_command_line_config()
149 self.command_line_config = loader.load_config()180 self.command_line_config = loader.load_config()
150 self.extra_args = loader.get_extra_args()181 self.extra_args = loader.get_extra_args()
151182
183 def set_command_line_config_log_level(self):
152 try:184 try:
153 self.log_level = self.command_line_config.Global.log_level185 self.log_level = self.command_line_config.Global.log_level
154 except AttributeError:186 except AttributeError:
155 pass # Use existing value which is set in Application.init_logger.187 pass
188
189 def post_load_command_line_config(self):
190 """Do actions just after loading the command line config."""
191 pass
192
193 def log_command_line_config(self):
156 self.log.debug("Command line config loaded:")194 self.log.debug("Command line config loaded:")
157 self.log.debug(repr(self.command_line_config))195 self.log.debug(repr(self.command_line_config))
158196
159 def post_load_command_line_config(self):197 def find_ipython_dir(self):
160 """Do actions just after loading the command line config."""
161 pass
162
163 def find_ipythondir(self):
164 """Set the IPython directory.198 """Set the IPython directory.
165199
166 This sets ``self.ipythondir``, but the actual value that is passed200 This sets ``self.ipython_dir``, but the actual value that is passed
167 to the application is kept in either ``self.default_config`` or201 to the application is kept in either ``self.default_config`` or
168 ``self.command_line_config``. This also added ``self.ipythondir`` to202 ``self.command_line_config``. This also adds ``self.ipython_dir`` to
169 ``sys.path`` so config files there can be references by other config203 ``sys.path`` so config files there can be references by other config
170 files.204 files.
171 """205 """
172206
173 try:207 try:
174 self.ipythondir = self.command_line_config.Global.ipythondir208 self.ipython_dir = self.command_line_config.Global.ipython_dir
175 except AttributeError:209 except AttributeError:
176 self.ipythondir = self.default_config.Global.ipythondir210 self.ipython_dir = self.default_config.Global.ipython_dir
177 sys.path.append(os.path.abspath(self.ipythondir))211 sys.path.append(os.path.abspath(self.ipython_dir))
178 if not os.path.isdir(self.ipythondir):212 if not os.path.isdir(self.ipython_dir):
179 os.makedirs(self.ipythondir, mode = 0777)213 os.makedirs(self.ipython_dir, mode=0777)
180 self.log.debug("IPYTHONDIR set to: %s" % self.ipythondir)214 self.log.debug("IPYTHON_DIR set to: %s" % self.ipython_dir)
215
216 def find_resources(self):
217 """Find other resources that need to be in place.
218
219 Things like cluster directories need to be in place to find the
220 config file. These happen right after the IPython directory has
221 been set.
222 """
223 pass
181224
182 def find_config_file_name(self):225 def find_config_file_name(self):
183 """Find the config file name for this application.226 """Find the config file name for this application.
184227
228 This must set ``self.config_file_name`` to the filename of the
229 config file to use (just the filename). The search paths for the
230 config file are set in :meth:`find_config_file_paths` and then passed
231 to the config file loader where they are resolved to an absolute path.
232
185 If a profile has been set at the command line, this will resolve233 If a profile has been set at the command line, this will resolve
186 it. The search paths for the config file are set in234 it.
187 :meth:`find_config_file_paths` and then passed to the config file
188 loader where they are resolved to an absolute path.
189 """235 """
190236
191 try:237 try:
@@ -196,14 +242,18 @@
196 try:242 try:
197 self.profile_name = self.command_line_config.Global.profile243 self.profile_name = self.command_line_config.Global.profile
198 name_parts = self.config_file_name.split('.')244 name_parts = self.config_file_name.split('.')
199 name_parts.insert(1, '_' + self.profile_name + '.')245 name_parts.insert(1, u'_' + self.profile_name + u'.')
200 self.config_file_name = ''.join(name_parts)246 self.config_file_name = ''.join(name_parts)
201 except AttributeError:247 except AttributeError:
202 pass248 pass
203249
204 def find_config_file_paths(self):250 def find_config_file_paths(self):
205 """Set the search paths for resolving the config file."""251 """Set the search paths for resolving the config file.
206 self.config_file_paths = (os.getcwd(), self.ipythondir)252
253 This must set ``self.config_file_paths`` to a sequence of search
254 paths to pass to the config file loader.
255 """
256 self.config_file_paths = (os.getcwd(), self.ipython_dir)
207257
208 def pre_load_file_config(self):258 def pre_load_file_config(self):
209 """Do actions before the config file is loaded."""259 """Do actions before the config file is loaded."""
@@ -216,7 +266,7 @@
216 ``CONFIG_FILE`` config variable is set to the resolved config file266 ``CONFIG_FILE`` config variable is set to the resolved config file
217 location. If not successful, an empty config is used.267 location. If not successful, an empty config is used.
218 """268 """
219 self.log.debug("Attempting to load config file: <%s>" % self.config_file_name)269 self.log.debug("Attempting to load config file: %s" % self.config_file_name)
220 loader = PyFileConfigLoader(self.config_file_name,270 loader = PyFileConfigLoader(self.config_file_name,
221 path=self.config_file_paths)271 path=self.config_file_paths)
222 try:272 try:
@@ -225,19 +275,18 @@
225 except IOError:275 except IOError:
226 # Only warn if the default config file was NOT being used.276 # Only warn if the default config file was NOT being used.
227 if not self.config_file_name==self.default_config_file_name:277 if not self.config_file_name==self.default_config_file_name:
228 self.log.warn("Config file not found, skipping: <%s>" % \278 self.log.warn("Config file not found, skipping: %s" % \
229 self.config_file_name, exc_info=True)279 self.config_file_name, exc_info=True)
230 self.file_config = Config()280 self.file_config = Config()
231 except:281 except:
232 self.log.warn("Error loading config file: <%s>" % \282 self.log.warn("Error loading config file: %s" % \
233 self.config_file_name, exc_info=True)283 self.config_file_name, exc_info=True)
234 self.file_config = Config()284 self.file_config = Config()
235 else:285
236 self.log.debug("Config file loaded: <%s>" % loader.full_filename)286 def set_file_config_log_level(self):
237 self.log.debug(repr(self.file_config))
238 # We need to keeep self.log_level updated. But we only use the value287 # We need to keeep self.log_level updated. But we only use the value
239 # of the file_config if a value was not specified at the command288 # of the file_config if a value was not specified at the command
240 # line.289 # line, because the command line overrides everything.
241 if not hasattr(self.command_line_config.Global, 'log_level'):290 if not hasattr(self.command_line_config.Global, 'log_level'):
242 try:291 try:
243 self.log_level = self.file_config.Global.log_level292 self.log_level = self.file_config.Global.log_level
@@ -248,6 +297,11 @@
248 """Do actions after the config file is loaded."""297 """Do actions after the config file is loaded."""
249 pass298 pass
250299
300 def log_file_config(self):
301 if hasattr(self.file_config.Global, 'config_file'):
302 self.log.debug("Config file loaded: %s" % self.file_config.Global.config_file)
303 self.log.debug(repr(self.file_config))
304
251 def merge_configs(self):305 def merge_configs(self):
252 """Merge the default, command line and file config objects."""306 """Merge the default, command line and file config objects."""
253 config = Config()307 config = Config()
@@ -255,6 +309,8 @@
255 config._merge(self.file_config)309 config._merge(self.file_config)
256 config._merge(self.command_line_config)310 config._merge(self.command_line_config)
257 self.master_config = config311 self.master_config = config
312
313 def log_master_config(self):
258 self.log.debug("Master config created:")314 self.log.debug("Master config created:")
259 self.log.debug(repr(self.master_config))315 self.log.debug(repr(self.master_config))
260316
@@ -280,21 +336,29 @@
280336
281 def abort(self):337 def abort(self):
282 """Abort the starting of the application."""338 """Abort the starting of the application."""
283 self.log.critical("Aborting application: %s" % self.name, exc_info=True)339 if self._exiting:
284 sys.exit(1)340 pass
341 else:
342 self.log.critical("Aborting application: %s" % self.name, exc_info=True)
343 self._exiting = True
344 sys.exit(1)
285345
286 def exit(self):346 def exit(self, exit_status=0):
287 self.log.critical("Aborting application: %s" % self.name)347 if self._exiting:
288 sys.exit(1)348 pass
349 else:
350 self.log.debug("Exiting application: %s" % self.name)
351 self._exiting = True
352 sys.exit(exit_status)
289353
290 def attempt(self, func, action='abort'):354 def attempt(self, func, action='abort'):
291 try:355 try:
292 func()356 func()
293 except SystemExit:357 except SystemExit:
294 self.exit()358 raise
295 except:359 except:
296 if action == 'abort':360 if action == 'abort':
297 self.abort()361 self.abort()
298 elif action == 'exit':362 elif action == 'exit':
299 self.exit()
300
301\ No newline at end of file363\ No newline at end of file
364 self.exit(0)
365
302366
=== modified file 'IPython/core/builtin_trap.py'
--- IPython/core/builtin_trap.py 2009-10-09 22:54:40 +0000
+++ IPython/core/builtin_trap.py 2009-11-21 00:11:10 +0000
@@ -86,6 +86,7 @@
86 """Store ipython references in the __builtin__ namespace."""86 """Store ipython references in the __builtin__ namespace."""
87 self.add_builtin('exit', Quitter(self.shell, 'exit'))87 self.add_builtin('exit', Quitter(self.shell, 'exit'))
88 self.add_builtin('quit', Quitter(self.shell, 'quit'))88 self.add_builtin('quit', Quitter(self.shell, 'quit'))
89 self.add_builtin('get_ipython', self.shell.get_ipython)
8990
90 # Recursive reload function91 # Recursive reload function
91 try:92 try:
9293
=== modified file 'IPython/core/component.py'
--- IPython/core/component.py 2009-09-28 05:57:44 +0000
+++ IPython/core/component.py 2009-11-21 00:11:11 +0000
@@ -237,14 +237,20 @@
237 self.config = config237 self.config = config
238 # We used to deepcopy, but for now we are trying to just save238 # We used to deepcopy, but for now we are trying to just save
239 # by reference. This *could* have side effects as all components239 # by reference. This *could* have side effects as all components
240 # will share config.240 # will share config. In fact, I did find such a side effect in
241 # _config_changed below. If a config attribute value was a mutable type
242 # all instances of a component were getting the same copy, effectively
243 # making that a class attribute.
241 # self.config = deepcopy(config)244 # self.config = deepcopy(config)
242 else:245 else:
243 if self.parent is not None:246 if self.parent is not None:
244 self.config = self.parent.config247 self.config = self.parent.config
245 # We used to deepcopy, but for now we are trying to just save248 # We used to deepcopy, but for now we are trying to just save
246 # by reference. This *could* have side effects as all components249 # by reference. This *could* have side effects as all components
247 # will share config.250 # will share config. In fact, I did find such a side effect in
251 # _config_changed below. If a config attribute value was a mutable type
252 # all instances of a component were getting the same copy, effectively
253 # making that a class attribute.
248 # self.config = deepcopy(self.parent.config)254 # self.config = deepcopy(self.parent.config)
249255
250 self.created = datetime.datetime.now()256 self.created = datetime.datetime.now()
@@ -296,14 +302,29 @@
296 if new._has_section(sname):302 if new._has_section(sname):
297 my_config = new[sname]303 my_config = new[sname]
298 for k, v in traitlets.items():304 for k, v in traitlets.items():
305 # Don't allow traitlets with config=True to start with
306 # uppercase. Otherwise, they are confused with Config
307 # subsections. But, developers shouldn't have uppercase
308 # attributes anyways! (PEP 6)
309 if k[0].upper()==k[0] and not k.startswith('_'):
310 raise ComponentError('Component traitlets with '
311 'config=True must start with a lowercase so they are '
312 'not confused with Config subsections: %s.%s' % \
313 (self.__class__.__name__, k))
299 try:314 try:
315 # Here we grab the value from the config
316 # If k has the naming convention of a config
317 # section, it will be auto created.
300 config_value = my_config[k]318 config_value = my_config[k]
301 except KeyError:319 except KeyError:
302 pass320 pass
303 else:321 else:
304 # print "Setting %s.%s from %s.%s=%r" % \322 # print "Setting %s.%s from %s.%s=%r" % \
305 # (self.__class__.__name__,k,sname,k,config_value)323 # (self.__class__.__name__,k,sname,k,config_value)
306 setattr(self, k, config_value)324 # We have to do a deepcopy here if we don't deepcopy the entire
325 # config object. If we don't, a mutable config_value will be
326 # shared by all instances, effectively making it a class attribute.
327 setattr(self, k, deepcopy(config_value))
307328
308 @property329 @property
309 def children(self):330 def children(self):
310331
=== modified file 'IPython/core/crashhandler.py'
--- IPython/core/crashhandler.py 2009-08-26 20:54:07 +0000
+++ IPython/core/crashhandler.py 2009-11-21 00:11:11 +0000
@@ -124,7 +124,7 @@
124 #color_scheme = 'Linux' # dbg124 #color_scheme = 'Linux' # dbg
125 125
126 try:126 try:
127 rptdir = self.IP.config.IPYTHONDIR127 rptdir = self.IP.ipython_dir
128 except:128 except:
129 rptdir = os.getcwd()129 rptdir = os.getcwd()
130 if not os.path.isdir(rptdir):130 if not os.path.isdir(rptdir):
131131
=== modified file 'IPython/core/debugger.py'
--- IPython/core/debugger.py 2009-08-19 21:56:41 +0000
+++ IPython/core/debugger.py 2009-11-21 00:11:11 +0000
@@ -70,6 +70,7 @@
70def BdbQuit_IPython_excepthook(self,et,ev,tb):70def BdbQuit_IPython_excepthook(self,et,ev,tb):
71 print 'Exiting Debugger.'71 print 'Exiting Debugger.'
7272
73
73class Tracer(object):74class Tracer(object):
74 """Class for local debugging, similar to pdb.set_trace.75 """Class for local debugging, similar to pdb.set_trace.
7576
@@ -105,12 +106,10 @@
105 from the Python standard library for usage details.106 from the Python standard library for usage details.
106 """107 """
107108
108 global __IPYTHON__
109 try:109 try:
110 __IPYTHON__110 ip = ipapi.get()
111 except NameError:111 except:
112 # Outside of ipython, we set our own exception hook manually112 # Outside of ipython, we set our own exception hook manually
113 __IPYTHON__ = ipapi.get()
114 BdbQuit_excepthook.excepthook_ori = sys.excepthook113 BdbQuit_excepthook.excepthook_ori = sys.excepthook
115 sys.excepthook = BdbQuit_excepthook114 sys.excepthook = BdbQuit_excepthook
116 def_colors = 'NoColor'115 def_colors = 'NoColor'
@@ -122,9 +121,8 @@
122 pass121 pass
123 else:122 else:
124 # In ipython, we use its custom exception handler mechanism123 # In ipython, we use its custom exception handler mechanism
125 ip = ipapi.get()
126 def_colors = ip.colors124 def_colors = ip.colors
127 ip.set_custom_exc((bdb.BdbQuit,),BdbQuit_IPython_excepthook)125 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
128126
129 if colors is None:127 if colors is None:
130 colors = def_colors128 colors = def_colors
@@ -138,6 +136,7 @@
138 136
139 self.debugger.set_trace(sys._getframe().f_back)137 self.debugger.set_trace(sys._getframe().f_back)
140138
139
141def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):140def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
142 """Make new_fn have old_fn's doc string. This is particularly useful141 """Make new_fn have old_fn's doc string. This is particularly useful
143 for the do_... commands that hook into the help system.142 for the do_... commands that hook into the help system.
@@ -149,6 +148,7 @@
149 wrapper.__doc__ = old_fn.__doc__ + additional_text148 wrapper.__doc__ = old_fn.__doc__ + additional_text
150 return wrapper149 return wrapper
151150
151
152def _file_lines(fname):152def _file_lines(fname):
153 """Return the contents of a named file as a list of lines.153 """Return the contents of a named file as a list of lines.
154154
@@ -164,143 +164,98 @@
164 outfile.close()164 outfile.close()
165 return out165 return out
166166
167
167class Pdb(OldPdb):168class Pdb(OldPdb):
168 """Modified Pdb class, does not load readline."""169 """Modified Pdb class, does not load readline."""
169170
170 if sys.version[:3] >= '2.5' or has_pydb:171 def __init__(self,color_scheme='NoColor',completekey=None,
171 def __init__(self,color_scheme='NoColor',completekey=None,172 stdin=None, stdout=None):
172 stdin=None, stdout=None):
173173
174 # Parent constructor:174 # Parent constructor:
175 if has_pydb and completekey is None:175 if has_pydb and completekey is None:
176 OldPdb.__init__(self,stdin=stdin,stdout=Term.cout)176 OldPdb.__init__(self,stdin=stdin,stdout=Term.cout)
177 else:177 else:
178 OldPdb.__init__(self,completekey,stdin,stdout)178 OldPdb.__init__(self,completekey,stdin,stdout)
179
180 self.prompt = prompt # The default prompt is '(Pdb)'
181 179
182 # IPython changes...180 self.prompt = prompt # The default prompt is '(Pdb)'
183 self.is_pydb = has_pydb
184
185 if self.is_pydb:
186
187 # iplib.py's ipalias seems to want pdb's checkline
188 # which located in pydb.fn
189 import pydb.fns
190 self.checkline = lambda filename, lineno: \
191 pydb.fns.checkline(self, filename, lineno)
192
193 self.curframe = None
194 self.do_restart = self.new_do_restart
195
196 self.old_all_completions = __IPYTHON__.Completer.all_completions
197 __IPYTHON__.Completer.all_completions=self.all_completions
198
199 self.do_list = decorate_fn_with_doc(self.list_command_pydb,
200 OldPdb.do_list)
201 self.do_l = self.do_list
202 self.do_frame = decorate_fn_with_doc(self.new_do_frame,
203 OldPdb.do_frame)
204
205 self.aliases = {}
206
207 # Create color table: we copy the default one from the traceback
208 # module and add a few attributes needed for debugging
209 self.color_scheme_table = exception_colors()
210
211 # shorthands
212 C = coloransi.TermColors
213 cst = self.color_scheme_table
214
215 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
216 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
217
218 cst['Linux'].colors.breakpoint_enabled = C.LightRed
219 cst['Linux'].colors.breakpoint_disabled = C.Red
220
221 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
222 cst['LightBG'].colors.breakpoint_disabled = C.Red
223
224 self.set_colors(color_scheme)
225
226 # Add a python parser so we can syntax highlight source while
227 # debugging.
228 self.parser = PyColorize.Parser()
229
230
231 else:
232 # Ugly hack: for Python 2.3-2.4, we can't call the parent constructor,
233 # because it binds readline and breaks tab-completion. This means we
234 # have to COPY the constructor here.
235 def __init__(self,color_scheme='NoColor'):
236 bdb.Bdb.__init__(self)
237 cmd.Cmd.__init__(self,completekey=None) # don't load readline
238 self.prompt = 'ipdb> ' # The default prompt is '(Pdb)'
239 self.aliases = {}
240
241 # These two lines are part of the py2.4 constructor, let's put them
242 # unconditionally here as they won't cause any problems in 2.3.
243 self.mainpyfile = ''
244 self._wait_for_mainpyfile = 0
245
246 # Read $HOME/.pdbrc and ./.pdbrc
247 try:
248 self.rcLines = _file_lines(os.path.join(os.environ['HOME'],
249 ".pdbrc"))
250 except KeyError:
251 self.rcLines = []
252 self.rcLines.extend(_file_lines(".pdbrc"))
253
254 # Create color table: we copy the default one from the traceback
255 # module and add a few attributes needed for debugging
256 self.color_scheme_table = exception_colors()
257
258 # shorthands
259 C = coloransi.TermColors
260 cst = self.color_scheme_table
261
262 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
263 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
264
265 cst['Linux'].colors.breakpoint_enabled = C.LightRed
266 cst['Linux'].colors.breakpoint_disabled = C.Red
267
268 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
269 cst['LightBG'].colors.breakpoint_disabled = C.Red
270
271 self.set_colors(color_scheme)
272
273 # Add a python parser so we can syntax highlight source while
274 # debugging.
275 self.parser = PyColorize.Parser()
276 181
182 # IPython changes...
183 self.is_pydb = has_pydb
184
185 self.shell = ipapi.get()
186
187 if self.is_pydb:
188
189 # iplib.py's ipalias seems to want pdb's checkline
190 # which located in pydb.fn
191 import pydb.fns
192 self.checkline = lambda filename, lineno: \
193 pydb.fns.checkline(self, filename, lineno)
194
195 self.curframe = None
196 self.do_restart = self.new_do_restart
197
198 self.old_all_completions = self.shell.Completer.all_completions
199 self.shell.Completer.all_completions=self.all_completions
200
201 self.do_list = decorate_fn_with_doc(self.list_command_pydb,
202 OldPdb.do_list)
203 self.do_l = self.do_list
204 self.do_frame = decorate_fn_with_doc(self.new_do_frame,
205 OldPdb.do_frame)
206
207 self.aliases = {}
208
209 # Create color table: we copy the default one from the traceback
210 # module and add a few attributes needed for debugging
211 self.color_scheme_table = exception_colors()
212
213 # shorthands
214 C = coloransi.TermColors
215 cst = self.color_scheme_table
216
217 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
218 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
219
220 cst['Linux'].colors.breakpoint_enabled = C.LightRed
221 cst['Linux'].colors.breakpoint_disabled = C.Red
222
223 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
224 cst['LightBG'].colors.breakpoint_disabled = C.Red
225
226 self.set_colors(color_scheme)
227
228 # Add a python parser so we can syntax highlight source while
229 # debugging.
230 self.parser = PyColorize.Parser()
231
277 def set_colors(self, scheme):232 def set_colors(self, scheme):
278 """Shorthand access to the color table scheme selector method."""233 """Shorthand access to the color table scheme selector method."""
279 self.color_scheme_table.set_active_scheme(scheme)234 self.color_scheme_table.set_active_scheme(scheme)
280235
281 def interaction(self, frame, traceback):236 def interaction(self, frame, traceback):
282 __IPYTHON__.set_completer_frame(frame)237 self.shell.set_completer_frame(frame)
283 OldPdb.interaction(self, frame, traceback)238 OldPdb.interaction(self, frame, traceback)
284239
285 def new_do_up(self, arg):240 def new_do_up(self, arg):
286 OldPdb.do_up(self, arg)241 OldPdb.do_up(self, arg)
287 __IPYTHON__.set_completer_frame(self.curframe)242 self.shell.set_completer_frame(self.curframe)
288 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)243 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
289244
290 def new_do_down(self, arg):245 def new_do_down(self, arg):
291 OldPdb.do_down(self, arg)246 OldPdb.do_down(self, arg)
292 __IPYTHON__.set_completer_frame(self.curframe)247 self.shell.set_completer_frame(self.curframe)
293248
294 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)249 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
295250
296 def new_do_frame(self, arg):251 def new_do_frame(self, arg):
297 OldPdb.do_frame(self, arg)252 OldPdb.do_frame(self, arg)
298 __IPYTHON__.set_completer_frame(self.curframe)253 self.shell.set_completer_frame(self.curframe)
299254
300 def new_do_quit(self, arg):255 def new_do_quit(self, arg):
301 256
302 if hasattr(self, 'old_all_completions'):257 if hasattr(self, 'old_all_completions'):
303 __IPYTHON__.Completer.all_completions=self.old_all_completions258 self.shell.Completer.all_completions=self.old_all_completions
304 259
305 260
306 return OldPdb.do_quit(self, arg)261 return OldPdb.do_quit(self, arg)
@@ -314,7 +269,7 @@
314 return self.do_quit(arg)269 return self.do_quit(arg)
315270
316 def postloop(self):271 def postloop(self):
317 __IPYTHON__.set_completer_frame(None)272 self.shell.set_completer_frame(None)
318273
319 def print_stack_trace(self):274 def print_stack_trace(self):
320 try:275 try:
@@ -331,7 +286,7 @@
331 # vds: >>286 # vds: >>
332 frame, lineno = frame_lineno287 frame, lineno = frame_lineno
333 filename = frame.f_code.co_filename288 filename = frame.f_code.co_filename
334 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)289 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
335 # vds: <<290 # vds: <<
336291
337 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):292 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
@@ -500,7 +455,7 @@
500 # vds: >>455 # vds: >>
501 lineno = first456 lineno = first
502 filename = self.curframe.f_code.co_filename457 filename = self.curframe.f_code.co_filename
503 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)458 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
504 # vds: <<459 # vds: <<
505460
506 do_l = do_list461 do_l = do_list
@@ -509,16 +464,16 @@
509 """The debugger interface to magic_pdef"""464 """The debugger interface to magic_pdef"""
510 namespaces = [('Locals', self.curframe.f_locals),465 namespaces = [('Locals', self.curframe.f_locals),
511 ('Globals', self.curframe.f_globals)]466 ('Globals', self.curframe.f_globals)]
512 __IPYTHON__.magic_pdef(arg, namespaces=namespaces)467 self.shell.magic_pdef(arg, namespaces=namespaces)
513468
514 def do_pdoc(self, arg):469 def do_pdoc(self, arg):
515 """The debugger interface to magic_pdoc"""470 """The debugger interface to magic_pdoc"""
516 namespaces = [('Locals', self.curframe.f_locals),471 namespaces = [('Locals', self.curframe.f_locals),
517 ('Globals', self.curframe.f_globals)]472 ('Globals', self.curframe.f_globals)]
518 __IPYTHON__.magic_pdoc(arg, namespaces=namespaces)473 self.shell.magic_pdoc(arg, namespaces=namespaces)
519474
520 def do_pinfo(self, arg):475 def do_pinfo(self, arg):
521 """The debugger equivalant of ?obj"""476 """The debugger equivalant of ?obj"""
522 namespaces = [('Locals', self.curframe.f_locals),477 namespaces = [('Locals', self.curframe.f_locals),
523 ('Globals', self.curframe.f_globals)]478 ('Globals', self.curframe.f_globals)]
524 __IPYTHON__.magic_pinfo("pinfo %s" % arg, namespaces=namespaces)479 self.shell.magic_pinfo("pinfo %s" % arg, namespaces=namespaces)
525480
=== modified file 'IPython/core/display_trap.py'
--- IPython/core/display_trap.py 2009-10-09 22:54:40 +0000
+++ IPython/core/display_trap.py 2009-11-21 00:11:11 +0000
@@ -46,11 +46,11 @@
46 # Only turn off the trap when the outermost call to __exit__ is made.46 # Only turn off the trap when the outermost call to __exit__ is made.
47 self._nested_level = 047 self._nested_level = 0
4848
49 @auto_attr49 # @auto_attr
50 def shell(self):50 # def shell(self):
51 return Component.get_instances(51 # return Component.get_instances(
52 root=self.root,52 # root=self.root,
53 klass='IPython.core.iplib.InteractiveShell')[0]53 # klass='IPython.core.iplib.InteractiveShell')[0]
5454
55 def __enter__(self):55 def __enter__(self):
56 if self._nested_level == 0:56 if self._nested_level == 0:
5757
=== modified file 'IPython/core/embed.py'
--- IPython/core/embed.py 2009-09-13 22:06:04 +0000
+++ IPython/core/embed.py 2009-11-21 00:11:11 +0000
@@ -68,7 +68,7 @@
68 # is True by default.68 # is True by default.
69 display_banner = CBool(True)69 display_banner = CBool(True)
7070
71 def __init__(self, parent=None, config=None, ipythondir=None, usage=None,71 def __init__(self, parent=None, config=None, ipython_dir=None, usage=None,
72 user_ns=None, user_global_ns=None,72 user_ns=None, user_global_ns=None,
73 banner1=None, banner2=None, display_banner=None,73 banner1=None, banner2=None, display_banner=None,
74 custom_exceptions=((),None), exit_msg=''):74 custom_exceptions=((),None), exit_msg=''):
@@ -76,7 +76,7 @@
76 self.save_sys_ipcompleter()76 self.save_sys_ipcompleter()
7777
78 super(InteractiveShellEmbed,self).__init__(78 super(InteractiveShellEmbed,self).__init__(
79 parent=parent, config=config, ipythondir=ipythondir, usage=usage, 79 parent=parent, config=config, ipython_dir=ipython_dir, usage=usage,
80 user_ns=user_ns, user_global_ns=user_global_ns,80 user_ns=user_ns, user_global_ns=user_global_ns,
81 banner1=banner1, banner2=banner2, display_banner=display_banner,81 banner1=banner1, banner2=banner2, display_banner=display_banner,
82 custom_exceptions=custom_exceptions)82 custom_exceptions=custom_exceptions)
@@ -233,14 +233,6 @@
233 for var in local_varnames:233 for var in local_varnames:
234 delvar(var,None)234 delvar(var,None)
235235
236 def set_completer_frame(self, frame=None):
237 if frame:
238 self.Completer.namespace = frame.f_locals
239 self.Completer.global_namespace = frame.f_globals
240 else:
241 self.Completer.namespace = self.user_ns
242 self.Completer.global_namespace = self.user_global_ns
243
244236
245_embedded_shell = None237_embedded_shell = None
246238
247239
=== modified file 'IPython/core/ipapi.py'
--- IPython/core/ipapi.py 2009-09-18 02:59:36 +0000
+++ IPython/core/ipapi.py 2009-11-21 00:11:11 +0000
@@ -18,16 +18,19 @@
18# Imports18# Imports
19#-----------------------------------------------------------------------------19#-----------------------------------------------------------------------------
2020
21from IPython.core.error import TryNext, UsageError21from IPython.core.error import TryNext, UsageError, IPythonCoreError
2222
23#-----------------------------------------------------------------------------23#-----------------------------------------------------------------------------
24# Classes and functions24# Classes and functions
25#-----------------------------------------------------------------------------25#-----------------------------------------------------------------------------
2626
27
27def get():28def get():
28 """Get the most recently created InteractiveShell instance."""29 """Get the most recently created InteractiveShell instance."""
29 from IPython.core.iplib import InteractiveShell30 from IPython.core.iplib import InteractiveShell
30 insts = InteractiveShell.get_instances()31 insts = InteractiveShell.get_instances()
32 if len(insts)==0:
33 return None
31 most_recent = insts[0]34 most_recent = insts[0]
32 for inst in insts[1:]:35 for inst in insts[1:]:
33 if inst.created > most_recent.created:36 if inst.created > most_recent.created:
3437
=== modified file 'IPython/core/ipapp.py'
--- IPython/core/ipapp.py 2009-09-18 03:26:43 +0000
+++ IPython/core/ipapp.py 2009-11-21 00:11:11 +0000
@@ -1,7 +1,8 @@
1#!/usr/bin/env python1#!/usr/bin/env python
2# encoding: utf-82# encoding: utf-8
3"""3"""
4The main IPython application object4The :class:`~IPython.core.application.Application` object for the command
5line :command:`ipython` program.
56
6Authors:7Authors:
78
@@ -28,19 +29,17 @@
28import sys29import sys
29import warnings30import warnings
3031
31from IPython.core.application import Application, IPythonArgParseConfigLoader32from IPython.core.application import Application, BaseAppArgParseConfigLoader
32from IPython.core import release33from IPython.core import release
33from IPython.core.iplib import InteractiveShell34from IPython.core.iplib import InteractiveShell
34from IPython.config.loader import (35from IPython.config.loader import (
35 NoConfigDefault, 36 NoConfigDefault,
36 Config,37 Config,
37 ConfigError,
38 PyFileConfigLoader38 PyFileConfigLoader
39)39)
4040
41from IPython.lib import inputhook41from IPython.lib import inputhook
4242
43from IPython.utils.ipstruct import Struct
44from IPython.utils.genutils import filefind, get_ipython_dir43from IPython.utils.genutils import filefind, get_ipython_dir
4544
46#-----------------------------------------------------------------------------45#-----------------------------------------------------------------------------
@@ -80,181 +79,181 @@
80#-----------------------------------------------------------------------------79#-----------------------------------------------------------------------------
8180
82cl_args = (81cl_args = (
83 (('-autocall',), dict(82 (('--autocall',), dict(
84 type=int, dest='InteractiveShell.autocall', default=NoConfigDefault,83 type=int, dest='InteractiveShell.autocall', default=NoConfigDefault,
85 help='Set the autocall value (0,1,2).',84 help='Set the autocall value (0,1,2).',
86 metavar='InteractiveShell.autocall')85 metavar='InteractiveShell.autocall')
87 ),86 ),
88 (('-autoindent',), dict(87 (('--autoindent',), dict(
89 action='store_true', dest='InteractiveShell.autoindent', default=NoConfigDefault,88 action='store_true', dest='InteractiveShell.autoindent', default=NoConfigDefault,
90 help='Turn on autoindenting.')89 help='Turn on autoindenting.')
91 ),90 ),
92 (('-noautoindent',), dict(91 (('--no-autoindent',), dict(
93 action='store_false', dest='InteractiveShell.autoindent', default=NoConfigDefault,92 action='store_false', dest='InteractiveShell.autoindent', default=NoConfigDefault,
94 help='Turn off autoindenting.')93 help='Turn off autoindenting.')
95 ),94 ),
96 (('-automagic',), dict(95 (('--automagic',), dict(
97 action='store_true', dest='InteractiveShell.automagic', default=NoConfigDefault,96 action='store_true', dest='InteractiveShell.automagic', default=NoConfigDefault,
98 help='Turn on the auto calling of magic commands.')97 help='Turn on the auto calling of magic commands.')
99 ),98 ),
100 (('-noautomagic',), dict(99 (('--no-automagic',), dict(
101 action='store_false', dest='InteractiveShell.automagic', default=NoConfigDefault,100 action='store_false', dest='InteractiveShell.automagic', default=NoConfigDefault,
102 help='Turn off the auto calling of magic commands.')101 help='Turn off the auto calling of magic commands.')
103 ),102 ),
104 (('-autoedit_syntax',), dict(103 (('--autoedit-syntax',), dict(
105 action='store_true', dest='InteractiveShell.autoedit_syntax', default=NoConfigDefault,104 action='store_true', dest='InteractiveShell.autoedit_syntax', default=NoConfigDefault,
106 help='Turn on auto editing of files with syntax errors.')105 help='Turn on auto editing of files with syntax errors.')
107 ),106 ),
108 (('-noautoedit_syntax',), dict(107 (('--no-autoedit-syntax',), dict(
109 action='store_false', dest='InteractiveShell.autoedit_syntax', default=NoConfigDefault,108 action='store_false', dest='InteractiveShell.autoedit_syntax', default=NoConfigDefault,
110 help='Turn off auto editing of files with syntax errors.')109 help='Turn off auto editing of files with syntax errors.')
111 ),110 ),
112 (('-banner',), dict(111 (('--banner',), dict(
113 action='store_true', dest='Global.display_banner', default=NoConfigDefault,112 action='store_true', dest='Global.display_banner', default=NoConfigDefault,
114 help='Display a banner upon starting IPython.')113 help='Display a banner upon starting IPython.')
115 ),114 ),
116 (('-nobanner',), dict(115 (('--no-banner',), dict(
117 action='store_false', dest='Global.display_banner', default=NoConfigDefault,116 action='store_false', dest='Global.display_banner', default=NoConfigDefault,
118 help="Don't display a banner upon starting IPython.")117 help="Don't display a banner upon starting IPython.")
119 ),118 ),
120 (('-cache_size',), dict(119 (('--cache-size',), dict(
121 type=int, dest='InteractiveShell.cache_size', default=NoConfigDefault,120 type=int, dest='InteractiveShell.cache_size', default=NoConfigDefault,
122 help="Set the size of the output cache.",121 help="Set the size of the output cache.",
123 metavar='InteractiveShell.cache_size')122 metavar='InteractiveShell.cache_size')
124 ),123 ),
125 (('-classic',), dict(124 (('--classic',), dict(
126 action='store_true', dest='Global.classic', default=NoConfigDefault,125 action='store_true', dest='Global.classic', default=NoConfigDefault,
127 help="Gives IPython a similar feel to the classic Python prompt.")126 help="Gives IPython a similar feel to the classic Python prompt.")
128 ),127 ),
129 (('-colors',), dict(128 (('--colors',), dict(
130 type=str, dest='InteractiveShell.colors', default=NoConfigDefault,129 type=str, dest='InteractiveShell.colors', default=NoConfigDefault,
131 help="Set the color scheme (NoColor, Linux, and LightBG).",130 help="Set the color scheme (NoColor, Linux, and LightBG).",
132 metavar='InteractiveShell.colors')131 metavar='InteractiveShell.colors')
133 ),132 ),
134 (('-color_info',), dict(133 (('--color-info',), dict(
135 action='store_true', dest='InteractiveShell.color_info', default=NoConfigDefault,134 action='store_true', dest='InteractiveShell.color_info', default=NoConfigDefault,
136 help="Enable using colors for info related things.")135 help="Enable using colors for info related things.")
137 ),136 ),
138 (('-nocolor_info',), dict(137 (('--no-color-info',), dict(
139 action='store_false', dest='InteractiveShell.color_info', default=NoConfigDefault,138 action='store_false', dest='InteractiveShell.color_info', default=NoConfigDefault,
140 help="Disable using colors for info related things.")139 help="Disable using colors for info related things.")
141 ),140 ),
142 (('-confirm_exit',), dict(141 (('--confirm-exit',), dict(
143 action='store_true', dest='InteractiveShell.confirm_exit', default=NoConfigDefault,142 action='store_true', dest='InteractiveShell.confirm_exit', default=NoConfigDefault,
144 help="Prompt the user when existing.")143 help="Prompt the user when existing.")
145 ),144 ),
146 (('-noconfirm_exit',), dict(145 (('--no-confirm-exit',), dict(
147 action='store_false', dest='InteractiveShell.confirm_exit', default=NoConfigDefault,146 action='store_false', dest='InteractiveShell.confirm_exit', default=NoConfigDefault,
148 help="Don't prompt the user when existing.")147 help="Don't prompt the user when existing.")
149 ),148 ),
150 (('-deep_reload',), dict(149 (('--deep-reload',), dict(
151 action='store_true', dest='InteractiveShell.deep_reload', default=NoConfigDefault,150 action='store_true', dest='InteractiveShell.deep_reload', default=NoConfigDefault,
152 help="Enable deep (recursive) reloading by default.")151 help="Enable deep (recursive) reloading by default.")
153 ),152 ),
154 (('-nodeep_reload',), dict(153 (('--no-deep-reload',), dict(
155 action='store_false', dest='InteractiveShell.deep_reload', default=NoConfigDefault,154 action='store_false', dest='InteractiveShell.deep_reload', default=NoConfigDefault,
156 help="Disable deep (recursive) reloading by default.")155 help="Disable deep (recursive) reloading by default.")
157 ),156 ),
158 (('-editor',), dict(157 (('--editor',), dict(
159 type=str, dest='InteractiveShell.editor', default=NoConfigDefault,158 type=str, dest='InteractiveShell.editor', default=NoConfigDefault,
160 help="Set the editor used by IPython (default to $EDITOR/vi/notepad).",159 help="Set the editor used by IPython (default to $EDITOR/vi/notepad).",
161 metavar='InteractiveShell.editor')160 metavar='InteractiveShell.editor')
162 ),161 ),
163 (('-log','-l'), dict(162 (('--log','-l'), dict(
164 action='store_true', dest='InteractiveShell.logstart', default=NoConfigDefault,163 action='store_true', dest='InteractiveShell.logstart', default=NoConfigDefault,
165 help="Start logging to the default file (./ipython_log.py).")164 help="Start logging to the default file (./ipython_log.py).")
166 ),165 ),
167 (('-logfile','-lf'), dict(166 (('--logfile','-lf'), dict(
168 type=str, dest='InteractiveShell.logfile', default=NoConfigDefault,167 type=unicode, dest='InteractiveShell.logfile', default=NoConfigDefault,
169 help="Start logging to logfile.",168 help="Start logging to logfile.",
170 metavar='InteractiveShell.logfile')169 metavar='InteractiveShell.logfile')
171 ),170 ),
172 (('-logappend','-la'), dict(171 (('--log-append','-la'), dict(
173 type=str, dest='InteractiveShell.logappend', default=NoConfigDefault,172 type=unicode, dest='InteractiveShell.logappend', default=NoConfigDefault,
174 help="Start logging to logappend in append mode.",173 help="Start logging to the give file in append mode.",
175 metavar='InteractiveShell.logfile')174 metavar='InteractiveShell.logfile')
176 ),175 ),
177 (('-pdb',), dict(176 (('--pdb',), dict(
178 action='store_true', dest='InteractiveShell.pdb', default=NoConfigDefault,177 action='store_true', dest='InteractiveShell.pdb', default=NoConfigDefault,
179 help="Enable auto calling the pdb debugger after every exception.")178 help="Enable auto calling the pdb debugger after every exception.")
180 ),179 ),
181 (('-nopdb',), dict(180 (('--no-pdb',), dict(
182 action='store_false', dest='InteractiveShell.pdb', default=NoConfigDefault,181 action='store_false', dest='InteractiveShell.pdb', default=NoConfigDefault,
183 help="Disable auto calling the pdb debugger after every exception.")182 help="Disable auto calling the pdb debugger after every exception.")
184 ),183 ),
185 (('-pprint',), dict(184 (('--pprint',), dict(
186 action='store_true', dest='InteractiveShell.pprint', default=NoConfigDefault,185 action='store_true', dest='InteractiveShell.pprint', default=NoConfigDefault,
187 help="Enable auto pretty printing of results.")186 help="Enable auto pretty printing of results.")
188 ),187 ),
189 (('-nopprint',), dict(188 (('--no-pprint',), dict(
190 action='store_false', dest='InteractiveShell.pprint', default=NoConfigDefault,189 action='store_false', dest='InteractiveShell.pprint', default=NoConfigDefault,
191 help="Disable auto auto pretty printing of results.")190 help="Disable auto auto pretty printing of results.")
192 ),191 ),
193 (('-prompt_in1','-pi1'), dict(192 (('--prompt-in1','-pi1'), dict(
194 type=str, dest='InteractiveShell.prompt_in1', default=NoConfigDefault,193 type=str, dest='InteractiveShell.prompt_in1', default=NoConfigDefault,
195 help="Set the main input prompt ('In [\#]: ')",194 help="Set the main input prompt ('In [\#]: ')",
196 metavar='InteractiveShell.prompt_in1')195 metavar='InteractiveShell.prompt_in1')
197 ),196 ),
198 (('-prompt_in2','-pi2'), dict(197 (('--prompt-in2','-pi2'), dict(
199 type=str, dest='InteractiveShell.prompt_in2', default=NoConfigDefault,198 type=str, dest='InteractiveShell.prompt_in2', default=NoConfigDefault,
200 help="Set the secondary input prompt (' .\D.: ')",199 help="Set the secondary input prompt (' .\D.: ')",
201 metavar='InteractiveShell.prompt_in2')200 metavar='InteractiveShell.prompt_in2')
202 ),201 ),
203 (('-prompt_out','-po'), dict(202 (('--prompt-out','-po'), dict(
204 type=str, dest='InteractiveShell.prompt_out', default=NoConfigDefault,203 type=str, dest='InteractiveShell.prompt_out', default=NoConfigDefault,
205 help="Set the output prompt ('Out[\#]:')",204 help="Set the output prompt ('Out[\#]:')",
206 metavar='InteractiveShell.prompt_out')205 metavar='InteractiveShell.prompt_out')
207 ),206 ),
208 (('-quick',), dict(207 (('--quick',), dict(
209 action='store_true', dest='Global.quick', default=NoConfigDefault,208 action='store_true', dest='Global.quick', default=NoConfigDefault,
210 help="Enable quick startup with no config files.")209 help="Enable quick startup with no config files.")
211 ),210 ),
212 (('-readline',), dict(211 (('--readline',), dict(
213 action='store_true', dest='InteractiveShell.readline_use', default=NoConfigDefault,212 action='store_true', dest='InteractiveShell.readline_use', default=NoConfigDefault,
214 help="Enable readline for command line usage.")213 help="Enable readline for command line usage.")
215 ),214 ),
216 (('-noreadline',), dict(215 (('--no-readline',), dict(
217 action='store_false', dest='InteractiveShell.readline_use', default=NoConfigDefault,216 action='store_false', dest='InteractiveShell.readline_use', default=NoConfigDefault,
218 help="Disable readline for command line usage.")217 help="Disable readline for command line usage.")
219 ),218 ),
220 (('-screen_length','-sl'), dict(219 (('--screen-length','-sl'), dict(
221 type=int, dest='InteractiveShell.screen_length', default=NoConfigDefault,220 type=int, dest='InteractiveShell.screen_length', default=NoConfigDefault,
222 help='Number of lines on screen, used to control printing of long strings.',221 help='Number of lines on screen, used to control printing of long strings.',
223 metavar='InteractiveShell.screen_length')222 metavar='InteractiveShell.screen_length')
224 ),223 ),
225 (('-separate_in','-si'), dict(224 (('--separate-in','-si'), dict(
226 type=str, dest='InteractiveShell.separate_in', default=NoConfigDefault,225 type=str, dest='InteractiveShell.separate_in', default=NoConfigDefault,
227 help="Separator before input prompts. Default '\n'.",226 help="Separator before input prompts. Default '\n'.",
228 metavar='InteractiveShell.separate_in')227 metavar='InteractiveShell.separate_in')
229 ),228 ),
230 (('-separate_out','-so'), dict(229 (('--separate-out','-so'), dict(
231 type=str, dest='InteractiveShell.separate_out', default=NoConfigDefault,230 type=str, dest='InteractiveShell.separate_out', default=NoConfigDefault,
232 help="Separator before output prompts. Default 0 (nothing).",231 help="Separator before output prompts. Default 0 (nothing).",
233 metavar='InteractiveShell.separate_out')232 metavar='InteractiveShell.separate_out')
234 ),233 ),
235 (('-separate_out2','-so2'), dict(234 (('--separate-out2','-so2'), dict(
236 type=str, dest='InteractiveShell.separate_out2', default=NoConfigDefault,235 type=str, dest='InteractiveShell.separate_out2', default=NoConfigDefault,
237 help="Separator after output prompts. Default 0 (nonight).",236 help="Separator after output prompts. Default 0 (nonight).",
238 metavar='InteractiveShell.separate_out2')237 metavar='InteractiveShell.separate_out2')
239 ),238 ),
240 (('-nosep',), dict(239 (('-no-sep',), dict(
241 action='store_true', dest='Global.nosep', default=NoConfigDefault,240 action='store_true', dest='Global.nosep', default=NoConfigDefault,
242 help="Eliminate all spacing between prompts.")241 help="Eliminate all spacing between prompts.")
243 ),242 ),
244 (('-term_title',), dict(243 (('--term-title',), dict(
245 action='store_true', dest='InteractiveShell.term_title', default=NoConfigDefault,244 action='store_true', dest='InteractiveShell.term_title', default=NoConfigDefault,
246 help="Enable auto setting the terminal title.")245 help="Enable auto setting the terminal title.")
247 ),246 ),
248 (('-noterm_title',), dict(247 (('--no-term-title',), dict(
249 action='store_false', dest='InteractiveShell.term_title', default=NoConfigDefault,248 action='store_false', dest='InteractiveShell.term_title', default=NoConfigDefault,
250 help="Disable auto setting the terminal title.")249 help="Disable auto setting the terminal title.")
251 ),250 ),
252 (('-xmode',), dict(251 (('--xmode',), dict(
253 type=str, dest='InteractiveShell.xmode', default=NoConfigDefault,252 type=str, dest='InteractiveShell.xmode', default=NoConfigDefault,
254 help="Exception mode ('Plain','Context','Verbose')",253 help="Exception mode ('Plain','Context','Verbose')",
255 metavar='InteractiveShell.xmode')254 metavar='InteractiveShell.xmode')
256 ),255 ),
257 (('-ext',), dict(256 (('--ext',), dict(
258 type=str, dest='Global.extra_extension', default=NoConfigDefault,257 type=str, dest='Global.extra_extension', default=NoConfigDefault,
259 help="The dotted module name of an IPython extension to load.",258 help="The dotted module name of an IPython extension to load.",
260 metavar='Global.extra_extension')259 metavar='Global.extra_extension')
@@ -268,36 +267,39 @@
268 action='store_true', dest='Global.force_interact', default=NoConfigDefault,267 action='store_true', dest='Global.force_interact', default=NoConfigDefault,
269 help="If running code from the command line, become interactive afterwards.")268 help="If running code from the command line, become interactive afterwards.")
270 ),269 ),
271 (('-wthread',), dict(270 (('--wthread',), dict(
272 action='store_true', dest='Global.wthread', default=NoConfigDefault,271 action='store_true', dest='Global.wthread', default=NoConfigDefault,
273 help="Enable wxPython event loop integration.")272 help="Enable wxPython event loop integration.")
274 ),273 ),
275 (('-q4thread','-qthread'), dict(274 (('--q4thread','--qthread'), dict(
276 action='store_true', dest='Global.q4thread', default=NoConfigDefault,275 action='store_true', dest='Global.q4thread', default=NoConfigDefault,
277 help="Enable Qt4 event loop integration. Qt3 is no longer supported.")276 help="Enable Qt4 event loop integration. Qt3 is no longer supported.")
278 ),277 ),
279 (('-gthread',), dict(278 (('--gthread',), dict(
280 action='store_true', dest='Global.gthread', default=NoConfigDefault,279 action='store_true', dest='Global.gthread', default=NoConfigDefault,
281 help="Enable GTK event loop integration.")280 help="Enable GTK event loop integration.")
282 ),281 ),
283 # # These are only here to get the proper deprecation warnings282 # # These are only here to get the proper deprecation warnings
284 (('-pylab',), dict(283 (('--pylab',), dict(
285 action='store_true', dest='Global.pylab', default=NoConfigDefault,284 action='store_true', dest='Global.pylab', default=NoConfigDefault,
286 help="Disabled. Pylab has been disabled until matplotlib supports this version of IPython.")285 help="Disabled. Pylab has been disabled until matplotlib "
286 "supports this version of IPython.")
287 )287 )
288)288)
289289
290290
291class IPythonAppCLConfigLoader(IPythonArgParseConfigLoader):291class IPythonAppCLConfigLoader(BaseAppArgParseConfigLoader):
292292
293 arguments = cl_args293 arguments = cl_args
294294
295295
296_default_config_file_name = 'ipython_config.py'296default_config_file_name = u'ipython_config.py'
297
297298
298class IPythonApp(Application):299class IPythonApp(Application):
299 name = 'ipython'300 name = u'ipython'
300 config_file_name = _default_config_file_name301 description = 'IPython: an enhanced interactive Python shell.'
302 config_file_name = default_config_file_name
301303
302 def create_default_config(self):304 def create_default_config(self):
303 super(IPythonApp, self).create_default_config()305 super(IPythonApp, self).create_default_config()
@@ -313,11 +315,6 @@
313 # By default always interact by starting the IPython mainloop.315 # By default always interact by starting the IPython mainloop.
314 self.default_config.Global.interact = True316 self.default_config.Global.interact = True
315317
316 # Let the parent class set the default, but each time log_level
317 # changes from config, we need to update self.log_level as that is
318 # what updates the actual log level in self.log.
319 self.default_config.Global.log_level = self.log_level
320
321 # No GUI integration by default318 # No GUI integration by default
322 self.default_config.Global.wthread = False319 self.default_config.Global.wthread = False
323 self.default_config.Global.q4thread = False320 self.default_config.Global.q4thread = False
@@ -326,8 +323,9 @@
326 def create_command_line_config(self):323 def create_command_line_config(self):
327 """Create and return a command line config loader."""324 """Create and return a command line config loader."""
328 return IPythonAppCLConfigLoader(325 return IPythonAppCLConfigLoader(
329 description=ipython_desc,326 description=self.description,
330 version=release.version)327 version=release.version
328 )
331329
332 def post_load_command_line_config(self):330 def post_load_command_line_config(self):
333 """Do actions after loading cl config."""331 """Do actions after loading cl config."""
@@ -477,9 +475,9 @@
477 self.shell.showtraceback()475 self.shell.showtraceback()
478476
479 def _exec_file(self, fname):477 def _exec_file(self, fname):
480 full_filename = filefind(fname, ['.', self.ipythondir])478 full_filename = filefind(fname, [u'.', self.ipython_dir])
481 if os.path.isfile(full_filename):479 if os.path.isfile(full_filename):
482 if full_filename.endswith('.py'):480 if full_filename.endswith(u'.py'):
483 self.log.info("Running file in user namespace: %s" % full_filename)481 self.log.info("Running file in user namespace: %s" % full_filename)
484 self.shell.safe_execfile(full_filename, self.shell.user_ns)482 self.shell.safe_execfile(full_filename, self.shell.user_ns)
485 elif full_filename.endswith('.ipy'):483 elif full_filename.endswith('.ipy'):
@@ -527,20 +525,20 @@
527 self.shell.mainloop()525 self.shell.mainloop()
528526
529527
530def load_default_config(ipythondir=None):528def load_default_config(ipython_dir=None):
531 """Load the default config file from the default ipythondir.529 """Load the default config file from the default ipython_dir.
532530
533 This is useful for embedded shells.531 This is useful for embedded shells.
534 """532 """
535 if ipythondir is None:533 if ipython_dir is None:
536 ipythondir = get_ipython_dir()534 ipython_dir = get_ipython_dir()
537 cl = PyFileConfigLoader(_default_config_file_name, ipythondir)535 cl = PyFileConfigLoader(default_config_file_name, ipython_dir)
538 config = cl.load_config()536 config = cl.load_config()
539 return config537 return config
540538
541539
542def launch_new_instance():540def launch_new_instance():
543 """Create a run a full blown IPython instance"""541 """Create and run a full blown IPython instance"""
544 app = IPythonApp()542 app = IPythonApp()
545 app.start()543 app.start()
546544
547545
=== modified file 'IPython/core/iplib.py'
--- IPython/core/iplib.py 2009-10-09 22:54:40 +0000
+++ IPython/core/iplib.py 2009-11-21 00:11:11 +0000
@@ -162,6 +162,15 @@
162 return ed162 return ed
163163
164164
165def get_default_colors():
166 if sys.platform=='darwin':
167 return "LightBG"
168 elif os.name=='nt':
169 return 'Linux'
170 else:
171 return 'Linux'
172
173
165class SeparateStr(Str):174class SeparateStr(Str):
166 """A Str subclass to validate separate_in, separate_out, etc.175 """A Str subclass to validate separate_in, separate_out, etc.
167176
@@ -182,7 +191,7 @@
182class InteractiveShell(Component, Magic):191class InteractiveShell(Component, Magic):
183 """An enhanced, interactive shell for Python."""192 """An enhanced, interactive shell for Python."""
184193
185 autocall = Enum((0,1,2), config=True)194 autocall = Enum((0,1,2), default_value=1, config=True)
186 autoedit_syntax = CBool(False, config=True)195 autoedit_syntax = CBool(False, config=True)
187 autoindent = CBool(True, config=True)196 autoindent = CBool(True, config=True)
188 automagic = CBool(True, config=True)197 automagic = CBool(True, config=True)
@@ -192,7 +201,7 @@
192 cache_size = Int(1000, config=True)201 cache_size = Int(1000, config=True)
193 color_info = CBool(True, config=True)202 color_info = CBool(True, config=True)
194 colors = CaselessStrEnum(('NoColor','LightBG','Linux'), 203 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
195 default_value='LightBG', config=True)204 default_value=get_default_colors(), config=True)
196 confirm_exit = CBool(True, config=True)205 confirm_exit = CBool(True, config=True)
197 debug = CBool(False, config=True)206 debug = CBool(False, config=True)
198 deep_reload = CBool(False, config=True)207 deep_reload = CBool(False, config=True)
@@ -206,7 +215,7 @@
206 embedded_active = CBool(False)215 embedded_active = CBool(False)
207 editor = Str(get_default_editor(), config=True)216 editor = Str(get_default_editor(), config=True)
208 filename = Str("<ipython console>")217 filename = Str("<ipython console>")
209 ipythondir= Unicode('', config=True) # Set to get_ipython_dir() in __init__218 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
210 logstart = CBool(False, config=True)219 logstart = CBool(False, config=True)
211 logfile = Str('', config=True)220 logfile = Str('', config=True)
212 logappend = Str('', config=True)221 logappend = Str('', config=True)
@@ -264,7 +273,7 @@
264 # Subclasses with thread support should override this as needed.273 # Subclasses with thread support should override this as needed.
265 isthreaded = False274 isthreaded = False
266275
267 def __init__(self, parent=None, config=None, ipythondir=None, usage=None,276 def __init__(self, parent=None, config=None, ipython_dir=None, usage=None,
268 user_ns=None, user_global_ns=None,277 user_ns=None, user_global_ns=None,
269 banner1=None, banner2=None, display_banner=None,278 banner1=None, banner2=None, display_banner=None,
270 custom_exceptions=((),None)):279 custom_exceptions=((),None)):
@@ -274,7 +283,7 @@
274 super(InteractiveShell, self).__init__(parent, config=config)283 super(InteractiveShell, self).__init__(parent, config=config)
275284
276 # These are relatively independent and stateless285 # These are relatively independent and stateless
277 self.init_ipythondir(ipythondir)286 self.init_ipython_dir(ipython_dir)
278 self.init_instance_attrs()287 self.init_instance_attrs()
279 self.init_term_title()288 self.init_term_title()
280 self.init_usage(usage)289 self.init_usage(usage)
@@ -332,7 +341,7 @@
332 def _banner2_changed(self):341 def _banner2_changed(self):
333 self.compute_banner()342 self.compute_banner()
334343
335 def _ipythondir_changed(self, name, new):344 def _ipython_dir_changed(self, name, new):
336 if not os.path.isdir(new):345 if not os.path.isdir(new):
337 os.makedirs(new, mode = 0777)346 os.makedirs(new, mode = 0777)
338 if not os.path.isdir(self.ipython_extension_dir):347 if not os.path.isdir(self.ipython_extension_dir):
@@ -340,7 +349,7 @@
340349
341 @property350 @property
342 def ipython_extension_dir(self):351 def ipython_extension_dir(self):
343 return os.path.join(self.ipythondir, 'extensions')352 return os.path.join(self.ipython_dir, 'extensions')
344353
345 @property354 @property
346 def usable_screen_length(self):355 def usable_screen_length(self):
@@ -372,19 +381,19 @@
372 # init_* methods called by __init__381 # init_* methods called by __init__
373 #-------------------------------------------------------------------------382 #-------------------------------------------------------------------------
374383
375 def init_ipythondir(self, ipythondir):384 def init_ipython_dir(self, ipython_dir):
376 if ipythondir is not None:385 if ipython_dir is not None:
377 self.ipythondir = ipythondir386 self.ipython_dir = ipython_dir
378 self.config.Global.ipythondir = self.ipythondir387 self.config.Global.ipython_dir = self.ipython_dir
379 return388 return
380389
381 if hasattr(self.config.Global, 'ipythondir'):390 if hasattr(self.config.Global, 'ipython_dir'):
382 self.ipythondir = self.config.Global.ipythondir391 self.ipython_dir = self.config.Global.ipython_dir
383 else:392 else:
384 self.ipythondir = get_ipython_dir()393 self.ipython_dir = get_ipython_dir()
385394
386 # All children can just read this395 # All children can just read this
387 self.config.Global.ipythondir = self.ipythondir396 self.config.Global.ipython_dir = self.ipython_dir
388397
389 def init_instance_attrs(self):398 def init_instance_attrs(self):
390 self.jobs = BackgroundJobManager()399 self.jobs = BackgroundJobManager()
@@ -1070,7 +1079,7 @@
1070 histfname = 'history-%s' % self.profile1079 histfname = 'history-%s' % self.profile
1071 else:1080 else:
1072 histfname = 'history'1081 histfname = 'history'
1073 self.histfile = os.path.join(self.ipythondir, histfname)1082 self.histfile = os.path.join(self.ipython_dir, histfname)
10741083
1075 # Fill the history zero entry, user counter starts at 11084 # Fill the history zero entry, user counter starts at 1
1076 self.input_hist.append('\n')1085 self.input_hist.append('\n')
@@ -1078,12 +1087,12 @@
10781087
1079 def init_shadow_hist(self):1088 def init_shadow_hist(self):
1080 try:1089 try:
1081 self.db = pickleshare.PickleShareDB(self.ipythondir + "/db")1090 self.db = pickleshare.PickleShareDB(self.ipython_dir + "/db")
1082 except exceptions.UnicodeDecodeError:1091 except exceptions.UnicodeDecodeError:
1083 print "Your ipythondir can't be decoded to unicode!"1092 print "Your ipython_dir can't be decoded to unicode!"
1084 print "Please set HOME environment variable to something that"1093 print "Please set HOME environment variable to something that"
1085 print r"only has ASCII characters, e.g. c:\home"1094 print r"only has ASCII characters, e.g. c:\home"
1086 print "Now it is", self.ipythondir1095 print "Now it is", self.ipython_dir
1087 sys.exit()1096 sys.exit()
1088 self.shadowhist = ipcorehist.ShadowHist(self.db)1097 self.shadowhist = ipcorehist.ShadowHist(self.db)
10891098
@@ -1426,9 +1435,7 @@
1426 return outcomps1435 return outcomps
14271436
1428 def set_custom_completer(self,completer,pos=0):1437 def set_custom_completer(self,completer,pos=0):
1429 """set_custom_completer(completer,pos=0)1438 """Adds a new custom completer function.
1430
1431 Adds a new custom completer function.
14321439
1433 The position argument (defaults to 0) is the index in the completers1440 The position argument (defaults to 0) is the index in the completers
1434 list where you want the completer to be inserted."""1441 list where you want the completer to be inserted."""
@@ -1438,9 +1445,18 @@
1438 self.Completer.matchers.insert(pos,newcomp)1445 self.Completer.matchers.insert(pos,newcomp)
14391446
1440 def set_completer(self):1447 def set_completer(self):
1441 """reset readline's completer to be our own."""1448 """Reset readline's completer to be our own."""
1442 self.readline.set_completer(self.Completer.complete)1449 self.readline.set_completer(self.Completer.complete)
14431450
1451 def set_completer_frame(self, frame=None):
1452 """Set the frame of the completer."""
1453 if frame:
1454 self.Completer.namespace = frame.f_locals
1455 self.Completer.global_namespace = frame.f_globals
1456 else:
1457 self.Completer.namespace = self.user_ns
1458 self.Completer.global_namespace = self.user_global_ns
1459
1444 #-------------------------------------------------------------------------1460 #-------------------------------------------------------------------------
1445 # Things related to readline1461 # Things related to readline
1446 #-------------------------------------------------------------------------1462 #-------------------------------------------------------------------------
@@ -1913,7 +1929,7 @@
1913 # SystemExit exception changed between Python 2.4 and 2.5, so1929 # SystemExit exception changed between Python 2.4 and 2.5, so
1914 # the checks must be done in a version-dependent way.1930 # the checks must be done in a version-dependent way.
1915 show = False1931 show = False
1916 if status.message!=0 and not kw['exit_ignore']:1932 if status.args[0]==0 and not kw['exit_ignore']:
1917 show = True1933 show = True
1918 if show:1934 if show:
1919 self.showtraceback()1935 self.showtraceback()
@@ -2278,6 +2294,8 @@
2278 def get_component(self, name=None, klass=None):2294 def get_component(self, name=None, klass=None):
2279 """Fetch a component by name and klass in my tree."""2295 """Fetch a component by name and klass in my tree."""
2280 c = Component.get_instances(root=self, name=name, klass=klass)2296 c = Component.get_instances(root=self, name=name, klass=klass)
2297 if len(c) == 0:
2298 return None
2281 if len(c) == 1:2299 if len(c) == 1:
2282 return c[0]2300 return c[0]
2283 else:2301 else:
@@ -2309,7 +2327,7 @@
2309 You can put your extension modules anywhere you want, as long as2327 You can put your extension modules anywhere you want, as long as
2310 they can be imported by Python's standard import mechanism. However,2328 they can be imported by Python's standard import mechanism. However,
2311 to make it easy to write extensions, you can also put your extensions2329 to make it easy to write extensions, you can also put your extensions
2312 in ``os.path.join(self.ipythondir, 'extensions')``. This directory2330 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
2313 is added to ``sys.path`` automatically.2331 is added to ``sys.path`` automatically.
2314 """2332 """
2315 from IPython.utils.syspathcontext import prepended_to_syspath2333 from IPython.utils.syspathcontext import prepended_to_syspath
23162334
=== modified file 'IPython/core/magic.py'
--- IPython/core/magic.py 2009-10-09 22:54:40 +0000
+++ IPython/core/magic.py 2009-11-21 00:11:11 +0000
@@ -21,6 +21,7 @@
21import pdb21import pdb
22import pydoc22import pydoc
23import sys23import sys
24import shutil
24import re25import re
25import tempfile26import tempfile
26import time27import time
@@ -1268,7 +1269,6 @@
1268 If you want IPython to automatically do this on every exception, see1269 If you want IPython to automatically do this on every exception, see
1269 the %pdb magic for more details.1270 the %pdb magic for more details.
1270 """1271 """
1271
1272 self.shell.debugger(force=True)1272 self.shell.debugger(force=True)
12731273
1274 @testdec.skip_doctest1274 @testdec.skip_doctest
@@ -3378,34 +3378,6 @@
3378 qr = IPython.core.usage.quick_reference + self.magic_magic('-brief')3378 qr = IPython.core.usage.quick_reference + self.magic_magic('-brief')
3379 3379
3380 page(qr)3380 page(qr)
3381
3382 def magic_upgrade(self,arg):
3383 """ Upgrade your IPython installation
3384
3385 This will copy the config files that don't yet exist in your
3386 ipython dir from the system config dir. Use this after upgrading
3387 IPython if you don't wish to delete your .ipython dir.
3388
3389 Call with -nolegacy to get rid of ipythonrc* files (recommended for
3390 new users)
3391
3392 """
3393 ip = self.getapi()
3394 ipinstallation = path(IPython.__file__).dirname()
3395 upgrade_script = '%s "%s"' % (sys.executable,ipinstallation / 'utils' / 'upgradedir.py')
3396 src_config = ipinstallation / 'config' / 'userconfig'
3397 userdir = path(ip.config.IPYTHONDIR)
3398 cmd = '%s "%s" "%s"' % (upgrade_script, src_config, userdir)
3399 print ">",cmd
3400 shell(cmd)
3401 if arg == '-nolegacy':
3402 legacy = userdir.files('ipythonrc*')
3403 print "Nuking legacy files:",legacy
3404
3405 [p.remove() for p in legacy]
3406 suffix = (sys.platform == 'win32' and '.ini' or '')
3407 (userdir / ('ipythonrc' + suffix)).write_text('# Empty, see ipy_user_conf.py\n')
3408
34093381
3410 def magic_doctest_mode(self,parameter_s=''):3382 def magic_doctest_mode(self,parameter_s=''):
3411 """Toggle doctest mode on and off.3383 """Toggle doctest mode on and off.
@@ -3550,4 +3522,59 @@
3550 """Reload an IPython extension by its module name."""3522 """Reload an IPython extension by its module name."""
3551 self.reload_extension(module_str)3523 self.reload_extension(module_str)
35523524
3525 def magic_install_profiles(self, s):
3526 """Install the default IPython profiles into the .ipython dir.
3527
3528 If the default profiles have already been installed, they will not
3529 be overwritten. You can force overwriting them by using the ``-o``
3530 option::
3531
3532 In [1]: %install_profiles -o
3533 """
3534 if '-o' in s:
3535 overwrite = True
3536 else:
3537 overwrite = False
3538 from IPython.config import profile
3539 profile_dir = os.path.split(profile.__file__)[0]
3540 ipython_dir = self.ipython_dir
3541 files = os.listdir(profile_dir)
3542
3543 to_install = []
3544 for f in files:
3545 if f.startswith('ipython_config'):
3546 src = os.path.join(profile_dir, f)
3547 dst = os.path.join(ipython_dir, f)
3548 if (not os.path.isfile(dst)) or overwrite:
3549 to_install.append((f, src, dst))
3550 if len(to_install)>0:
3551 print "Installing profiles to: ", ipython_dir
3552 for (f, src, dst) in to_install:
3553 shutil.copy(src, dst)
3554 print " %s" % f
3555
3556 def magic_install_default_config(self, s):
3557 """Install IPython's default config file into the .ipython dir.
3558
3559 If the default config file (:file:`ipython_config.py`) is already
3560 installed, it will not be overwritten. You can force overwriting
3561 by using the ``-o`` option::
3562
3563 In [1]: %install_default_config
3564 """
3565 if '-o' in s:
3566 overwrite = True
3567 else:
3568 overwrite = False
3569 from IPython.config import default
3570 config_dir = os.path.split(default.__file__)[0]
3571 ipython_dir = self.ipython_dir
3572 default_config_file_name = 'ipython_config.py'
3573 src = os.path.join(config_dir, default_config_file_name)
3574 dst = os.path.join(ipython_dir, default_config_file_name)
3575 if (not os.path.isfile(dst)) or overwrite:
3576 shutil.copy(src, dst)
3577 print "Installing default config file: %s" % dst
3578
3579
3553# end Magic3580# end Magic
35543581
=== removed file 'IPython/core/oldusersetup.py'
--- IPython/core/oldusersetup.py 2009-08-18 06:55:22 +0000
+++ IPython/core/oldusersetup.py 1970-01-01 00:00:00 +0000
@@ -1,219 +0,0 @@
1# -*- coding: utf-8 -*-
2"""
3Main IPython Component
4"""
5
6#-----------------------------------------------------------------------------
7# Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
8# Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
9# Copyright (C) 2008-2009 The IPython Development Team
10#
11# Distributed under the terms of the BSD License. The full license is in
12# the file COPYING, distributed as part of this software.
13#-----------------------------------------------------------------------------
14
15#-----------------------------------------------------------------------------
16# Imports
17#-----------------------------------------------------------------------------
18
19import glob
20import os
21import shutil
22import sys
23
24from IPython.utils.genutils import *
25
26def user_setup(ipythondir,rc_suffix,mode='install',interactive=True):
27 """Install or upgrade the user configuration directory.
28
29 Can be called when running for the first time or to upgrade the user's
30 .ipython/ directory.
31
32 Parameters
33 ----------
34 ipythondir : path
35 The directory to be used for installation/upgrade. In 'install' mode,
36 if this path already exists, the function exits immediately.
37
38 rc_suffix : str
39 Extension for the config files. On *nix platforms it is typically the
40 empty string, while Windows normally uses '.ini'.
41
42 mode : str, optional
43 Valid modes are 'install' and 'upgrade'.
44
45 interactive : bool, optional
46 If False, do not wait for user input on any errors. Normally after
47 printing its status information, this function waits for the user to
48 hit Return before proceeding. This is because the default use case is
49 when first installing the IPython configuration, so we want the user to
50 acknowledge the initial message, which contains some useful
51 information.
52 """
53
54 # For automatic use, deactivate all i/o
55 if interactive:
56 def wait():
57 try:
58 raw_input("Please press <RETURN> to start IPython.")
59 except EOFError:
60 print >> Term.cout
61 print '*'*70
62
63 def printf(s):
64 print s
65 else:
66 wait = lambda : None
67 printf = lambda s : None
68
69 # Install mode should be re-entrant: if the install dir already exists,
70 # bail out cleanly.
71 # XXX. This is too hasty to return. We need to check to make sure that
72 # all the expected config files and directories are actually there. We
73 # currently have a failure mode if someone deletes a needed config file
74 # but still has the ipythondir.
75 if mode == 'install' and os.path.isdir(ipythondir):
76 return
77
78 cwd = os.getcwd() # remember where we started
79 glb = glob.glob
80
81 printf('*'*70)
82 if mode == 'install':
83 printf(
84"""Welcome to IPython. I will try to create a personal configuration directory
85where you can customize many aspects of IPython's functionality in:\n""")
86 else:
87 printf('I am going to upgrade your configuration in:')
88
89 printf(ipythondir)
90
91 rcdirend = os.path.join('IPython','config','userconfig')
92 cfg = lambda d: os.path.join(d,rcdirend)
93 try:
94 rcdir = filter(os.path.isdir,map(cfg,sys.path))[0]
95 printf("Initializing from configuration: %s" % rcdir)
96 except IndexError:
97 warning = """
98Installation error. IPython's directory was not found.
99
100Check the following:
101
102The ipython/IPython directory should be in a directory belonging to your
103PYTHONPATH environment variable (that is, it should be in a directory
104belonging to sys.path). You can copy it explicitly there or just link to it.
105
106IPython will create a minimal default configuration for you.
107
108"""
109 warn(warning)
110 wait()
111
112 if sys.platform =='win32':
113 inif = 'ipythonrc.ini'
114 else:
115 inif = 'ipythonrc'
116 minimal_setup = {'ipy_user_conf.py' : 'import ipy_defaults',
117 inif : '# intentionally left blank' }
118 os.makedirs(ipythondir, mode = 0777)
119 for f, cont in minimal_setup.items():
120 # In 2.5, this can be more cleanly done using 'with'
121 fobj = file(ipythondir + '/' + f,'w')
122 fobj.write(cont)
123 fobj.close()
124
125 return
126
127 if mode == 'install':
128 try:
129 shutil.copytree(rcdir,ipythondir)
130 os.chdir(ipythondir)
131 rc_files = glb("ipythonrc*")
132 for rc_file in rc_files:
133 os.rename(rc_file,rc_file+rc_suffix)
134 except:
135 warning = """
136
137There was a problem with the installation:
138%s
139Try to correct it or contact the developers if you think it's a bug.
140IPython will proceed with builtin defaults.""" % sys.exc_info()[1]
141 warn(warning)
142 wait()
143 return
144
145 elif mode == 'upgrade':
146 try:
147 os.chdir(ipythondir)
148 except:
149 printf("""
150Can not upgrade: changing to directory %s failed. Details:
151%s
152""" % (ipythondir,sys.exc_info()[1]) )
153 wait()
154 return
155 else:
156 sources = glb(os.path.join(rcdir,'[A-Za-z]*'))
157 for new_full_path in sources:
158 new_filename = os.path.basename(new_full_path)
159 if new_filename.startswith('ipythonrc'):
160 new_filename = new_filename + rc_suffix
161 # The config directory should only contain files, skip any
162 # directories which may be there (like CVS)
163 if os.path.isdir(new_full_path):
164 continue
165 if os.path.exists(new_filename):
166 old_file = new_filename+'.old'
167 if os.path.exists(old_file):
168 os.remove(old_file)
169 os.rename(new_filename,old_file)
170 shutil.copy(new_full_path,new_filename)
171 else:
172 raise ValueError('unrecognized mode for install: %r' % mode)
173
174 # Fix line-endings to those native to each platform in the config
175 # directory.
176 try:
177 os.chdir(ipythondir)
178 except:
179 printf("""
180Problem: changing to directory %s failed.
181Details:
182%s
183
184Some configuration files may have incorrect line endings. This should not
185cause any problems during execution. """ % (ipythondir,sys.exc_info()[1]) )
186 wait()
187 else:
188 for fname in glb('ipythonrc*'):
189 try:
190 native_line_ends(fname,backup=0)
191 except IOError:
192 pass
193
194 if mode == 'install':
195 printf("""
196Successful installation!
197
198Please read the sections 'Initial Configuration' and 'Quick Tips' in the
199IPython manual (there are both HTML and PDF versions supplied with the
200distribution) to make sure that your system environment is properly configured
201to take advantage of IPython's features.
202
203Important note: the configuration system has changed! The old system is
204still in place, but its setting may be partly overridden by the settings in
205"~/.ipython/ipy_user_conf.py" config file. Please take a look at the file
206if some of the new settings bother you.
207
208""")
209 else:
210 printf("""
211Successful upgrade!
212
213All files in your directory:
214%(ipythondir)s
215which would have been overwritten by the upgrade were backed up with a .old
216extension. If you had made particular customizations in those files you may
217want to merge them back into the new files.""" % locals() )
218 wait()
219 os.chdir(cwd)
220\ No newline at end of file0\ No newline at end of file
2211
=== modified file 'IPython/core/prefilter.py' (properties changed: -x to +x)
--- IPython/core/prefilter.py 2009-09-28 05:57:44 +0000
+++ IPython/core/prefilter.py 2009-11-21 00:11:11 +0000
@@ -39,7 +39,7 @@
39from IPython.core.page import page39from IPython.core.page import page
4040
41from IPython.utils.traitlets import List, Int, Any, Str, CBool, Bool41from IPython.utils.traitlets import List, Int, Any, Str, CBool, Bool
42from IPython.utils.genutils import make_quoted_expr42from IPython.utils.genutils import make_quoted_expr, Term
43from IPython.utils.autoattr import auto_attr43from IPython.utils.autoattr import auto_attr
4444
45#-----------------------------------------------------------------------------45#-----------------------------------------------------------------------------
4646
=== modified file 'IPython/core/tests/test_iplib.py'
--- IPython/core/tests/test_iplib.py 2009-08-19 21:56:41 +0000
+++ IPython/core/tests/test_iplib.py 2009-11-21 00:11:11 +0000
@@ -15,7 +15,7 @@
15# our own packages15# our own packages
16from IPython.core import iplib16from IPython.core import iplib
17from IPython.core import ipapi17from IPython.core import ipapi
18from IPython.core.oldusersetup import user_setup18
1919
20#-----------------------------------------------------------------------------20#-----------------------------------------------------------------------------
21# Globals21# Globals
@@ -54,27 +54,4 @@
54 continue54 continue
55 nt.assert_equals(len(ns),0)55 nt.assert_equals(len(ns),0)
5656
57
58# make sure that user_setup can be run re-entrantly in 'install' mode.
59def test_user_setup():
60 # use a lambda to pass kwargs to the generator
61 user_setup = lambda a,k: user_setup(*a,**k)
62 kw = dict(mode='install', interactive=False)
63
64 # Call the user setup and verify that the directory exists
65 yield user_setup, (ip.config.IPYTHONDIR,''), kw
66 yield os.path.isdir, ip.config.IPYTHONDIR
67
68 # Now repeat the operation with a non-existent directory. Check both that
69 # the call succeeds and that the directory is created.
70 tmpdir = tempfile.mktemp(prefix='ipython-test-')
71 # Use a try with an empty except because try/finally doesn't work with a
72 # yield in Python 2.4.
73 try:
74 yield user_setup, (tmpdir,''), kw
75 yield os.path.isdir, tmpdir
76 except:
77 pass
78 # Clean up the temp dir once done
79 shutil.rmtree(tmpdir)
80 57
81\ No newline at end of file58\ No newline at end of file
8259
=== modified file 'IPython/core/usage.py'
--- IPython/core/usage.py 2009-08-18 23:09:56 +0000
+++ IPython/core/usage.py 2009-11-21 00:11:11 +0000
@@ -40,7 +40,7 @@
40 in directories.40 in directories.
4141
42 In the rest of this text, we will refer to this directory as42 In the rest of this text, we will refer to this directory as
43 IPYTHONDIR.43 IPYTHON_DIR.
4444
45REGULAR OPTIONS45REGULAR OPTIONS
46 After the above threading options have been given, regular options can46 After the above threading options have been given, regular options can
@@ -150,9 +150,9 @@
150 here (in case your default EDITOR is something like Emacs).150 here (in case your default EDITOR is something like Emacs).
151151
152 -ipythondir <name>152 -ipythondir <name>
153 The name of your IPython configuration directory IPYTHONDIR.153 The name of your IPython configuration directory IPYTHON_DIR.
154 This can also be specified through the environment variable154 This can also be specified through the environment variable
155 IPYTHONDIR.155 IPYTHON_DIR.
156156
157 -log|l Generate a log file of all input. The file is named157 -log|l Generate a log file of all input. The file is named
158 ipython_log.py in your current directory (which prevents logs158 ipython_log.py in your current directory (which prevents logs
@@ -201,10 +201,10 @@
201201
202 -profile|p <name>202 -profile|p <name>
203 Assume that your config file is ipythonrc-<name> (looks in cur-203 Assume that your config file is ipythonrc-<name> (looks in cur-
204 rent dir first, then in IPYTHONDIR). This is a quick way to keep204 rent dir first, then in IPYTHON_DIR). This is a quick way to keep
205 and load multiple config files for different tasks, especially205 and load multiple config files for different tasks, especially
206 if you use the include option of config files. You can keep a206 if you use the include option of config files. You can keep a
207 basic IPYTHONDIR/ipythonrc file and then have other 'profiles'207 basic IPYTHON_DIR/ipythonrc file and then have other 'profiles'
208 which include this one and load extra things for particular208 which include this one and load extra things for particular
209 tasks. For example:209 tasks. For example:
210210
@@ -245,7 +245,7 @@
245 -rcfile <name>245 -rcfile <name>
246 Name of your IPython resource configuration file. normally246 Name of your IPython resource configuration file. normally
247 IPython loads ipythonrc (from current directory) or247 IPython loads ipythonrc (from current directory) or
248 IPYTHONDIR/ipythonrc. If the loading of your config file fails,248 IPYTHON_DIR/ipythonrc. If the loading of your config file fails,
249 IPython starts with a bare bones configuration (no modules249 IPython starts with a bare bones configuration (no modules
250 loaded at all).250 loaded at all).
251251
@@ -284,7 +284,7 @@
284 Simply removes all input/output separators.284 Simply removes all input/output separators.
285285
286 -upgrade286 -upgrade
287 Allows you to upgrade your IPYTHONDIR configuration when you287 Allows you to upgrade your IPYTHON_DIR configuration when you
288 install a new version of IPython. Since new versions may288 install a new version of IPython. Since new versions may
289 include new command lines options or example files, this copies289 include new command lines options or example files, this copies
290 updated ipythonrc-type files. However, it backs up (with a .old290 updated ipythonrc-type files. However, it backs up (with a .old
291291
=== renamed file 'IPython/kernel/magic.py' => 'IPython/extensions/parallelmagic.py'
--- IPython/kernel/magic.py 2009-09-12 15:58:55 +0000
+++ IPython/extensions/parallelmagic.py 2009-11-21 00:11:11 +0000
@@ -1,171 +1,205 @@
1#!/usr/bin/env python
1# encoding: utf-82# encoding: utf-8
23
3"""Magic command interface for interactive parallel work."""4"""Magic command interface for interactive parallel work."""
45
5__docformat__ = "restructuredtext en"6#-----------------------------------------------------------------------------
67# Copyright (C) 2008-2009 The IPython Development Team
7#-------------------------------------------------------------------------------
8# Copyright (C) 2008 The IPython Development Team
9#8#
10# Distributed under the terms of the BSD License. The full license is in9# Distributed under the terms of the BSD License. The full license is in
11# the file COPYING, distributed as part of this software.10# the file COPYING, distributed as part of this software.
12#-------------------------------------------------------------------------------11#-----------------------------------------------------------------------------
1312
14#-------------------------------------------------------------------------------13#-----------------------------------------------------------------------------
15# Imports14# Imports
16#-------------------------------------------------------------------------------15#-----------------------------------------------------------------------------
1716
18import new17import new
1918
20from IPython.core.iplib import InteractiveShell19from IPython.core.component import Component
21from IPython.core.shell import MTInteractiveShell20from IPython.utils.traitlets import Bool, Any
2221from IPython.utils.autoattr import auto_attr
23from twisted.internet.defer import Deferred22
2423#-----------------------------------------------------------------------------
25
26#-------------------------------------------------------------------------------
27# Definitions of magic functions for use with IPython24# Definitions of magic functions for use with IPython
28#-------------------------------------------------------------------------------25#-----------------------------------------------------------------------------
2926
30NO_ACTIVE_CONTROLLER = """27
31Error: No Controller is activated28NO_ACTIVE_MULTIENGINE_CLIENT = """
32Use activate() on a RemoteController object to activate it for magics.29Use activate() on a MultiEngineClient object to activate it for magics.
33"""30"""
3431
35def magic_result(self,parameter_s=''):32
36 """Print the result of command i on all engines of the active controller.33class ParalleMagicComponent(Component):
37 34 """A component to manage the %result, %px and %autopx magics."""
38 To activate a controller in IPython, first create it and then call35
39 the activate() method.36 active_multiengine_client = Any()
40 37 verbose = Bool(False, config=True)
41 Then you can do the following:38
42 39 def __init__(self, parent, name=None, config=None):
43 >>> result # Print the latest result40 super(ParalleMagicComponent, self).__init__(parent, name=name, config=config)
44 Printing result... 41 self._define_magics()
45 [127.0.0.1:0] In [1]: b = 1042 # A flag showing if autopx is activated or not
46 [127.0.0.1:1] In [1]: b = 1043 self.autopx = False
47 44
48 >>> result 0 # Print result 045 # Access other components like this rather than by a regular attribute.
49 In [14]: result 046 # This won't lookup the InteractiveShell object until it is used and
50 Printing result... 47 # then it is cached. This is both efficient and couples this class
51 [127.0.0.1:0] In [0]: a = 548 # more loosely to InteractiveShell.
52 [127.0.0.1:1] In [0]: a = 549 @auto_attr
53 """50 def shell(self):
54 try:51 return Component.get_instances(
55 activeController = __IPYTHON__.activeController52 root=self.root,
56 except AttributeError:53 klass='IPython.core.iplib.InteractiveShell')[0]
57 print NO_ACTIVE_CONTROLLER54
58 else:55 def _define_magics(self):
56 """Define the magic functions."""
57 self.shell.define_magic('result', self.magic_result)
58 self.shell.define_magic('px', self.magic_px)
59 self.shell.define_magic('autopx', self.magic_autopx)
60
61 def magic_result(self, ipself, parameter_s=''):
62 """Print the result of command i on all engines..
63
64 To use this a :class:`MultiEngineClient` instance must be created
65 and then activated by calling its :meth:`activate` method.
66
67 Then you can do the following::
68
69 In [23]: %result
70 Out[23]:
71 <Results List>
72 [0] In [6]: a = 10
73 [1] In [6]: a = 10
74
75 In [22]: %result 6
76 Out[22]:
77 <Results List>
78 [0] In [6]: a = 10
79 [1] In [6]: a = 10
80 """
81 if self.active_multiengine_client is None:
82 print NO_ACTIVE_MULTIENGINE_CLIENT
83 return
84
59 try:85 try:
60 index = int(parameter_s)86 index = int(parameter_s)
61 except:87 except:
62 index = None88 index = None
63 result = activeController.get_result(index)89 result = self.active_multiengine_client.get_result(index)
64 return result90 return result
6591
66def magic_px(self,parameter_s=''):92 def magic_px(self, ipself, parameter_s=''):
67 """Executes the given python command on the active IPython Controller.93 """Executes the given python command in parallel.
68 94
69 To activate a Controller in IPython, first create it and then call95 To use this a :class:`MultiEngineClient` instance must be created
70 the activate() method.96 and then activated by calling its :meth:`activate` method.
71
72 Then you can do the following:
73
74 >>> %px a = 5 # Runs a = 5 on all nodes
75 """
76
77 try:
78 activeController = __IPYTHON__.activeController
79 except AttributeError:
80 print NO_ACTIVE_CONTROLLER
81 else:
82 print "Parallel execution on engines: %s" % activeController.targets
83 result = activeController.execute(parameter_s)
84 return result
85
86def pxrunsource(self, source, filename="<input>", symbol="single"):
87
88 try:
89 code = self.compile(source, filename, symbol)
90 except (OverflowError, SyntaxError, ValueError):
91 # Case 1
92 self.showsyntaxerror(filename)
93 return None
94
95 if code is None:
96 # Case 2
97 return True
98
99 # Case 3
100 # Because autopx is enabled, we now call executeAll or disable autopx if
101 # %autopx or autopx has been called
102 if 'get_ipython().magic("%autopx' in source or 'get_ipython().magic("autopx' in source:
103 _disable_autopx(self)
104 return False
105 else:
106 try:
107 result = self.activeController.execute(source)
108 except:
109 self.showtraceback()
110 else:
111 print result.__repr__()
112 return False
113 97
114def magic_autopx(self, parameter_s=''):98 Then you can do the following::
115 """Toggles auto parallel mode for the active IPython Controller.99
116 100 In [24]: %px a = 5
117 To activate a Controller in IPython, first create it and then call101 Parallel execution on engines: all
118 the activate() method.102 Out[24]:
119 103 <Results List>
120 Then you can do the following:104 [0] In [7]: a = 5
121 105 [1] In [7]: a = 5
122 >>> %autopx # Now all commands are executed in parallel106 """
123 Auto Parallel Enabled107
124 Type %autopx to disable108 if self.active_multiengine_client is None:
125 ...109 print NO_ACTIVE_MULTIENGINE_CLIENT
126 >>> %autopx # Now all commands are locally executed110 return
127 Auto Parallel Disabled111 print "Parallel execution on engines: %s" % self.active_multiengine_client.targets
128 """112 result = self.active_multiengine_client.execute(parameter_s)
129 113 return result
130 if hasattr(self, 'autopx'):114
131 if self.autopx == True:115 def magic_autopx(self, ipself, parameter_s=''):
132 _disable_autopx(self)116 """Toggles auto parallel mode.
117
118 To use this a :class:`MultiEngineClient` instance must be created
119 and then activated by calling its :meth:`activate` method. Once this
120 is called, all commands typed at the command line are send to
121 the engines to be executed in parallel. To control which engine
122 are used, set the ``targets`` attributed of the multiengine client
123 before entering ``%autopx`` mode.
124
125 Then you can do the following::
126
127 In [25]: %autopx
128 %autopx to enabled
129
130 In [26]: a = 10
131 <Results List>
132 [0] In [8]: a = 10
133 [1] In [8]: a = 10
134
135
136 In [27]: %autopx
137 %autopx disabled
138 """
139 if self.autopx:
140 self._disable_autopx()
133 else:141 else:
134 _enable_autopx(self)142 self._enable_autopx()
135 else:143
136 _enable_autopx(self)144 def _enable_autopx(self):
137145 """Enable %autopx mode by saving the original runsource and installing
138def _enable_autopx(self):146 pxrunsource.
139 """Enable %autopx mode by saving the original runsource and installing 147 """
140 pxrunsource.148 if self.active_multiengine_client is None:
141 """149 print NO_ACTIVE_MULTIENGINE_CLIENT
142 try:150 return
143 activeController = __IPYTHON__.activeController151
144 except AttributeError:152 self._original_runsource = self.shell.runsource
145 print "No active RemoteController found, use RemoteController.activate()."153 self.shell.runsource = new.instancemethod(
146 else:154 self.pxrunsource, self.shell, self.shell.__class__
147 self._original_runsource = self.runsource155 )
148 self.runsource = new.instancemethod(pxrunsource, self, self.__class__)
149 self.autopx = True156 self.autopx = True
150 print "Auto Parallel Enabled\nType %autopx to disable"157 print "%autopx enabled"
151158
152def _disable_autopx(self):159 def _disable_autopx(self):
153 """Disable %autopx by restoring the original runsource."""160 """Disable %autopx by restoring the original InteractiveShell.runsource."""
154 if hasattr(self, 'autopx'):161 if self.autopx:
155 if self.autopx == True:162 self.shell.runsource = self._original_runsource
156 self.runsource = self._original_runsource
157 self.autopx = False163 self.autopx = False
158 print "Auto Parallel Disabled"164 print "%autopx disabled"
159 165
160# Add the new magic function to the class dict:166 def pxrunsource(self, ipself, source, filename="<input>", symbol="single"):
161167 """A parallel replacement for InteractiveShell.runsource."""
162InteractiveShell.magic_result = magic_result168
163InteractiveShell.magic_px = magic_px169 try:
164InteractiveShell.magic_autopx = magic_autopx170 code = ipself.compile(source, filename, symbol)
165171 except (OverflowError, SyntaxError, ValueError):
166# And remove the global name to keep global namespace clean. Don't worry, the172 # Case 1
167# copy bound to IPython stays, we're just removing the global name.173 ipself.showsyntaxerror(filename)
168del magic_result174 return None
169del magic_px175
170del magic_autopx176 if code is None:
177 # Case 2
178 return True
179
180 # Case 3
181 # Because autopx is enabled, we now call executeAll or disable autopx if
182 # %autopx or autopx has been called
183 if 'get_ipython().magic("%autopx' in source or 'get_ipython().magic("autopx' in source:
184 self._disable_autopx()
185 return False
186 else:
187 try:
188 result = self.active_multiengine_client.execute(source)
189 except:
190 ipself.showtraceback()
191 else:
192 print result.__repr__()
193 return False
194
195
196_loaded = False
197
198
199def load_ipython_extension(ip):
200 """Load the extension in IPython."""
201 global _loaded
202 if not _loaded:
203 prd = ParalleMagicComponent(ip, name='parallel_magic')
204 _loaded = True
171205
172206
=== modified file 'IPython/frontend/wx/ipythonx.py'
--- IPython/frontend/wx/ipythonx.py 2009-03-29 01:05:30 +0000
+++ IPython/frontend/wx/ipythonx.py 2009-11-21 00:11:11 +0000
@@ -6,11 +6,10 @@
6try:6try:
7 import wx7 import wx
8except ImportError, e:8except ImportError, e:
9 e.message = """%s9 e.args[0] = """%s
10________________________________________________________________________________10________________________________________________________________________________
11You need wxPython to run this application.11You need wxPython to run this application.
12""" % e.message12""" % e.args[0]
13 e.args = (e.message, ) + e.args[1:]
14 raise e13 raise e
1514
16from wx_frontend import WxController15from wx_frontend import WxController
1716
=== modified file 'IPython/gui/wx/wxIPython.py'
--- IPython/gui/wx/wxIPython.py 2009-08-19 21:56:41 +0000
+++ IPython/gui/wx/wxIPython.py 2009-11-21 00:11:11 +0000
@@ -109,7 +109,7 @@
109109
110 def optionSave(self, name, value):110 def optionSave(self, name, value):
111 ip = get()111 ip = get()
112 path = ip.config.IPYTHONDIR112 path = ip.ipython_dir
113 opt = open(path + '/options.conf','w')113 opt = open(path + '/options.conf','w')
114114
115 try:115 try:
@@ -126,7 +126,7 @@
126 def optionLoad(self):126 def optionLoad(self):
127 try:127 try:
128 ip = get()128 ip = get()
129 path = ip.config.IPYTHONDIR129 path = ip.ipython_dir
130 opt = open(path + '/options.conf','r')130 opt = open(path + '/options.conf','r')
131 lines = opt.readlines()131 lines = opt.readlines()
132 opt.close()132 opt.close()
133133
=== modified file 'IPython/kernel/asyncclient.py'
--- IPython/kernel/asyncclient.py 2008-07-22 02:39:52 +0000
+++ IPython/kernel/asyncclient.py 2009-11-21 00:11:11 +0000
@@ -1,3 +1,4 @@
1#!/usr/bin/env python
1# encoding: utf-82# encoding: utf-8
23
3"""Asynchronous clients for the IPython controller.4"""Asynchronous clients for the IPython controller.
@@ -9,32 +10,32 @@
910
10The main methods are are `get_*_client` and `get_client`.11The main methods are are `get_*_client` and `get_client`.
11"""12"""
1213#-----------------------------------------------------------------------------
13__docformat__ = "restructuredtext en"14# Copyright (C) 2008-2009 The IPython Development Team
14
15#-------------------------------------------------------------------------------
16# Copyright (C) 2008 The IPython Development Team
17#15#
18# Distributed under the terms of the BSD License. The full license is in16# Distributed under the terms of the BSD License. The full license is in
19# the file COPYING, distributed as part of this software.17# the file COPYING, distributed as part of this software.
20#-------------------------------------------------------------------------------18#-----------------------------------------------------------------------------
2119
22#-------------------------------------------------------------------------------20#-----------------------------------------------------------------------------
23# Imports21# Imports
24#-------------------------------------------------------------------------------22#-----------------------------------------------------------------------------
2523
26from IPython.kernel import codeutil24from IPython.kernel import codeutil
27from IPython.kernel.clientconnector import ClientConnector25from IPython.kernel.clientconnector import (
26 AsyncClientConnector,
27 AsyncCluster
28)
2829
29# Other things that the user will need30# Other things that the user will need
30from IPython.kernel.task import MapTask, StringTask31from IPython.kernel.task import MapTask, StringTask
31from IPython.kernel.error import CompositeError32from IPython.kernel.error import CompositeError
3233
33#-------------------------------------------------------------------------------34#-----------------------------------------------------------------------------
34# Code35# Code
35#-------------------------------------------------------------------------------36#-----------------------------------------------------------------------------
3637
37_client_tub = ClientConnector()38_client_tub = AsyncClientConnector()
38get_multiengine_client = _client_tub.get_multiengine_client39get_multiengine_client = _client_tub.get_multiengine_client
39get_task_client = _client_tub.get_task_client40get_task_client = _client_tub.get_task_client
40get_client = _client_tub.get_client41get_client = _client_tub.get_client
4142
=== modified file 'IPython/kernel/client.py'
--- IPython/kernel/client.py 2009-07-02 21:35:36 +0000
+++ IPython/kernel/client.py 2009-11-21 00:11:11 +0000
@@ -1,3 +1,4 @@
1#!/usr/bin/env python
1# encoding: utf-82# encoding: utf-8
23
3"""This module contains blocking clients for the controller interfaces.4"""This module contains blocking clients for the controller interfaces.
@@ -15,33 +16,36 @@
15 * CompositeError16 * CompositeError
16"""17"""
1718
18__docformat__ = "restructuredtext en"19#-----------------------------------------------------------------------------
1920# Copyright (C) 2008-2009 The IPython Development Team
20#-------------------------------------------------------------------------------
21# Copyright (C) 2008 The IPython Development Team
22#21#
23# Distributed under the terms of the BSD License. The full license is in22# Distributed under the terms of the BSD License. The full license is in
24# the file COPYING, distributed as part of this software.23# the file COPYING, distributed as part of this software.
25#-------------------------------------------------------------------------------24#-----------------------------------------------------------------------------
2625
27#-------------------------------------------------------------------------------26#-----------------------------------------------------------------------------
28# Imports27# Imports
29#-------------------------------------------------------------------------------28#-----------------------------------------------------------------------------
3029
30from cStringIO import StringIO
31import sys31import sys
32import warnings
3233
33# from IPython.utils import growl34# from IPython.utils import growl
34# growl.start("IPython1 Client")35# growl.start("IPython1 Client")
3536
3637
37from twisted.internet import reactor38from twisted.internet import reactor
38from IPython.kernel.clientconnector import ClientConnector39from twisted.internet.error import PotentialZombieWarning
40from twisted.python import log
41
42from IPython.kernel.clientconnector import ClientConnector, Cluster
39from IPython.kernel.twistedutil import ReactorInThread43from IPython.kernel.twistedutil import ReactorInThread
40from IPython.kernel.twistedutil import blockingCallFromThread44from IPython.kernel.twistedutil import blockingCallFromThread
4145
42# These enable various things 46# These enable various things
43from IPython.kernel import codeutil47from IPython.kernel import codeutil
44import IPython.kernel.magic48# import IPython.kernel.magic
4549
46# Other things that the user will need50# Other things that the user will need
47from IPython.kernel.task import MapTask, StringTask51from IPython.kernel.task import MapTask, StringTask
@@ -51,46 +55,34 @@
51# Code55# Code
52#-------------------------------------------------------------------------------56#-------------------------------------------------------------------------------
5357
58warnings.simplefilter('ignore', PotentialZombieWarning)
59
54_client_tub = ClientConnector()60_client_tub = ClientConnector()
5561
5662get_multiengine_client = _client_tub.get_multiengine_client
57def get_multiengine_client(furl_or_file=''):63get_task_client = _client_tub.get_task_client
58 """Get the blocking MultiEngine client.
59
60 :Parameters:
61 furl_or_file : str
62 A furl or a filename containing a furl. If empty, the
63 default furl_file will be used
64
65 :Returns:
66 The connected MultiEngineClient instance
67 """
68 client = blockingCallFromThread(_client_tub.get_multiengine_client,
69 furl_or_file)
70 return client.adapt_to_blocking_client()
71
72def get_task_client(furl_or_file=''):
73 """Get the blocking Task client.
74
75 :Parameters:
76 furl_or_file : str
77 A furl or a filename containing a furl. If empty, the
78 default furl_file will be used
79
80 :Returns:
81 The connected TaskClient instance
82 """
83 client = blockingCallFromThread(_client_tub.get_task_client,
84 furl_or_file)
85 return client.adapt_to_blocking_client()
86
87
88MultiEngineClient = get_multiengine_client64MultiEngineClient = get_multiengine_client
89TaskClient = get_task_client65TaskClient = get_task_client
9066
9167# This isn't great. I should probably set this up in the ReactorInThread
68# class below. But, it does work for now.
69log.startLogging(sys.stdout, setStdout=0)
9270
93# Now we start the reactor in a thread71# Now we start the reactor in a thread
94rit = ReactorInThread()72rit = ReactorInThread()
95rit.setDaemon(True)73rit.setDaemon(True)
96rit.start()
97\ No newline at end of file74\ No newline at end of file
75rit.start()
76
77
78
79
80__all__ = [
81 'MapTask',
82 'StringTask',
83 'MultiEngineClient',
84 'TaskClient',
85 'CompositeError',
86 'get_task_client',
87 'get_multiengine_client',
88 'Cluster'
89]
9890
=== modified file 'IPython/kernel/clientconnector.py'
--- IPython/kernel/clientconnector.py 2009-08-27 21:34:41 +0000
+++ IPython/kernel/clientconnector.py 2009-11-21 00:11:11 +0000
@@ -1,142 +1,268 @@
1#!/usr/bin/env python
1# encoding: utf-82# encoding: utf-8
23
3"""A class for handling client connections to the controller."""4"""Facilities for handling client connections to the controller."""
45
5__docformat__ = "restructuredtext en"6#-----------------------------------------------------------------------------
67# Copyright (C) 2008-2009 The IPython Development Team
7#-------------------------------------------------------------------------------
8# Copyright (C) 2008 The IPython Development Team
9#8#
10# Distributed under the terms of the BSD License. The full license is in9# Distributed under the terms of the BSD License. The full license is in
11# the file COPYING, distributed as part of this software.10# the file COPYING, distributed as part of this software.
12#-------------------------------------------------------------------------------11#-----------------------------------------------------------------------------
1312
14#-------------------------------------------------------------------------------13#-----------------------------------------------------------------------------
15# Imports14# Imports
16#-------------------------------------------------------------------------------15#-----------------------------------------------------------------------------
16
17from __future__ import with_statement
18import os
19
20from IPython.kernel.fcutil import (
21 Tub,
22 find_furl,
23 is_valid_furl_or_file,
24 validate_furl_or_file,
25 FURLError
26)
27from IPython.kernel.clusterdir import ClusterDir, ClusterDirError
28from IPython.kernel.launcher import IPClusterLauncher
29from IPython.kernel.twistedutil import (
30 gatherBoth,
31 make_deferred,
32 blockingCallFromThread,
33 sleep_deferred
34)
35from IPython.utils.importstring import import_item
36from IPython.utils.genutils import get_ipython_dir
1737
18from twisted.internet import defer38from twisted.internet import defer
1939from twisted.internet.defer import inlineCallbacks, returnValue
20from IPython.kernel.fcutil import Tub, UnauthenticatedTub40from twisted.python import failure, log
2141
22from IPython.kernel.config import config_manager as kernel_config_manager42#-----------------------------------------------------------------------------
23from IPython.utils.importstring import import_item
24from IPython.kernel.fcutil import find_furl
25
26co = kernel_config_manager.get_config_obj()
27client_co = co['client']
28
29#-------------------------------------------------------------------------------
30# The ClientConnector class43# The ClientConnector class
31#-------------------------------------------------------------------------------44#-----------------------------------------------------------------------------
3245
33class ClientConnector(object):46DELAY = 0.2
34 """47MAX_TRIES = 9
35 This class gets remote references from furls and returns the wrapped clients.48
36 49
37 This class is also used in `client.py` and `asyncclient.py` to create 50class ClientConnectorError(Exception):
38 a single per client-process Tub.51 pass
39 """52
40 53
54class AsyncClientConnector(object):
55 """A class for getting remote references and clients from furls.
56
57 This start a single :class:`Tub` for all remote reference and caches
58 references.
59 """
60
41 def __init__(self):61 def __init__(self):
42 self._remote_refs = {}62 self._remote_refs = {}
43 self.tub = Tub()63 self.tub = Tub()
44 self.tub.startService()64 self.tub.startService()
45 65
66 def _find_furl(self, profile='default', cluster_dir=None,
67 furl_or_file=None, furl_file_name=None,
68 ipython_dir=None):
69 """Find a FURL file by profile+ipython_dir or cluster dir.
70
71 This raises an :exc:`~IPython.kernel.fcutil.FURLError` exception
72 if a FURL file can't be found.
73 """
74 # Try by furl_or_file
75 if furl_or_file is not None:
76 validate_furl_or_file(furl_or_file)
77 return furl_or_file
78
79 if furl_file_name is None:
80 raise FURLError('A furl_file_name must be provided')
81
82 # Try by cluster_dir
83 if cluster_dir is not None:
84 cluster_dir_obj = ClusterDir.find_cluster_dir(cluster_dir)
85 sdir = cluster_dir_obj.security_dir
86 furl_file = os.path.join(sdir, furl_file_name)
87 validate_furl_or_file(furl_file)
88 return furl_file
89
90 # Try by profile
91 if ipython_dir is None:
92 ipython_dir = get_ipython_dir()
93 if profile is not None:
94 cluster_dir_obj = ClusterDir.find_cluster_dir_by_profile(
95 ipython_dir, profile)
96 sdir = cluster_dir_obj.security_dir
97 furl_file = os.path.join(sdir, furl_file_name)
98 validate_furl_or_file(furl_file)
99 return furl_file
100
101 raise FURLError('Could not find a valid FURL file.')
102
46 def get_reference(self, furl_or_file):103 def get_reference(self, furl_or_file):
47 """104 """Get a remote reference using a furl or a file containing a furl.
48 Get a remote reference using a furl or a file containing a furl.105
49
50 Remote references are cached locally so once a remote reference106 Remote references are cached locally so once a remote reference
51 has been retrieved for a given furl, the cached version is 107 has been retrieved for a given furl, the cached version is
52 returned.108 returned.
53 109
54 :Parameters:110 Parameters
55 furl_or_file : str111 ----------
56 A furl or a filename containing a furl112 furl_or_file : str
57 113 A furl or a filename containing a furl. This should already be
58 :Returns:114 validated, but might not yet exist.
59 A deferred to a remote reference115
116 Returns
117 -------
118 A deferred to a remote reference
60 """119 """
61 furl = find_furl(furl_or_file)120 furl = furl_or_file
62 if furl in self._remote_refs:121 if furl in self._remote_refs:
63 d = defer.succeed(self._remote_refs[furl])122 d = defer.succeed(self._remote_refs[furl])
64 else:123 else:
65 d = self.tub.getReference(furl)124 d = self.tub.getReference(furl)
66 d.addCallback(self.save_ref, furl)125 d.addCallback(self._save_ref, furl)
67 return d126 return d
68 127
69 def save_ref(self, ref, furl):128 def _save_ref(self, ref, furl):
70 """129 """Cache a remote reference by its furl."""
71 Cache a remote reference by its furl.
72 """
73 self._remote_refs[furl] = ref130 self._remote_refs[furl] = ref
74 return ref131 return ref
75 132
76 def get_task_client(self, furl_or_file=''):133 def get_task_client(self, profile='default', cluster_dir=None,
77 """134 furl_or_file=None, ipython_dir=None,
78 Get the task controller client.135 delay=DELAY, max_tries=MAX_TRIES):
79 136 """Get the task controller client.
80 This method is a simple wrapper around `get_client` that allow137
81 `furl_or_file` to be empty, in which case, the furls is taken138 This method is a simple wrapper around `get_client` that passes in
82 from the default furl file given in the configuration.139 the default name of the task client FURL file. Usually only
83 140 the ``profile`` option will be needed. If a FURL file can't be
84 :Parameters:141 found by its profile, use ``cluster_dir`` or ``furl_or_file``.
85 furl_or_file : str142
86 A furl or a filename containing a furl. If empty, the143 Parameters
87 default furl_file will be used144 ----------
88 145 profile : str
89 :Returns:146 The name of a cluster directory profile (default="default"). The
90 A deferred to the actual client class147 cluster directory "cluster_<profile>" will be searched for
91 """148 in ``os.getcwd()``, the ipython_dir and then in the directories
92 task_co = client_co['client_interfaces']['task']149 listed in the :env:`IPCLUSTER_DIR_PATH` environment variable.
93 if furl_or_file:150 cluster_dir : str
94 ff = furl_or_file151 The full path to a cluster directory. This is useful if profiles
95 else:152 are not being used.
96 ff = task_co['furl_file']153 furl_or_file : str
97 return self.get_client(ff)154 A furl or a filename containing a FURLK. This is useful if you
98155 simply know the location of the FURL file.
99 def get_multiengine_client(self, furl_or_file=''):156 ipython_dir : str
100 """157 The location of the ipython_dir if different from the default.
101 Get the multiengine controller client.158 This is used if the cluster directory is being found by profile.
102 159 delay : float
103 This method is a simple wrapper around `get_client` that allow160 The initial delay between re-connection attempts. Susequent delays
104 `furl_or_file` to be empty, in which case, the furls is taken161 get longer according to ``delay[i] = 1.5*delay[i-1]``.
105 from the default furl file given in the configuration.162 max_tries : int
106 163 The max number of re-connection attempts.
107 :Parameters:164
108 furl_or_file : str165 Returns
109 A furl or a filename containing a furl. If empty, the166 -------
110 default furl_file will be used167 A deferred to the actual client class.
111 168 """
112 :Returns:169 return self.get_client(
113 A deferred to the actual client class170 profile, cluster_dir, furl_or_file,
114 """171 'ipcontroller-tc.furl', ipython_dir,
115 task_co = client_co['client_interfaces']['multiengine']172 delay, max_tries
116 if furl_or_file:173 )
117 ff = furl_or_file174
118 else:175 def get_multiengine_client(self, profile='default', cluster_dir=None,
119 ff = task_co['furl_file']176 furl_or_file=None, ipython_dir=None,
120 return self.get_client(ff)177 delay=DELAY, max_tries=MAX_TRIES):
178 """Get the multiengine controller client.
179
180 This method is a simple wrapper around `get_client` that passes in
181 the default name of the task client FURL file. Usually only
182 the ``profile`` option will be needed. If a FURL file can't be
183 found by its profile, use ``cluster_dir`` or ``furl_or_file``.
184
185 Parameters
186 ----------
187 profile : str
188 The name of a cluster directory profile (default="default"). The
189 cluster directory "cluster_<profile>" will be searched for
190 in ``os.getcwd()``, the ipython_dir and then in the directories
191 listed in the :env:`IPCLUSTER_DIR_PATH` environment variable.
192 cluster_dir : str
193 The full path to a cluster directory. This is useful if profiles
194 are not being used.
195 furl_or_file : str
196 A furl or a filename containing a FURLK. This is useful if you
197 simply know the location of the FURL file.
198 ipython_dir : str
199 The location of the ipython_dir if different from the default.
200 This is used if the cluster directory is being found by profile.
201 delay : float
202 The initial delay between re-connection attempts. Susequent delays
203 get longer according to ``delay[i] = 1.5*delay[i-1]``.
204 max_tries : int
205 The max number of re-connection attempts.
206
207 Returns
208 -------
209 A deferred to the actual client class.
210 """
211 return self.get_client(
212 profile, cluster_dir, furl_or_file,
213 'ipcontroller-mec.furl', ipython_dir,
214 delay, max_tries
215 )
121 216
122 def get_client(self, furl_or_file):217 def get_client(self, profile='default', cluster_dir=None,
123 """218 furl_or_file=None, furl_file_name=None, ipython_dir=None,
124 Get a remote reference and wrap it in a client by furl.219 delay=DELAY, max_tries=MAX_TRIES):
125 220 """Get a remote reference and wrap it in a client by furl.
126 This method first gets a remote reference and then calls its 221
127 `get_client_name` method to find the apprpriate client class222 This method is a simple wrapper around `get_client` that passes in
128 that should be used to wrap the remote reference.223 the default name of the task client FURL file. Usually only
129 224 the ``profile`` option will be needed. If a FURL file can't be
130 :Parameters:225 found by its profile, use ``cluster_dir`` or ``furl_or_file``.
131 furl_or_file : str226
132 A furl or a filename containing a furl227 Parameters
133 228 ----------
134 :Returns:229 profile : str
135 A deferred to the actual client class230 The name of a cluster directory profile (default="default"). The
136 """231 cluster directory "cluster_<profile>" will be searched for
137 furl = find_furl(furl_or_file)232 in ``os.getcwd()``, the ipython_dir and then in the directories
138 d = self.get_reference(furl)233 listed in the :env:`IPCLUSTER_DIR_PATH` environment variable.
139 def wrap_remote_reference(rr):234 cluster_dir : str
235 The full path to a cluster directory. This is useful if profiles
236 are not being used.
237 furl_or_file : str
238 A furl or a filename containing a FURL. This is useful if you
239 simply know the location of the FURL file.
240 furl_file_name : str
241 The filename (not the full path) of the FURL. This must be
242 provided if ``furl_or_file`` is not.
243 ipython_dir : str
244 The location of the ipython_dir if different from the default.
245 This is used if the cluster directory is being found by profile.
246 delay : float
247 The initial delay between re-connection attempts. Susequent delays
248 get longer according to ``delay[i] = 1.5*delay[i-1]``.
249 max_tries : int
250 The max number of re-connection attempts.
251
252 Returns
253 -------
254 A deferred to the actual client class. Or a failure to a
255 :exc:`FURLError`.
256 """
257 try:
258 furl_file = self._find_furl(
259 profile, cluster_dir, furl_or_file,
260 furl_file_name, ipython_dir
261 )
262 except FURLError:
263 return defer.fail(failure.Failure())
264
265 def _wrap_remote_reference(rr):
140 d = rr.callRemote('get_client_name')266 d = rr.callRemote('get_client_name')
141 d.addCallback(lambda name: import_item(name))267 d.addCallback(lambda name: import_item(name))
142 def adapt(client_interface):268 def adapt(client_interface):
@@ -146,5 +272,502 @@
146 d.addCallback(adapt)272 d.addCallback(adapt)
147273
148 return d274 return d
149 d.addCallback(wrap_remote_reference)275
150 return d276 d = self._try_to_connect(furl_file, delay, max_tries, attempt=0)
277 d.addCallback(_wrap_remote_reference)
278 d.addErrback(self._handle_error, furl_file)
279 return d
280
281 def _handle_error(self, f, furl_file):
282 raise ClientConnectorError('Could not connect to the controller '
283 'using the FURL file. This usually means that i) the controller '
284 'was not started or ii) a firewall was blocking the client from '
285 'connecting to the controller: %s' % furl_file)
286
287 @inlineCallbacks
288 def _try_to_connect(self, furl_or_file, delay, max_tries, attempt):
289 """Try to connect to the controller with retry logic."""
290 if attempt < max_tries:
291 log.msg("Connecting [%r]" % attempt)
292 try:
293 self.furl = find_furl(furl_or_file)
294 # Uncomment this to see the FURL being tried.
295 # log.msg("FURL: %s" % self.furl)
296 rr = yield self.get_reference(self.furl)
297 log.msg("Connected: %s" % furl_or_file)
298 except:
299 if attempt==max_tries-1:
300 # This will propagate the exception all the way to the top
301 # where it can be handled.
302 raise
303 else:
304 yield sleep_deferred(delay)
305 rr = yield self._try_to_connect(
306 furl_or_file, 1.5*delay, max_tries, attempt+1
307 )
308 returnValue(rr)
309 else:
310 returnValue(rr)
311 else:
312 raise ClientConnectorError(
313 'Could not connect to controller, max_tries (%r) exceeded. '
314 'This usually means that i) the controller was not started, '
315 'or ii) a firewall was blocking the client from connecting '
316 'to the controller.' % max_tries
317 )
318
319
320class ClientConnector(object):
321 """A blocking version of a client connector.
322
323 This class creates a single :class:`Tub` instance and allows remote
324 references and client to be retrieved by their FURLs. Remote references
325 are cached locally and FURL files can be found using profiles and cluster
326 directories.
327 """
328
329 def __init__(self):
330 self.async_cc = AsyncClientConnector()
331
332 def get_task_client(self, profile='default', cluster_dir=None,
333 furl_or_file=None, ipython_dir=None,
334 delay=DELAY, max_tries=MAX_TRIES):
335 """Get the task client.
336
337 Usually only the ``profile`` option will be needed. If a FURL file
338 can't be found by its profile, use ``cluster_dir`` or
339 ``furl_or_file``.
340
341 Parameters
342 ----------
343 profile : str
344 The name of a cluster directory profile (default="default"). The
345 cluster directory "cluster_<profile>" will be searched for
346 in ``os.getcwd()``, the ipython_dir and then in the directories
347 listed in the :env:`IPCLUSTER_DIR_PATH` environment variable.
348 cluster_dir : str
349 The full path to a cluster directory. This is useful if profiles
350 are not being used.
351 furl_or_file : str
352 A furl or a filename containing a FURLK. This is useful if you
353 simply know the location of the FURL file.
354 ipython_dir : str
355 The location of the ipython_dir if different from the default.
356 This is used if the cluster directory is being found by profile.
357 delay : float
358 The initial delay between re-connection attempts. Susequent delays
359 get longer according to ``delay[i] = 1.5*delay[i-1]``.
360 max_tries : int
361 The max number of re-connection attempts.
362
363 Returns
364 -------
365 The task client instance.
366 """
367 client = blockingCallFromThread(
368 self.async_cc.get_task_client, profile, cluster_dir,
369 furl_or_file, ipython_dir, delay, max_tries
370 )
371 return client.adapt_to_blocking_client()
372
373 def get_multiengine_client(self, profile='default', cluster_dir=None,
374 furl_or_file=None, ipython_dir=None,
375 delay=DELAY, max_tries=MAX_TRIES):
376 """Get the multiengine client.
377
378 Usually only the ``profile`` option will be needed. If a FURL file
379 can't be found by its profile, use ``cluster_dir`` or
380 ``furl_or_file``.
381
382 Parameters
383 ----------
384 profile : str
385 The name of a cluster directory profile (default="default"). The
386 cluster directory "cluster_<profile>" will be searched for
387 in ``os.getcwd()``, the ipython_dir and then in the directories
388 listed in the :env:`IPCLUSTER_DIR_PATH` environment variable.
389 cluster_dir : str
390 The full path to a cluster directory. This is useful if profiles
391 are not being used.
392 furl_or_file : str
393 A furl or a filename containing a FURLK. This is useful if you
394 simply know the location of the FURL file.
395 ipython_dir : str
396 The location of the ipython_dir if different from the default.
397 This is used if the cluster directory is being found by profile.
398 delay : float
399 The initial delay between re-connection attempts. Susequent delays
400 get longer according to ``delay[i] = 1.5*delay[i-1]``.
401 max_tries : int
402 The max number of re-connection attempts.
403
404 Returns
405 -------
406 The multiengine client instance.
407 """
408 client = blockingCallFromThread(
409 self.async_cc.get_multiengine_client, profile, cluster_dir,
410 furl_or_file, ipython_dir, delay, max_tries
411 )
412 return client.adapt_to_blocking_client()
413
414 def get_client(self, profile='default', cluster_dir=None,
415 furl_or_file=None, ipython_dir=None,
416 delay=DELAY, max_tries=MAX_TRIES):
417 client = blockingCallFromThread(
418 self.async_cc.get_client, profile, cluster_dir,
419 furl_or_file, ipython_dir,
420 delay, max_tries
421 )
422 return client.adapt_to_blocking_client()
423
424
425class ClusterStateError(Exception):
426 pass
427
428
429class AsyncCluster(object):
430 """An class that wraps the :command:`ipcluster` script."""
431
432 def __init__(self, profile='default', cluster_dir=None, ipython_dir=None,
433 auto_create=False, auto_stop=True):
434 """Create a class to manage an IPython cluster.
435
436 This class calls the :command:`ipcluster` command with the right
437 options to start an IPython cluster. Typically a cluster directory
438 must be created (:command:`ipcluster create`) and configured before
439 using this class. Configuration is done by editing the
440 configuration files in the top level of the cluster directory.
441
442 Parameters
443 ----------
444 profile : str
445 The name of a cluster directory profile (default="default"). The
446 cluster directory "cluster_<profile>" will be searched for
447 in ``os.getcwd()``, the ipython_dir and then in the directories
448 listed in the :env:`IPCLUSTER_DIR_PATH` environment variable.
449 cluster_dir : str
450 The full path to a cluster directory. This is useful if profiles
451 are not being used.
452 ipython_dir : str
453 The location of the ipython_dir if different from the default.
454 This is used if the cluster directory is being found by profile.
455 auto_create : bool
456 Automatically create the cluster directory it is dones't exist.
457 This will usually only make sense if using a local cluster
458 (default=False).
459 auto_stop : bool
460 Automatically stop the cluster when this instance is garbage
461 collected (default=True). This is useful if you want the cluster
462 to live beyond your current process. There is also an instance
463 attribute ``auto_stop`` to change this behavior.
464 """
465 self._setup_cluster_dir(profile, cluster_dir, ipython_dir, auto_create)
466 self.state = 'before'
467 self.launcher = None
468 self.client_connector = None
469 self.auto_stop = auto_stop
470
471 def __del__(self):
472 if self.auto_stop and self.state=='running':
473 print "Auto stopping the cluster..."
474 self.stop()
475
476 @property
477 def location(self):
478 if hasattr(self, 'cluster_dir_obj'):
479 return self.cluster_dir_obj.location
480 else:
481 return ''
482
483 @property
484 def running(self):
485 if self.state=='running':
486 return True
487 else:
488 return False
489
490 def _setup_cluster_dir(self, profile, cluster_dir, ipython_dir, auto_create):
491 if ipython_dir is None:
492 ipython_dir = get_ipython_dir()
493 if cluster_dir is not None:
494 try:
495 self.cluster_dir_obj = ClusterDir.find_cluster_dir(cluster_dir)
496 except ClusterDirError:
497 pass
498 if profile is not None:
499 try:
500 self.cluster_dir_obj = ClusterDir.find_cluster_dir_by_profile(
501 ipython_dir, profile)
502 except ClusterDirError:
503 pass
504 if auto_create or profile=='default':
505 # This should call 'ipcluster create --profile default
506 self.cluster_dir_obj = ClusterDir.create_cluster_dir_by_profile(
507 ipython_dir, profile)
508 else:
509 raise ClusterDirError('Cluster dir not found.')
510
511 @make_deferred
512 def start(self, n=2):
513 """Start the IPython cluster with n engines.
514
515 Parameters
516 ----------
517 n : int
518 The number of engine to start.
519 """
520 # We might want to add logic to test if the cluster has started
521 # by another process....
522 if not self.state=='running':
523 self.launcher = IPClusterLauncher(os.getcwd())
524 self.launcher.ipcluster_n = n
525 self.launcher.ipcluster_subcommand = 'start'
526 d = self.launcher.start()
527 d.addCallback(self._handle_start)
528 return d
529 else:
530 raise ClusterStateError('Cluster is already running')
531
532 @make_deferred
533 def stop(self):
534 """Stop the IPython cluster if it is running."""
535 if self.state=='running':
536 d1 = self.launcher.observe_stop()
537 d1.addCallback(self._handle_stop)
538 d2 = self.launcher.stop()
539 return gatherBoth([d1, d2], consumeErrors=True)
540 else:
541 raise ClusterStateError("Cluster not running")
542
543 def get_multiengine_client(self, delay=DELAY, max_tries=MAX_TRIES):
544 """Get the multiengine client for the running cluster.
545
546 If this fails, it means that the cluster has not finished starting.
547 Usually waiting a few seconds are re-trying will solve this.
548 """
549 if self.client_connector is None:
550 self.client_connector = AsyncClientConnector()
551 return self.client_connector.get_multiengine_client(
552 cluster_dir=self.cluster_dir_obj.location,
553 delay=delay, max_tries=max_tries
554 )
555
556 def get_task_client(self, delay=DELAY, max_tries=MAX_TRIES):
557 """Get the task client for the running cluster.
558
559 If this fails, it means that the cluster has not finished starting.
560 Usually waiting a few seconds are re-trying will solve this.
561 """
562 if self.client_connector is None:
563 self.client_connector = AsyncClientConnector()
564 return self.client_connector.get_task_client(
565 cluster_dir=self.cluster_dir_obj.location,
566 delay=delay, max_tries=max_tries
567 )
568
569 def get_ipengine_logs(self):
570 return self.get_logs_by_name('ipengine')
571
572 def get_ipcontroller_logs(self):
573 return self.get_logs_by_name('ipcontroller')
574
575 def get_ipcluster_logs(self):
576 return self.get_logs_by_name('ipcluster')
577
578 def get_logs_by_name(self, name='ipcluster'):
579 log_dir = self.cluster_dir_obj.log_dir
580 logs = {}
581 for log in os.listdir(log_dir):
582 if log.startswith(name + '-') and log.endswith('.log'):
583 with open(os.path.join(log_dir, log), 'r') as f:
584 logs[log] = f.read()
585 return logs
586
587 def get_logs(self):
588 d = self.get_ipcluster_logs()
589 d.update(self.get_ipengine_logs())
590 d.update(self.get_ipcontroller_logs())
591 return d
592
593 def _handle_start(self, r):
594 self.state = 'running'
595
596 def _handle_stop(self, r):
597 self.state = 'after'
598
599
600class Cluster(object):
601
602
603 def __init__(self, profile='default', cluster_dir=None, ipython_dir=None,
604 auto_create=False, auto_stop=True):
605 """Create a class to manage an IPython cluster.
606
607 This class calls the :command:`ipcluster` command with the right
608 options to start an IPython cluster. Typically a cluster directory
609 must be created (:command:`ipcluster create`) and configured before
610 using this class. Configuration is done by editing the
611 configuration files in the top level of the cluster directory.
612
613 Parameters
614 ----------
615 profile : str
616 The name of a cluster directory profile (default="default"). The
617 cluster directory "cluster_<profile>" will be searched for
618 in ``os.getcwd()``, the ipython_dir and then in the directories
619 listed in the :env:`IPCLUSTER_DIR_PATH` environment variable.
620 cluster_dir : str
621 The full path to a cluster directory. This is useful if profiles
622 are not being used.
623 ipython_dir : str
624 The location of the ipython_dir if different from the default.
625 This is used if the cluster directory is being found by profile.
626 auto_create : bool
627 Automatically create the cluster directory it is dones't exist.
628 This will usually only make sense if using a local cluster
629 (default=False).
630 auto_stop : bool
631 Automatically stop the cluster when this instance is garbage
632 collected (default=True). This is useful if you want the cluster
633 to live beyond your current process. There is also an instance
634 attribute ``auto_stop`` to change this behavior.
635 """
636 self.async_cluster = AsyncCluster(
637 profile, cluster_dir, ipython_dir, auto_create, auto_stop
638 )
639 self.cluster_dir_obj = self.async_cluster.cluster_dir_obj
640 self.client_connector = None
641
642 def _set_auto_stop(self, value):
643 self.async_cluster.auto_stop = value
644
645 def _get_auto_stop(self):
646 return self.async_cluster.auto_stop
647
648 auto_stop = property(_get_auto_stop, _set_auto_stop)
649
650 @property
651 def location(self):
652 return self.async_cluster.location
653
654 @property
655 def running(self):
656 return self.async_cluster.running
657
658 def start(self, n=2):
659 """Start the IPython cluster with n engines.
660
661 Parameters
662 ----------
663 n : int
664 The number of engine to start.
665 """
666 return blockingCallFromThread(self.async_cluster.start, n)
667
668 def stop(self):
669 """Stop the IPython cluster if it is running."""
670 return blockingCallFromThread(self.async_cluster.stop)
671
672 def get_multiengine_client(self, delay=DELAY, max_tries=MAX_TRIES):
673 """Get the multiengine client for the running cluster.
674
675 This will try to attempt to the controller multiple times. If this
676 fails altogether, try looking at the following:
677 * Make sure the controller is starting properly by looking at its
678 log files.
679 * Make sure the controller is writing its FURL file in the location
680 expected by the client.
681 * Make sure a firewall on the controller's host is not blocking the
682 client from connecting.
683
684 Parameters
685 ----------
686 delay : float
687 The initial delay between re-connection attempts. Susequent delays
688 get longer according to ``delay[i] = 1.5*delay[i-1]``.
689 max_tries : int
690 The max number of re-connection attempts.
691 """
692 if self.client_connector is None:
693 self.client_connector = ClientConnector()
694 return self.client_connector.get_multiengine_client(
695 cluster_dir=self.cluster_dir_obj.location,
696 delay=delay, max_tries=max_tries
697 )
698
699 def get_task_client(self, delay=DELAY, max_tries=MAX_TRIES):
700 """Get the task client for the running cluster.
701
702 This will try to attempt to the controller multiple times. If this
703 fails altogether, try looking at the following:
704 * Make sure the controller is starting properly by looking at its
705 log files.
706 * Make sure the controller is writing its FURL file in the location
707 expected by the client.
708 * Make sure a firewall on the controller's host is not blocking the
709 client from connecting.
710
711 Parameters
712 ----------
713 delay : float
714 The initial delay between re-connection attempts. Susequent delays
715 get longer according to ``delay[i] = 1.5*delay[i-1]``.
716 max_tries : int
717 The max number of re-connection attempts.
718 """
719 if self.client_connector is None:
720 self.client_connector = ClientConnector()
721 return self.client_connector.get_task_client(
722 cluster_dir=self.cluster_dir_obj.location,
723 delay=delay, max_tries=max_tries
724 )
725
726 def __repr__(self):
727 s = "<Cluster(running=%r, location=%s)" % (self.running, self.location)
728 return s
729
730 def get_logs_by_name(self, name='ipcluter'):
731 """Get a dict of logs by process name (ipcluster, ipengine, etc.)"""
732 return self.async_cluster.get_logs_by_name(name)
733
734 def get_ipengine_logs(self):
735 """Get a dict of logs for all engines in this cluster."""
736 return self.async_cluster.get_ipengine_logs()
737
738 def get_ipcontroller_logs(self):
739 """Get a dict of logs for the controller in this cluster."""
740 return self.async_cluster.get_ipcontroller_logs()
741
742 def get_ipcluster_logs(self):
743 """Get a dict of the ipcluster logs for this cluster."""
744 return self.async_cluster.get_ipcluster_logs()
745
746 def get_logs(self):
747 """Get a dict of all logs for this cluster."""
748 return self.async_cluster.get_logs()
749
750 def _print_logs(self, logs):
751 for k, v in logs.iteritems():
752 print "==================================="
753 print "Logfile: %s" % k
754 print "==================================="
755 print v
756 print
757
758 def print_ipengine_logs(self):
759 """Print the ipengine logs for this cluster to stdout."""
760 self._print_logs(self.get_ipengine_logs())
761
762 def print_ipcontroller_logs(self):
763 """Print the ipcontroller logs for this cluster to stdout."""
764 self._print_logs(self.get_ipcontroller_logs())
765
766 def print_ipcluster_logs(self):
767 """Print the ipcluster logs for this cluster to stdout."""
768 self._print_logs(self.get_ipcluster_logs())
769
770 def print_logs(self):
771 """Print all the logs for this cluster to stdout."""
772 self._print_logs(self.get_logs())
773
151774
=== added file 'IPython/kernel/clusterdir.py'
--- IPython/kernel/clusterdir.py 1970-01-01 00:00:00 +0000
+++ IPython/kernel/clusterdir.py 2009-11-21 00:11:11 +0000
@@ -0,0 +1,475 @@
1#!/usr/bin/env python
2# encoding: utf-8
3"""
4The IPython cluster directory
5"""
6
7#-----------------------------------------------------------------------------
8# Copyright (C) 2008-2009 The IPython Development Team
9#
10# Distributed under the terms of the BSD License. The full license is in
11# the file COPYING, distributed as part of this software.
12#-----------------------------------------------------------------------------
13
14#-----------------------------------------------------------------------------
15# Imports
16#-----------------------------------------------------------------------------
17
18from __future__ import with_statement
19
20import os
21import shutil
22import sys
23
24from twisted.python import log
25
26from IPython.core import release
27from IPython.config.loader import PyFileConfigLoader
28from IPython.core.application import Application
29from IPython.core.component import Component
30from IPython.config.loader import ArgParseConfigLoader, NoConfigDefault
31from IPython.utils.traitlets import Unicode, Bool
32from IPython.utils import genutils
33
34#-----------------------------------------------------------------------------
35# Imports
36#-----------------------------------------------------------------------------
37
38
39class ClusterDirError(Exception):
40 pass
41
42
43class PIDFileError(Exception):
44 pass
45
46
47class ClusterDir(Component):
48 """An object to manage the cluster directory and its resources.
49
50 The cluster directory is used by :command:`ipcontroller`,
51 :command:`ipcontroller` and :command:`ipcontroller` to manage the
52 configuration, logging and security of these applications.
53
54 This object knows how to find, create and manage these directories. This
55 should be used by any code that want's to handle cluster directories.
56 """
57
58 security_dir_name = Unicode('security')
59 log_dir_name = Unicode('log')
60 pid_dir_name = Unicode('pid')
61 security_dir = Unicode(u'')
62 log_dir = Unicode(u'')
63 pid_dir = Unicode(u'')
64 location = Unicode(u'')
65
66 def __init__(self, location):
67 super(ClusterDir, self).__init__(None)
68 self.location = location
69
70 def _location_changed(self, name, old, new):
71 if not os.path.isdir(new):
72 os.makedirs(new)
73 self.security_dir = os.path.join(new, self.security_dir_name)
74 self.log_dir = os.path.join(new, self.log_dir_name)
75 self.pid_dir = os.path.join(new, self.pid_dir_name)
76 self.check_dirs()
77
78 def _log_dir_changed(self, name, old, new):
79 self.check_log_dir()
80
81 def check_log_dir(self):
82 if not os.path.isdir(self.log_dir):
83 os.mkdir(self.log_dir)
84
85 def _security_dir_changed(self, name, old, new):
86 self.check_security_dir()
87
88 def check_security_dir(self):
89 if not os.path.isdir(self.security_dir):
90 os.mkdir(self.security_dir, 0700)
91 os.chmod(self.security_dir, 0700)
92
93 def _pid_dir_changed(self, name, old, new):
94 self.check_pid_dir()
95
96 def check_pid_dir(self):
97 if not os.path.isdir(self.pid_dir):
98 os.mkdir(self.pid_dir, 0700)
99 os.chmod(self.pid_dir, 0700)
100
101 def check_dirs(self):
102 self.check_security_dir()
103 self.check_log_dir()
104 self.check_pid_dir()
105
106 def load_config_file(self, filename):
107 """Load a config file from the top level of the cluster dir.
108
109 Parameters
110 ----------
111 filename : unicode or str
112 The filename only of the config file that must be located in
113 the top-level of the cluster directory.
114 """
115 loader = PyFileConfigLoader(filename, self.location)
116 return loader.load_config()
117
118 def copy_config_file(self, config_file, path=None, overwrite=False):
119 """Copy a default config file into the active cluster directory.
120
121 Default configuration files are kept in :mod:`IPython.config.default`.
122 This function moves these from that location to the working cluster
123 directory.
124 """
125 if path is None:
126 import IPython.config.default
127 path = IPython.config.default.__file__.split(os.path.sep)[:-1]
128 path = os.path.sep.join(path)
129 src = os.path.join(path, config_file)
130 dst = os.path.join(self.location, config_file)
131 if not os.path.isfile(dst) or overwrite:
132 shutil.copy(src, dst)
133
134 def copy_all_config_files(self, path=None, overwrite=False):
135 """Copy all config files into the active cluster directory."""
136 for f in [u'ipcontroller_config.py', u'ipengine_config.py',
137 u'ipcluster_config.py']:
138 self.copy_config_file(f, path=path, overwrite=overwrite)
139
140 @classmethod
141 def create_cluster_dir(csl, cluster_dir):
142 """Create a new cluster directory given a full path.
143
144 Parameters
145 ----------
146 cluster_dir : str
147 The full path to the cluster directory. If it does exist, it will
148 be used. If not, it will be created.
149 """
150 return ClusterDir(cluster_dir)
151
152 @classmethod
153 def create_cluster_dir_by_profile(cls, path, profile=u'default'):
154 """Create a cluster dir by profile name and path.
155
156 Parameters
157 ----------
158 path : str
159 The path (directory) to put the cluster directory in.
160 profile : str
161 The name of the profile. The name of the cluster directory will
162 be "cluster_<profile>".
163 """
164 if not os.path.isdir(path):
165 raise ClusterDirError('Directory not found: %s' % path)
166 cluster_dir = os.path.join(path, u'cluster_' + profile)
167 return ClusterDir(cluster_dir)
168
169 @classmethod
170 def find_cluster_dir_by_profile(cls, ipython_dir, profile=u'default'):
171 """Find an existing cluster dir by profile name, return its ClusterDir.
172
173 This searches through a sequence of paths for a cluster dir. If it
174 is not found, a :class:`ClusterDirError` exception will be raised.
175
176 The search path algorithm is:
177 1. ``os.getcwd()``
178 2. ``ipython_dir``
179 3. The directories found in the ":" separated
180 :env:`IPCLUSTER_DIR_PATH` environment variable.
181
182 Parameters
183 ----------
184 ipython_dir : unicode or str
185 The IPython directory to use.
186 profile : unicode or str
187 The name of the profile. The name of the cluster directory
188 will be "cluster_<profile>".
189 """
190 dirname = u'cluster_' + profile
191 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
192 if cluster_dir_paths:
193 cluster_dir_paths = cluster_dir_paths.split(':')
194 else:
195 cluster_dir_paths = []
196 paths = [os.getcwd(), ipython_dir] + cluster_dir_paths
197 for p in paths:
198 cluster_dir = os.path.join(p, dirname)
199 if os.path.isdir(cluster_dir):
200 return ClusterDir(cluster_dir)
201 else:
202 raise ClusterDirError('Cluster directory not found in paths: %s' % dirname)
203
204 @classmethod
205 def find_cluster_dir(cls, cluster_dir):
206 """Find/create a cluster dir and return its ClusterDir.
207
208 This will create the cluster directory if it doesn't exist.
209
210 Parameters
211 ----------
212 cluster_dir : unicode or str
213 The path of the cluster directory. This is expanded using
214 :func:`IPython.utils.genutils.expand_path`.
215 """
216 cluster_dir = genutils.expand_path(cluster_dir)
217 if not os.path.isdir(cluster_dir):
218 raise ClusterDirError('Cluster directory not found: %s' % cluster_dir)
219 return ClusterDir(cluster_dir)
220
221
222class AppWithClusterDirArgParseConfigLoader(ArgParseConfigLoader):
223 """Default command line options for IPython cluster applications."""
224
225 def _add_other_arguments(self):
226 self.parser.add_argument('--ipython-dir',
227 dest='Global.ipython_dir',type=unicode,
228 help='Set to override default location of Global.ipython_dir.',
229 default=NoConfigDefault,
230 metavar='Global.ipython_dir'
231 )
232 self.parser.add_argument('-p', '--profile',
233 dest='Global.profile',type=unicode,
234 help='The string name of the profile to be used. This determines '
235 'the name of the cluster dir as: cluster_<profile>. The default profile '
236 'is named "default". The cluster directory is resolve this way '
237 'if the --cluster-dir option is not used.',
238 default=NoConfigDefault,
239 metavar='Global.profile'
240 )
241 self.parser.add_argument('--log-level',
242 dest="Global.log_level",type=int,
243 help='Set the log level (0,10,20,30,40,50). Default is 30.',
244 default=NoConfigDefault,
245 metavar="Global.log_level"
246 )
247 self.parser.add_argument('--cluster-dir',
248 dest='Global.cluster_dir',type=unicode,
249 help='Set the cluster dir. This overrides the logic used by the '
250 '--profile option.',
251 default=NoConfigDefault,
252 metavar='Global.cluster_dir'
253 ),
254 self.parser.add_argument('--work-dir',
255 dest='Global.work_dir',type=unicode,
256 help='Set the working dir for the process.',
257 default=NoConfigDefault,
258 metavar='Global.work_dir'
259 )
260 self.parser.add_argument('--clean-logs',
261 dest='Global.clean_logs', action='store_true',
262 help='Delete old log flies before starting.',
263 default=NoConfigDefault
264 )
265 self.parser.add_argument('--no-clean-logs',
266 dest='Global.clean_logs', action='store_false',
267 help="Don't Delete old log flies before starting.",
268 default=NoConfigDefault
269 )
270
271class ApplicationWithClusterDir(Application):
272 """An application that puts everything into a cluster directory.
273
274 Instead of looking for things in the ipython_dir, this type of application
275 will use its own private directory called the "cluster directory"
276 for things like config files, log files, etc.
277
278 The cluster directory is resolved as follows:
279
280 * If the ``--cluster-dir`` option is given, it is used.
281 * If ``--cluster-dir`` is not given, the application directory is
282 resolve using the profile name as ``cluster_<profile>``. The search
283 path for this directory is then i) cwd if it is found there
284 and ii) in ipython_dir otherwise.
285
286 The config file for the application is to be put in the cluster
287 dir and named the value of the ``config_file_name`` class attribute.
288 """
289
290 auto_create_cluster_dir = True
291
292 def create_default_config(self):
293 super(ApplicationWithClusterDir, self).create_default_config()
294 self.default_config.Global.profile = u'default'
295 self.default_config.Global.cluster_dir = u''
296 self.default_config.Global.work_dir = os.getcwd()
297 self.default_config.Global.log_to_file = False
298 self.default_config.Global.clean_logs = False
299
300 def create_command_line_config(self):
301 """Create and return a command line config loader."""
302 return AppWithClusterDirArgParseConfigLoader(
303 description=self.description,
304 version=release.version
305 )
306
307 def find_resources(self):
308 """This resolves the cluster directory.
309
310 This tries to find the cluster directory and if successful, it will
311 have done:
312 * Sets ``self.cluster_dir_obj`` to the :class:`ClusterDir` object for
313 the application.
314 * Sets ``self.cluster_dir`` attribute of the application and config
315 objects.
316
317 The algorithm used for this is as follows:
318 1. Try ``Global.cluster_dir``.
319 2. Try using ``Global.profile``.
320 3. If both of these fail and ``self.auto_create_cluster_dir`` is
321 ``True``, then create the new cluster dir in the IPython directory.
322 4. If all fails, then raise :class:`ClusterDirError`.
323 """
324
325 try:
326 cluster_dir = self.command_line_config.Global.cluster_dir
327 except AttributeError:
328 cluster_dir = self.default_config.Global.cluster_dir
329 cluster_dir = genutils.expand_path(cluster_dir)
330 try:
331 self.cluster_dir_obj = ClusterDir.find_cluster_dir(cluster_dir)
332 except ClusterDirError:
333 pass
334 else:
335 self.log.info('Using existing cluster dir: %s' % \
336 self.cluster_dir_obj.location
337 )
338 self.finish_cluster_dir()
339 return
340
341 try:
342 self.profile = self.command_line_config.Global.profile
343 except AttributeError:
344 self.profile = self.default_config.Global.profile
345 try:
346 self.cluster_dir_obj = ClusterDir.find_cluster_dir_by_profile(
347 self.ipython_dir, self.profile)
348 except ClusterDirError:
349 pass
350 else:
351 self.log.info('Using existing cluster dir: %s' % \
352 self.cluster_dir_obj.location
353 )
354 self.finish_cluster_dir()
355 return
356
357 if self.auto_create_cluster_dir:
358 self.cluster_dir_obj = ClusterDir.create_cluster_dir_by_profile(
359 self.ipython_dir, self.profile
360 )
361 self.log.info('Creating new cluster dir: %s' % \
362 self.cluster_dir_obj.location
363 )
364 self.finish_cluster_dir()
365 else:
366 raise ClusterDirError('Could not find a valid cluster directory.')
367
368 def finish_cluster_dir(self):
369 # Set the cluster directory
370 self.cluster_dir = self.cluster_dir_obj.location
371
372 # These have to be set because they could be different from the one
373 # that we just computed. Because command line has the highest
374 # priority, this will always end up in the master_config.
375 self.default_config.Global.cluster_dir = self.cluster_dir
376 self.command_line_config.Global.cluster_dir = self.cluster_dir
377
378 # Set the search path to the cluster directory
379 self.config_file_paths = (self.cluster_dir,)
380
381 def find_config_file_name(self):
382 """Find the config file name for this application."""
383 # For this type of Application it should be set as a class attribute.
384 if not hasattr(self, 'config_file_name'):
385 self.log.critical("No config filename found")
386
387 def find_config_file_paths(self):
388 # Set the search path to the cluster directory
389 self.config_file_paths = (self.cluster_dir,)
390
391 def pre_construct(self):
392 # The log and security dirs were set earlier, but here we put them
393 # into the config and log them.
394 config = self.master_config
395 sdir = self.cluster_dir_obj.security_dir
396 self.security_dir = config.Global.security_dir = sdir
397 ldir = self.cluster_dir_obj.log_dir
398 self.log_dir = config.Global.log_dir = ldir
399 pdir = self.cluster_dir_obj.pid_dir
400 self.pid_dir = config.Global.pid_dir = pdir
401 self.log.info("Cluster directory set to: %s" % self.cluster_dir)
402 config.Global.work_dir = unicode(genutils.expand_path(config.Global.work_dir))
403 # Change to the working directory. We do this just before construct
404 # is called so all the components there have the right working dir.
405 self.to_work_dir()
406
407 def to_work_dir(self):
408 wd = self.master_config.Global.work_dir
409 if unicode(wd) != unicode(os.getcwd()):
410 os.chdir(wd)
411 self.log.info("Changing to working dir: %s" % wd)
412
413 def start_logging(self):
414 # Remove old log files
415 if self.master_config.Global.clean_logs:
416 log_dir = self.master_config.Global.log_dir
417 for f in os.listdir(log_dir):
418 if f.startswith(self.name + u'-') and f.endswith('.log'):
419 os.remove(os.path.join(log_dir, f))
420 # Start logging to the new log file
421 if self.master_config.Global.log_to_file:
422 log_filename = self.name + u'-' + str(os.getpid()) + u'.log'
423 logfile = os.path.join(self.log_dir, log_filename)
424 open_log_file = open(logfile, 'w')
425 else:
426 open_log_file = sys.stdout
427 log.startLogging(open_log_file)
428
429 def write_pid_file(self, overwrite=False):
430 """Create a .pid file in the pid_dir with my pid.
431
432 This must be called after pre_construct, which sets `self.pid_dir`.
433 This raises :exc:`PIDFileError` if the pid file exists already.
434 """
435 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
436 if os.path.isfile(pid_file):
437 pid = self.get_pid_from_file()
438 if not overwrite:
439 raise PIDFileError(
440 'The pid file [%s] already exists. \nThis could mean that this '
441 'server is already running with [pid=%s].' % (pid_file, pid)
442 )
443 with open(pid_file, 'w') as f:
444 self.log.info("Creating pid file: %s" % pid_file)
445 f.write(repr(os.getpid())+'\n')
446
447 def remove_pid_file(self):
448 """Remove the pid file.
449
450 This should be called at shutdown by registering a callback with
451 :func:`reactor.addSystemEventTrigger`. This needs to return
452 ``None``.
453 """
454 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
455 if os.path.isfile(pid_file):
456 try:
457 self.log.info("Removing pid file: %s" % pid_file)
458 os.remove(pid_file)
459 except:
460 self.log.warn("Error removing the pid file: %s" % pid_file)
461
462 def get_pid_from_file(self):
463 """Get the pid from the pid file.
464
465 If the pid file doesn't exist a :exc:`PIDFileError` is raised.
466 """
467 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
468 if os.path.isfile(pid_file):
469 with open(pid_file, 'r') as f:
470 pid = int(f.read().strip())
471 return pid
472 else:
473 raise PIDFileError('pid file not found: %s' % pid_file)
474
475
0476
=== removed directory 'IPython/kernel/config'
=== removed file 'IPython/kernel/config/__init__.py'
--- IPython/kernel/config/__init__.py 2009-07-02 02:49:32 +0000
+++ IPython/kernel/config/__init__.py 1970-01-01 00:00:00 +0000
@@ -1,126 +0,0 @@
1# encoding: utf-8
2
3"""Default kernel configuration."""
4
5__docformat__ = "restructuredtext en"
6
7#-------------------------------------------------------------------------------
8# Copyright (C) 2008 The IPython Development Team
9#
10# Distributed under the terms of the BSD License. The full license is in
11# the file COPYING, distributed as part of this software.
12#-------------------------------------------------------------------------------
13
14#-------------------------------------------------------------------------------
15# Imports
16#-------------------------------------------------------------------------------
17
18import os, sys
19from os.path import join as pjoin
20
21from IPython.external.configobj import ConfigObj
22from IPython.config.api import ConfigObjManager
23from IPython.utils.genutils import get_ipython_dir, get_security_dir
24
25default_kernel_config = ConfigObj()
26
27# This will raise OSError if ipythondir doesn't exist.
28security_dir = get_security_dir()
29
30#-------------------------------------------------------------------------------
31# Engine Configuration
32#-------------------------------------------------------------------------------
33
34engine_config = dict(
35 logfile = '', # Empty means log to stdout
36 furl_file = pjoin(security_dir, 'ipcontroller-engine.furl')
37)
38
39#-------------------------------------------------------------------------------
40# MPI Configuration
41#-------------------------------------------------------------------------------
42
43mpi_config = dict(
44 mpi4py = """from mpi4py import MPI as mpi
45mpi.size = mpi.COMM_WORLD.Get_size()
46mpi.rank = mpi.COMM_WORLD.Get_rank()
47""",
48 pytrilinos = """from PyTrilinos import Epetra
49class SimpleStruct:
50 pass
51mpi = SimpleStruct()
52mpi.rank = 0
53mpi.size = 0
54""",
55 default = ''
56)
57
58#-------------------------------------------------------------------------------
59# Controller Configuration
60#-------------------------------------------------------------------------------
61
62controller_config = dict(
63
64 logfile = '', # Empty means log to stdout
65 import_statement = '',
66 reuse_furls = False, # If False, old furl files are deleted
67
68 engine_tub = dict(
69 ip = '', # Empty string means all interfaces
70 port = 0, # 0 means pick a port for me
71 location = '', # Empty string means try to set automatically
72 secure = True,
73 cert_file = pjoin(security_dir, 'ipcontroller-engine.pem'),
74 ),
75 engine_fc_interface = 'IPython.kernel.enginefc.IFCControllerBase',
76 engine_furl_file = pjoin(security_dir, 'ipcontroller-engine.furl'),
77
78 controller_interfaces = dict(
79 # multiengine = dict(
80 # controller_interface = 'IPython.kernel.multiengine.IMultiEngine',
81 # fc_interface = 'IPython.kernel.multienginefc.IFCMultiEngine',
82 # furl_file = 'ipcontroller-mec.furl'
83 # ),
84 task = dict(
85 controller_interface = 'IPython.kernel.task.ITaskController',
86 fc_interface = 'IPython.kernel.taskfc.IFCTaskController',
87 furl_file = pjoin(security_dir, 'ipcontroller-tc.furl')
88 ),
89 multiengine = dict(
90 controller_interface = 'IPython.kernel.multiengine.IMultiEngine',
91 fc_interface = 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine',
92 furl_file = pjoin(security_dir, 'ipcontroller-mec.furl')
93 )
94 ),
95
96 client_tub = dict(
97 ip = '', # Empty string means all interfaces
98 port = 0, # 0 means pick a port for me
99 location = '', # Empty string means try to set automatically
100 secure = True,
101 cert_file = pjoin(security_dir, 'ipcontroller-client.pem')
102 )
103)
104
105#-------------------------------------------------------------------------------
106# Client Configuration
107#-------------------------------------------------------------------------------
108
109client_config = dict(
110 client_interfaces = dict(
111 task = dict(
112 furl_file = pjoin(security_dir, 'ipcontroller-tc.furl')
113 ),
114 multiengine = dict(
115 furl_file = pjoin(security_dir, 'ipcontroller-mec.furl')
116 )
117 )
118)
119
120default_kernel_config['engine'] = engine_config
121default_kernel_config['mpi'] = mpi_config
122default_kernel_config['controller'] = controller_config
123default_kernel_config['client'] = client_config
124
125
126config_manager = ConfigObjManager(default_kernel_config, 'IPython.kernel.ini')
127\ No newline at end of file0\ No newline at end of file
1281
=== added file 'IPython/kernel/configobjfactory.py'
--- IPython/kernel/configobjfactory.py 1970-01-01 00:00:00 +0000
+++ IPython/kernel/configobjfactory.py 2009-11-21 00:11:11 +0000
@@ -0,0 +1,79 @@
1#!/usr/bin/env python
2# encoding: utf-8
3"""
4A class for creating a Twisted service that is configured using IPython's
5configuration system.
6"""
7
8#-----------------------------------------------------------------------------
9# Copyright (C) 2008-2009 The IPython Development Team
10#
11# Distributed under the terms of the BSD License. The full license is in
12# the file COPYING, distributed as part of this software.
13#-----------------------------------------------------------------------------
14
15#-----------------------------------------------------------------------------
16# Imports
17#-----------------------------------------------------------------------------
18
19import zope.interface as zi
20
21from IPython.core.component import Component
22
23#-----------------------------------------------------------------------------
24# Code
25#-----------------------------------------------------------------------------
26
27
28class IConfiguredObjectFactory(zi.Interface):
29 """I am a component that creates a configured object.
30
31 This class is useful if you want to configure a class that is not a
32 subclass of :class:`IPython.core.component.Component`.
33 """
34
35 def __init__(config):
36 """Get ready to configure the object using config."""
37
38 def create():
39 """Return an instance of the configured object."""
40
41
42class ConfiguredObjectFactory(Component):
43
44 zi.implements(IConfiguredObjectFactory)
45
46 def __init__(self, config):
47 super(ConfiguredObjectFactory, self).__init__(None, config=config)
48
49 def create(self):
50 raise NotImplementedError('create must be implemented in a subclass')
51
52
53class IAdaptedConfiguredObjectFactory(zi.Interface):
54 """I am a component that adapts and configures an object.
55
56 This class is useful if you have the adapt an instance and configure it.
57 """
58
59 def __init__(config, adaptee=None):
60 """Get ready to adapt adaptee and then configure it using config."""
61
62 def create():
63 """Return an instance of the adapted and configured object."""
64
65
66class AdaptedConfiguredObjectFactory(Component):
67
68 # zi.implements(IAdaptedConfiguredObjectFactory)
69
70 def __init__(self, config, adaptee):
71 # print
72 # print "config pre:", config
73 super(AdaptedConfiguredObjectFactory, self).__init__(None, config=config)
74 # print
75 # print "config post:", config
76 self.adaptee = adaptee
77
78 def create(self):
79 raise NotImplementedError('create must be implemented in a subclass')
0\ No newline at end of file80\ No newline at end of file
181
=== removed directory 'IPython/kernel/core/config'
=== removed file 'IPython/kernel/core/config/__init__.py'
--- IPython/kernel/core/config/__init__.py 2008-06-06 19:41:55 +0000
+++ IPython/kernel/core/config/__init__.py 1970-01-01 00:00:00 +0000
@@ -1,25 +0,0 @@
1# encoding: utf-8
2
3__docformat__ = "restructuredtext en"
4
5#-------------------------------------------------------------------------------
6# Copyright (C) 2008 The IPython Development Team
7#
8# Distributed under the terms of the BSD License. The full license is in
9# the file COPYING, distributed as part of this software.
10#-------------------------------------------------------------------------------
11
12#-------------------------------------------------------------------------------
13# Imports
14#-------------------------------------------------------------------------------
15
16from IPython.external.configobj import ConfigObj
17from IPython.config.api import ConfigObjManager
18
19default_core_config = ConfigObj()
20default_core_config['shell'] = dict(
21 shell_class = 'IPython.kernel.core.interpreter.Interpreter',
22 import_statement = ''
23)
24
25config_manager = ConfigObjManager(default_core_config, 'IPython.kernel.core.ini')
26\ No newline at end of file0\ No newline at end of file
271
=== modified file 'IPython/kernel/engineconnector.py'
--- IPython/kernel/engineconnector.py 2009-04-18 21:53:37 +0000
+++ IPython/kernel/engineconnector.py 2009-11-21 00:11:11 +0000
@@ -1,32 +1,38 @@
1#!/usr/bin/env python
1# encoding: utf-82# encoding: utf-8
23
3"""A class that manages the engines connection to the controller."""4"""A class that manages the engines connection to the controller."""
45
5__docformat__ = "restructuredtext en"6#-----------------------------------------------------------------------------
67# Copyright (C) 2008-2009 The IPython Development Team
7#-------------------------------------------------------------------------------
8# Copyright (C) 2008 The IPython Development Team
9#8#
10# Distributed under the terms of the BSD License. The full license is in9# Distributed under the terms of the BSD License. The full license is in
11# the file COPYING, distributed as part of this software.10# the file COPYING, distributed as part of this software.
12#-------------------------------------------------------------------------------11#-----------------------------------------------------------------------------
1312
14#-------------------------------------------------------------------------------13#-----------------------------------------------------------------------------
15# Imports14# Imports
16#-------------------------------------------------------------------------------15#-----------------------------------------------------------------------------
1716
18import os17import os
19import cPickle as pickle18import cPickle as pickle
2019
21from twisted.python import log, failure20from twisted.python import log, failure
22from twisted.internet import defer21from twisted.internet import defer
22from twisted.internet.defer import inlineCallbacks, returnValue
2323
24from IPython.kernel.fcutil import find_furl24from IPython.kernel.fcutil import find_furl, validate_furl_or_file
25from IPython.kernel.enginefc import IFCEngine25from IPython.kernel.enginefc import IFCEngine
26from IPython.kernel.twistedutil import sleep_deferred, make_deferred
2627
27#-------------------------------------------------------------------------------28#-----------------------------------------------------------------------------
28# The ClientConnector class29# The ClientConnector class
29#-------------------------------------------------------------------------------30#-----------------------------------------------------------------------------
31
32
33class EngineConnectorError(Exception):
34 pass
35
3036
31class EngineConnector(object):37class EngineConnector(object):
32 """Manage an engines connection to a controller.38 """Manage an engines connection to a controller.
@@ -38,8 +44,10 @@
38 44
39 def __init__(self, tub):45 def __init__(self, tub):
40 self.tub = tub46 self.tub = tub
41 47
42 def connect_to_controller(self, engine_service, furl_or_file):48 @make_deferred
49 def connect_to_controller(self, engine_service, furl_or_file,
50 delay=0.1, max_tries=10):
43 """51 """
44 Make a connection to a controller specified by a furl.52 Make a connection to a controller specified by a furl.
45 53
@@ -48,34 +56,73 @@
48 foolscap URL contains all the information needed to connect to the 56 foolscap URL contains all the information needed to connect to the
49 controller, including the ip and port as well as any encryption and 57 controller, including the ip and port as well as any encryption and
50 authentication information needed for the connection.58 authentication information needed for the connection.
51 59
52 After getting a reference to the controller, this method calls the 60 After getting a reference to the controller, this method calls the
53 `register_engine` method of the controller to actually register the 61 `register_engine` method of the controller to actually register the
54 engine.62 engine.
55 63
56 :Parameters:64 This method will try to connect to the controller multiple times with
57 engine_service : IEngineBase65 a delay in between. Each time the FURL file is read anew.
58 An instance of an `IEngineBase` implementer66
59 furl_or_file : str67 Parameters
60 A furl or a filename containing a furl68 __________
69 engine_service : IEngineBase
70 An instance of an `IEngineBase` implementer
71 furl_or_file : str
72 A furl or a filename containing a furl
73 delay : float
74 The intial time to wait between connection attempts. Subsequent
75 attempts have increasing delays.
76 max_tries : int
77 The maximum number of connection attempts.
78
79 Returns
80 -------
81 A deferred to the registered client or a failure to an error
82 like :exc:`FURLError`.
61 """83 """
62 if not self.tub.running:84 if not self.tub.running:
63 self.tub.startService()85 self.tub.startService()
64 self.engine_service = engine_service86 self.engine_service = engine_service
65 self.engine_reference = IFCEngine(self.engine_service)87 self.engine_reference = IFCEngine(self.engine_service)
66 try:88
67 self.furl = find_furl(furl_or_file)89 validate_furl_or_file(furl_or_file)
68 except ValueError:90 d = self._try_to_connect(furl_or_file, delay, max_tries, attempt=0)
69 return defer.fail(failure.Failure())91 d.addCallback(self._register)
92 return d
93
94 @inlineCallbacks
95 def _try_to_connect(self, furl_or_file, delay, max_tries, attempt):
96 """Try to connect to the controller with retry logic."""
97 if attempt < max_tries:
98 log.msg("Attempting to connect to controller [%r]: %s" % \
99 (attempt, furl_or_file))
100 try:
101 self.furl = find_furl(furl_or_file)
102 # Uncomment this to see the FURL being tried.
103 # log.msg("FURL: %s" % self.furl)
104 rr = yield self.tub.getReference(self.furl)
105 except:
106 if attempt==max_tries-1:
107 # This will propagate the exception all the way to the top
108 # where it can be handled.
109 raise
110 else:
111 yield sleep_deferred(delay)
112 rr = yield self._try_to_connect(
113 furl_or_file, 1.5*delay, max_tries, attempt+1
114 )
115 # rr becomes an int when there is a connection!!!
116 returnValue(rr)
117 else:
118 returnValue(rr)
70 else:119 else:
71 d = self.tub.getReference(self.furl)120 raise EngineConnectorError(
72 d.addCallbacks(self._register, self._log_failure)121 'Could not connect to controller, max_tries (%r) exceeded. '
73 return d122 'This usually means that i) the controller was not started, '
74 123 'or ii) a firewall was blocking the engine from connecting '
75 def _log_failure(self, reason):124 'to the controller.' % max_tries
76 log.err('EngineConnector: engine registration failed:')125 )
77 log.err(reason)
78 return reason
79126
80 def _register(self, rr):127 def _register(self, rr):
81 self.remote_ref = rr128 self.remote_ref = rr
@@ -83,7 +130,7 @@
83 desired_id = self.engine_service.id130 desired_id = self.engine_service.id
84 d = self.remote_ref.callRemote('register_engine', self.engine_reference, 131 d = self.remote_ref.callRemote('register_engine', self.engine_reference,
85 desired_id, os.getpid(), pickle.dumps(self.engine_service.properties,2))132 desired_id, os.getpid(), pickle.dumps(self.engine_service.properties,2))
86 return d.addCallbacks(self._reference_sent, self._log_failure)133 return d.addCallback(self._reference_sent)
87134
88 def _reference_sent(self, registration_dict):135 def _reference_sent(self, registration_dict):
89 self.engine_service.id = registration_dict['id']136 self.engine_service.id = registration_dict['id']
90137
=== modified file 'IPython/kernel/error.py'
--- IPython/kernel/error.py 2009-08-04 01:18:28 +0000
+++ IPython/kernel/error.py 2009-11-21 00:11:11 +0000
@@ -127,9 +127,11 @@
127class CompositeError(KernelError):127class CompositeError(KernelError):
128 def __init__(self, message, elist):128 def __init__(self, message, elist):
129 Exception.__init__(self, *(message, elist))129 Exception.__init__(self, *(message, elist))
130 self.message = message130 # Don't use pack_exception because it will conflict with the .message
131 # attribute that is being deprecated in 2.6 and beyond.
132 self.msg = message
131 self.elist = elist133 self.elist = elist
132 134
133 def _get_engine_str(self, ev):135 def _get_engine_str(self, ev):
134 try:136 try:
135 ei = ev._ipython_engine_info137 ei = ev._ipython_engine_info
@@ -137,7 +139,7 @@
137 return '[Engine Exception]'139 return '[Engine Exception]'
138 else:140 else:
139 return '[%i:%s]: ' % (ei['engineid'], ei['method'])141 return '[%i:%s]: ' % (ei['engineid'], ei['method'])
140 142
141 def _get_traceback(self, ev):143 def _get_traceback(self, ev):
142 try:144 try:
143 tb = ev._ipython_traceback_text145 tb = ev._ipython_traceback_text
@@ -145,14 +147,14 @@
145 return 'No traceback available'147 return 'No traceback available'
146 else:148 else:
147 return tb149 return tb
148 150
149 def __str__(self):151 def __str__(self):
150 s = str(self.message)152 s = str(self.msg)
151 for et, ev, etb in self.elist:153 for et, ev, etb in self.elist:
152 engine_str = self._get_engine_str(ev)154 engine_str = self._get_engine_str(ev)
153 s = s + '\n' + engine_str + str(et.__name__) + ': ' + str(ev)155 s = s + '\n' + engine_str + str(et.__name__) + ': ' + str(ev)
154 return s156 return s
155 157
156 def print_tracebacks(self, excid=None):158 def print_tracebacks(self, excid=None):
157 if excid is None:159 if excid is None:
158 for (et,ev,etb) in self.elist:160 for (et,ev,etb) in self.elist:
159161
=== modified file 'IPython/kernel/fcutil.py'
--- IPython/kernel/fcutil.py 2008-06-06 19:41:55 +0000
+++ IPython/kernel/fcutil.py 2009-11-21 00:11:11 +0000
@@ -1,27 +1,62 @@
1#!/usr/bin/env python
1# encoding: utf-82# encoding: utf-8
23"""
3"""Foolscap related utilities."""4Foolscap related utilities.
45"""
5__docformat__ = "restructuredtext en"6
67#-----------------------------------------------------------------------------
7#-------------------------------------------------------------------------------8# Copyright (C) 2008-2009 The IPython Development Team
8# Copyright (C) 2008 The IPython Development Team
9#9#
10# Distributed under the terms of the BSD License. The full license is in10# Distributed under the terms of the BSD License. The full license is in
11# the file COPYING, distributed as part of this software.11# the file COPYING, distributed as part of this software.
12#-------------------------------------------------------------------------------12#-----------------------------------------------------------------------------
1313
14#-------------------------------------------------------------------------------14#-----------------------------------------------------------------------------
15# Imports15# Imports
16#-------------------------------------------------------------------------------16#-----------------------------------------------------------------------------
17
18from __future__ import with_statement
1719
18import os20import os
21import tempfile
22
23from twisted.internet import reactor, defer
24from twisted.python import log
1925
20from foolscap import Tub, UnauthenticatedTub26from foolscap import Tub, UnauthenticatedTub
2127
28from IPython.config.loader import Config
29
30from IPython.kernel.configobjfactory import AdaptedConfiguredObjectFactory
31
32from IPython.kernel.error import SecurityError
33
34from IPython.utils.traitlets import Int, Str, Bool, Instance
35from IPython.utils.importstring import import_item
36
37#-----------------------------------------------------------------------------
38# Code
39#-----------------------------------------------------------------------------
40
41
42# We do this so if a user doesn't have OpenSSL installed, it will try to use
43# an UnauthenticatedTub. But, they will still run into problems if they
44# try to use encrypted furls.
45try:
46 import OpenSSL
47except:
48 Tub = UnauthenticatedTub
49 have_crypto = False
50else:
51 have_crypto = True
52
53
54class FURLError(Exception):
55 pass
56
57
22def check_furl_file_security(furl_file, secure):58def check_furl_file_security(furl_file, secure):
23 """Remove the old furl_file if changing security modes."""59 """Remove the old furl_file if changing security modes."""
24
25 if os.path.isfile(furl_file):60 if os.path.isfile(furl_file):
26 f = open(furl_file, 'r')61 f = open(furl_file, 'r')
27 oldfurl = f.read().strip()62 oldfurl = f.read().strip()
@@ -29,41 +64,210 @@
29 if (oldfurl.startswith('pb://') and not secure) or (oldfurl.startswith('pbu://') and secure):64 if (oldfurl.startswith('pb://') and not secure) or (oldfurl.startswith('pbu://') and secure):
30 os.remove(furl_file)65 os.remove(furl_file)
3166
67
32def is_secure(furl):68def is_secure(furl):
69 """Is the given FURL secure or not."""
33 if is_valid(furl):70 if is_valid(furl):
34 if furl.startswith("pb://"):71 if furl.startswith("pb://"):
35 return True72 return True
36 elif furl.startswith("pbu://"):73 elif furl.startswith("pbu://"):
37 return False74 return False
38 else:75 else:
39 raise ValueError("invalid furl: %s" % furl)76 raise FURLError("invalid FURL: %s" % furl)
77
4078
41def is_valid(furl):79def is_valid(furl):
80 """Is the str a valid FURL or not."""
42 if isinstance(furl, str):81 if isinstance(furl, str):
43 if furl.startswith("pb://") or furl.startswith("pbu://"):82 if furl.startswith("pb://") or furl.startswith("pbu://"):
44 return True83 return True
45 else:84 else:
46 return False85 return False
4786
87
48def find_furl(furl_or_file):88def find_furl(furl_or_file):
89 """Find, validate and return a FURL in a string or file."""
49 if isinstance(furl_or_file, str):90 if isinstance(furl_or_file, str):
50 if is_valid(furl_or_file):91 if is_valid(furl_or_file):
51 return furl_or_file92 return furl_or_file
52 if os.path.isfile(furl_or_file):93 if os.path.isfile(furl_or_file):
53 furl = open(furl_or_file, 'r').read().strip()94 with open(furl_or_file, 'r') as f:
95 furl = f.read().strip()
54 if is_valid(furl):96 if is_valid(furl):
55 return furl97 return furl
56 raise ValueError("not a furl or a file containing a furl: %s" % furl_or_file)
57
58# We do this so if a user doesn't have OpenSSL installed, it will try to use
59# an UnauthenticatedTub. But, they will still run into problems if they
60# try to use encrypted furls.
61try:
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches