##// END OF EJS Templates
Beginning to transition all paths, files, dirs over to unicode....
Brian Granger -
Show More
@@ -1,194 +1,194 b''
1 import os
1 import os
2
2
3 c = get_config()
3 c = get_config()
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Select which launchers to use
6 # Select which launchers to use
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8
8
9 # This allows you to control what method is used to start the controller
9 # This allows you to control what method is used to start the controller
10 # and engines. The following methods are currently supported:
10 # and engines. The following methods are currently supported:
11 # * Start as a regular process on localhost.
11 # * Start as a regular process on localhost.
12 # * Start using mpiexec.
12 # * Start using mpiexec.
13 # * Start using PBS
13 # * Start using PBS
14 # * Start using SSH (currently broken)
14 # * Start using SSH (currently broken)
15
15
16 # The selected launchers can be configured below.
16 # The selected launchers can be configured below.
17
17
18 # Options are (LocalControllerLauncher, MPIExecControllerLauncher,
18 # Options are (LocalControllerLauncher, MPIExecControllerLauncher,
19 # PBSControllerLauncher, WindowsHPCControllerLauncher)
19 # PBSControllerLauncher, WindowsHPCControllerLauncher)
20 # c.Global.controller_launcher = 'IPython.kernel.launcher.LocalControllerLauncher'
20 # c.Global.controller_launcher = 'IPython.kernel.launcher.LocalControllerLauncher'
21
21
22 # Options are (LocalEngineSetLauncher, MPIExecEngineSetLauncher,
22 # Options are (LocalEngineSetLauncher, MPIExecEngineSetLauncher,
23 # PBSEngineSetLauncher)
23 # PBSEngineSetLauncher)
24 # c.Global.engine_launcher = 'IPython.kernel.launcher.LocalEngineSetLauncher'
24 # c.Global.engine_launcher = 'IPython.kernel.launcher.LocalEngineSetLauncher'
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Global configuration
27 # Global configuration
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 # The default number of engine that will be started. This is overridden by
30 # The default number of engine that will be started. This is overridden by
31 # the -n command line option: "ipcluster start -n 4"
31 # the -n command line option: "ipcluster start -n 4"
32 # c.Global.n = 2
32 # c.Global.n = 2
33
33
34 # Log to a file in cluster_dir/log, otherwise just log to sys.stdout.
34 # Log to a file in cluster_dir/log, otherwise just log to sys.stdout.
35 # c.Global.log_to_file = False
35 # c.Global.log_to_file = False
36
36
37 # Remove old logs from cluster_dir/log before starting.
37 # Remove old logs from cluster_dir/log before starting.
38 # c.Global.clean_logs = True
38 # c.Global.clean_logs = True
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Controller launcher configuration
41 # Controller launcher configuration
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44 # Configure how the controller is started. The configuration of the controller
44 # Configure how the controller is started. The configuration of the controller
45 # can also bet setup by editing the controller config file:
45 # can also bet setup by editing the controller config file:
46 # ipcontroller_config.py
46 # ipcontroller_config.py
47
47
48 # The command line arguments to call the controller with.
48 # The command line arguments to call the controller with.
49 # c.LocalControllerLauncher.controller_args = \
49 # c.LocalControllerLauncher.controller_args = \
50 # ['--log-to-file','--log-level', '40']
50 # ['--log-to-file','--log-level', '40']
51
51
52 # The mpiexec/mpirun command to use in started the controller.
52 # The mpiexec/mpirun command to use in started the controller.
53 # c.MPIExecControllerLauncher.mpi_cmd = ['mpiexec']
53 # c.MPIExecControllerLauncher.mpi_cmd = ['mpiexec']
54
54
55 # Additional arguments to pass to the actual mpiexec command.
55 # Additional arguments to pass to the actual mpiexec command.
56 # c.MPIExecControllerLauncher.mpi_args = []
56 # c.MPIExecControllerLauncher.mpi_args = []
57
57
58 # The command line argument to call the controller with.
58 # The command line argument to call the controller with.
59 # c.MPIExecControllerLauncher.controller_args = \
59 # c.MPIExecControllerLauncher.controller_args = \
60 # ['--log-to-file','--log-level', '40']
60 # ['--log-to-file','--log-level', '40']
61
61
62 # The command line program to use to submit a PBS job.
62 # The command line program to use to submit a PBS job.
63 # c.PBSControllerLauncher.submit_command = 'qsub'
63 # c.PBSControllerLauncher.submit_command = 'qsub'
64
64
65 # The command line program to use to delete a PBS job.
65 # The command line program to use to delete a PBS job.
66 # c.PBSControllerLauncher.delete_command = 'qdel'
66 # c.PBSControllerLauncher.delete_command = 'qdel'
67
67
68 # A regular expression that takes the output of qsub and find the job id.
68 # A regular expression that takes the output of qsub and find the job id.
69 # c.PBSControllerLauncher.job_id_regexp = '\d+'
69 # c.PBSControllerLauncher.job_id_regexp = '\d+'
70
70
71 # The batch submission script used to start the controller. This is where
71 # The batch submission script used to start the controller. This is where
72 # environment variables would be setup, etc. This string is interpolated using
72 # environment variables would be setup, etc. This string is interpolated using
73 # the Itpl module in IPython.external. Basically, you can use ${profile} for
73 # the Itpl module in IPython.external. Basically, you can use ${profile} for
74 # the controller profile or ${cluster_dir} for the cluster_dir.
74 # the controller profile or ${cluster_dir} for the cluster_dir.
75 # c.PBSControllerLauncher.batch_template = """"""
75 # c.PBSControllerLauncher.batch_template = """"""
76
76
77 # The name of the instantiated batch script that will actually be used to
77 # The name of the instantiated batch script that will actually be used to
78 # submit the job. This will be written to the cluster directory.
78 # submit the job. This will be written to the cluster directory.
79 # c.PBSControllerLauncher.batch_file_name = u'pbs_batch_script_controller'
79 # c.PBSControllerLauncher.batch_file_name = u'pbs_batch_script_controller'
80
80
81 #-----------------------------------------------------------------------------
81 #-----------------------------------------------------------------------------
82 # Windows HPC Server 2008 launcher configuration
82 # Windows HPC Server 2008 launcher configuration
83 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
84
84
85 # c.WinHPCJob.username = 'DOMAIN\\user'
85 # c.WinHPCJob.username = 'DOMAIN\\user'
86 # c.WinHPCJob.priority = 'Highest'
86 # c.WinHPCJob.priority = 'Highest'
87 # c.WinHPCJob.requested_nodes = ''
87 # c.WinHPCJob.requested_nodes = ''
88 # c.WinHPCJob.project = ''
88 # c.WinHPCJob.project = ''
89 # c.WinHPCJob.is_exclusive = False
89 # c.WinHPCJob.is_exclusive = False
90
90
91 # c.WinHPCTask.environment_variables = {}
91 # c.WinHPCTask.environment_variables = {}
92 # c.WinHPCTask.work_directory = ''
92 # c.WinHPCTask.work_directory = ''
93 # c.WinHPCTask.is_rerunnable = True
93 # c.WinHPCTask.is_rerunnable = True
94
94
95 # c.IPControllerTask.task_name = 'IPController'
95 # c.IPControllerTask.task_name = 'IPController'
96 # c.IPControllerTask.controller_cmd = ['ipcontroller.exe']
96 # c.IPControllerTask.controller_cmd = [u'ipcontroller.exe']
97 # c.IPControllerTask.controller_args = ['--log-to-file', '--log-level', '40']
97 # c.IPControllerTask.controller_args = ['--log-to-file', '--log-level', '40']
98 # c.IPControllerTask.environment_variables = {}
98 # c.IPControllerTask.environment_variables = {}
99
99
100 # c.IPEngineTask.task_name = 'IPController'
100 # c.IPEngineTask.task_name = 'IPController'
101 # c.IPEngineTask.engine_cmd = ['ipengine.exe']
101 # c.IPEngineTask.engine_cmd = [u'ipengine.exe']
102 # c.IPEngineTask.engine_args = ['--log-to-file', '--log-level', '40']
102 # c.IPEngineTask.engine_args = ['--log-to-file', '--log-level', '40']
103 # c.IPEngineTask.environment_variables = {}
103 # c.IPEngineTask.environment_variables = {}
104
104
105 # c.WindowsHPCLauncher.scheduler = 'HEADNODE'
105 # c.WindowsHPCLauncher.scheduler = 'HEADNODE'
106 # c.WindowsHPCLauncher.username = '\\DOMAIN\USERNAME'
106 # c.WindowsHPCLauncher.username = '\\DOMAIN\USERNAME'
107 # c.WindowsHPCLauncher.priority = 'Highest'
107 # c.WindowsHPCLauncher.priority = 'Highest'
108 # c.WindowsHPCLauncher.requested_nodes = ''
108 # c.WindowsHPCLauncher.requested_nodes = ''
109 # c.WindowsHPCLauncher.job_file_name = u'ipython_job.xml'
109 # c.WindowsHPCLauncher.job_file_name = u'ipython_job.xml'
110 # c.WindowsHPCLauncher.project = 'MyProject'
110 # c.WindowsHPCLauncher.project = 'MyProject'
111
111
112 # c.WindowsHPCControllerLauncher.scheduler = 'HEADNODE'
112 # c.WindowsHPCControllerLauncher.scheduler = 'HEADNODE'
113 # c.WindowsHPCControllerLauncher.username = '\\DOMAIN\USERNAME'
113 # c.WindowsHPCControllerLauncher.username = '\\DOMAIN\USERNAME'
114 # c.WindowsHPCControllerLauncher.priority = 'Highest'
114 # c.WindowsHPCControllerLauncher.priority = 'Highest'
115 # c.WindowsHPCControllerLauncher.requested_nodes = ''
115 # c.WindowsHPCControllerLauncher.requested_nodes = ''
116 # c.WindowsHPCControllerLauncher.job_file_name = u'ipcontroller_job.xml'
116 # c.WindowsHPCControllerLauncher.job_file_name = u'ipcontroller_job.xml'
117 # c.WindowsHPCControllerLauncher.project = 'MyProject'
117 # c.WindowsHPCControllerLauncher.project = 'MyProject'
118
118
119
119
120 #-----------------------------------------------------------------------------
120 #-----------------------------------------------------------------------------
121 # Engine launcher configuration
121 # Engine launcher configuration
122 #-----------------------------------------------------------------------------
122 #-----------------------------------------------------------------------------
123
123
124 # Command line argument passed to the engines.
124 # Command line argument passed to the engines.
125 # c.LocalEngineSetLauncher.engine_args = ['--log-to-file','--log-level', '40']
125 # c.LocalEngineSetLauncher.engine_args = ['--log-to-file','--log-level', '40']
126
126
127 # The mpiexec/mpirun command to use in started the controller.
127 # The mpiexec/mpirun command to use in started the controller.
128 # c.MPIExecEngineSetLauncher.mpi_cmd = ['mpiexec']
128 # c.MPIExecEngineSetLauncher.mpi_cmd = ['mpiexec']
129
129
130 # Additional arguments to pass to the actual mpiexec command.
130 # Additional arguments to pass to the actual mpiexec command.
131 # c.MPIExecEngineSetLauncher.mpi_args = []
131 # c.MPIExecEngineSetLauncher.mpi_args = []
132
132
133 # Command line argument passed to the engines.
133 # Command line argument passed to the engines.
134 # c.MPIExecEngineSetLauncher.engine_args = ['--log-to-file','--log-level', '40']
134 # c.MPIExecEngineSetLauncher.engine_args = ['--log-to-file','--log-level', '40']
135
135
136 # The default number of engines to start if not given elsewhere.
136 # The default number of engines to start if not given elsewhere.
137 # c.MPIExecEngineSetLauncher.n = 1
137 # c.MPIExecEngineSetLauncher.n = 1
138
138
139 # The command line program to use to submit a PBS job.
139 # The command line program to use to submit a PBS job.
140 # c.PBSEngineSetLauncher.submit_command = 'qsub'
140 # c.PBSEngineSetLauncher.submit_command = 'qsub'
141
141
142 # The command line program to use to delete a PBS job.
142 # The command line program to use to delete a PBS job.
143 # c.PBSEngineSetLauncher.delete_command = 'qdel'
143 # c.PBSEngineSetLauncher.delete_command = 'qdel'
144
144
145 # A regular expression that takes the output of qsub and find the job id.
145 # A regular expression that takes the output of qsub and find the job id.
146 # c.PBSEngineSetLauncher.job_id_regexp = '\d+'
146 # c.PBSEngineSetLauncher.job_id_regexp = '\d+'
147
147
148 # The batch submission script used to start the engines. This is where
148 # The batch submission script used to start the engines. This is where
149 # environment variables would be setup, etc. This string is interpolated using
149 # environment variables would be setup, etc. This string is interpolated using
150 # the Itpl module in IPython.external. Basically, you can use ${n} for the
150 # the Itpl module in IPython.external. Basically, you can use ${n} for the
151 # number of engine, ${profile} or the engine profile and ${cluster_dir}
151 # number of engine, ${profile} or the engine profile and ${cluster_dir}
152 # for the cluster_dir.
152 # for the cluster_dir.
153 # c.PBSEngineSetLauncher.batch_template = """"""
153 # c.PBSEngineSetLauncher.batch_template = """"""
154
154
155 # The name of the instantiated batch script that will actually be used to
155 # The name of the instantiated batch script that will actually be used to
156 # submit the job. This will be written to the cluster directory.
156 # submit the job. This will be written to the cluster directory.
157 # c.PBSEngineSetLauncher.batch_file_name = u'pbs_batch_script_engines'
157 # c.PBSEngineSetLauncher.batch_file_name = u'pbs_batch_script_engines'
158
158
159 #-----------------------------------------------------------------------------
159 #-----------------------------------------------------------------------------
160 # Base launcher configuration
160 # Base launcher configuration
161 #-----------------------------------------------------------------------------
161 #-----------------------------------------------------------------------------
162
162
163 # The various launchers are organized into an inheritance hierarchy.
163 # The various launchers are organized into an inheritance hierarchy.
164 # The configurations can also be iherited and the following attributes
164 # The configurations can also be iherited and the following attributes
165 # allow you to configure the base classes.
165 # allow you to configure the base classes.
166
166
167 # c.MPIExecLauncher.mpi_cmd = ['mpiexec']
167 # c.MPIExecLauncher.mpi_cmd = ['mpiexec']
168 # c.MPIExecLauncher.mpi_args = []
168 # c.MPIExecLauncher.mpi_args = []
169 # c.MPIExecLauncher.program = []
169 # c.MPIExecLauncher.program = []
170 # c.MPIExecLauncher.program_args = []
170 # c.MPIExecLauncher.program_args = []
171 # c.MPIExecLauncher.n = 1
171 # c.MPIExecLauncher.n = 1
172
172
173 # c.SSHLauncher.ssh_cmd = ['ssh']
173 # c.SSHLauncher.ssh_cmd = ['ssh']
174 # c.SSHLauncher.ssh_args = []
174 # c.SSHLauncher.ssh_args = []
175 # c.SSHLauncher.program = []
175 # c.SSHLauncher.program = []
176 # s.SSHLauncher.program_args = []
176 # s.SSHLauncher.program_args = []
177 # c.SSHLauncher.hostname = ''
177 # c.SSHLauncher.hostname = ''
178 # c.SSHLauncher.user = os.environ['USER']
178 # c.SSHLauncher.user = os.environ['USER']
179
179
180 # c.BatchSystemLauncher.submit_command
180 # c.BatchSystemLauncher.submit_command
181 # c.BatchSystemLauncher.delete_command
181 # c.BatchSystemLauncher.delete_command
182 # c.BatchSystemLauncher.job_id_regexp
182 # c.BatchSystemLauncher.job_id_regexp
183 # c.BatchSystemLauncher.batch_template
183 # c.BatchSystemLauncher.batch_template
184 # c.BatchSystemLauncher.batch_file_name
184 # c.BatchSystemLauncher.batch_file_name
185
185
186 # c.PBSLauncher.submit_command = 'qsub'
186 # c.PBSLauncher.submit_command = 'qsub'
187 # c.PBSLauncher.delete_command = 'qdel'
187 # c.PBSLauncher.delete_command = 'qdel'
188 # c.PBSLauncher.job_id_regexp = '\d+'
188 # c.PBSLauncher.job_id_regexp = '\d+'
189 # c.PBSLauncher.batch_template = """"""
189 # c.PBSLauncher.batch_template = """"""
190 # c.PBSLauncher.batch_file_name = u'pbs_batch_script'
190 # c.PBSLauncher.batch_file_name = u'pbs_batch_script'
191
191
192
192
193
193
194
194
@@ -1,132 +1,132 b''
1 from IPython.config.loader import Config
1 from IPython.config.loader import Config
2
2
3 c = get_config()
3 c = get_config()
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Global configuration
6 # Global configuration
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8
8
9 # Basic Global config attributes
9 # Basic Global config attributes
10
10
11 # Start up messages are logged to stdout using the logging module.
11 # Start up messages are logged to stdout using the logging module.
12 # These all happen before the twisted reactor is started and are
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)
13 # useful for debugging purposes. Can be (10=DEBUG,20=INFO,30=WARN,40=CRITICAL)
14 # and smaller is more verbose.
14 # and smaller is more verbose.
15 # c.Global.log_level = 20
15 # c.Global.log_level = 20
16
16
17 # Log to a file in cluster_dir/log, otherwise just log to sys.stdout.
17 # Log to a file in cluster_dir/log, otherwise just log to sys.stdout.
18 # c.Global.log_to_file = False
18 # c.Global.log_to_file = False
19
19
20 # Remove old logs from cluster_dir/log before starting.
20 # Remove old logs from cluster_dir/log before starting.
21 # c.Global.clean_logs = True
21 # c.Global.clean_logs = True
22
22
23 # A list of Python statements that will be run before starting the
23 # A list of Python statements that will be run before starting the
24 # controller. This is provided because occasionally certain things need to
24 # controller. This is provided because occasionally certain things need to
25 # be imported in the controller for pickling to work.
25 # be imported in the controller for pickling to work.
26 # c.Global.import_statements = ['import math']
26 # c.Global.import_statements = ['import math']
27
27
28 # Reuse the controller's FURL files. If False, FURL files are regenerated
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
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
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.
31 # values set for the client and engine connections below.
32 # c.Global.reuse_furls = True
32 # c.Global.reuse_furls = True
33
33
34 # Enable SSL encryption on all connections to the controller. If set, this
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.
35 # will override the values set for the client and engine connections below.
36 # c.Global.secure = True
36 # c.Global.secure = True
37
37
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39 # Configure the client services
39 # Configure the client services
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41
41
42 # Basic client service config attributes
42 # Basic client service config attributes
43
43
44 # The network interface the controller will listen on for client connections.
44 # The network interface the controller will listen on for client connections.
45 # This should be an IP address or hostname of the controller's host. The empty
45 # This should be an IP address or hostname of the controller's host. The empty
46 # string means listen on all interfaces.
46 # string means listen on all interfaces.
47 # c.FCClientServiceFactory.ip = ''
47 # c.FCClientServiceFactory.ip = ''
48
48
49 # The TCP/IP port the controller will listen on for client connections. If 0
49 # The TCP/IP port the controller will listen on for client connections. If 0
50 # a random port will be used. If the controller's host has a firewall running
50 # a random port will be used. If the controller's host has a firewall running
51 # it must allow incoming traffic on this port.
51 # it must allow incoming traffic on this port.
52 # c.FCClientServiceFactory.port = 0
52 # c.FCClientServiceFactory.port = 0
53
53
54 # The client learns how to connect to the controller by looking at the
54 # The client learns how to connect to the controller by looking at the
55 # location field embedded in the FURL. If this field is empty, all network
55 # location field embedded in the FURL. If this field is empty, all network
56 # interfaces that the controller is listening on will be listed. To have the
56 # interfaces that the controller is listening on will be listed. To have the
57 # client connect on a particular interface, list it here.
57 # client connect on a particular interface, list it here.
58 # c.FCClientServiceFactory.location = ''
58 # c.FCClientServiceFactory.location = ''
59
59
60 # Use SSL encryption for the client connection.
60 # Use SSL encryption for the client connection.
61 # c.FCClientServiceFactory.secure = True
61 # c.FCClientServiceFactory.secure = True
62
62
63 # Reuse the client FURL each time the controller is started. If set, you must
63 # Reuse the client FURL each time the controller is started. If set, you must
64 # also pick a specific network port above (FCClientServiceFactory.port).
64 # also pick a specific network port above (FCClientServiceFactory.port).
65 # c.FCClientServiceFactory.reuse_furls = False
65 # c.FCClientServiceFactory.reuse_furls = False
66
66
67 #-----------------------------------------------------------------------------
67 #-----------------------------------------------------------------------------
68 # Configure the engine services
68 # Configure the engine services
69 #-----------------------------------------------------------------------------
69 #-----------------------------------------------------------------------------
70
70
71 # Basic config attributes for the engine services.
71 # Basic config attributes for the engine services.
72
72
73 # The network interface the controller will listen on for engine connections.
73 # The network interface the controller will listen on for engine connections.
74 # This should be an IP address or hostname of the controller's host. The empty
74 # This should be an IP address or hostname of the controller's host. The empty
75 # string means listen on all interfaces.
75 # string means listen on all interfaces.
76 # c.FCEngineServiceFactory.ip = ''
76 # c.FCEngineServiceFactory.ip = ''
77
77
78 # The TCP/IP port the controller will listen on for engine connections. If 0
78 # The TCP/IP port the controller will listen on for engine connections. If 0
79 # a random port will be used. If the controller's host has a firewall running
79 # a random port will be used. If the controller's host has a firewall running
80 # it must allow incoming traffic on this port.
80 # it must allow incoming traffic on this port.
81 # c.FCEngineServiceFactory.port = 0
81 # c.FCEngineServiceFactory.port = 0
82
82
83 # The engine learns how to connect to the controller by looking at the
83 # The engine learns how to connect to the controller by looking at the
84 # location field embedded in the FURL. If this field is empty, all network
84 # location field embedded in the FURL. If this field is empty, all network
85 # interfaces that the controller is listening on will be listed. To have the
85 # interfaces that the controller is listening on will be listed. To have the
86 # client connect on a particular interface, list it here.
86 # client connect on a particular interface, list it here.
87 # c.FCEngineServiceFactory.location = ''
87 # c.FCEngineServiceFactory.location = ''
88
88
89 # Use SSL encryption for the engine connection.
89 # Use SSL encryption for the engine connection.
90 # c.FCEngineServiceFactory.secure = True
90 # c.FCEngineServiceFactory.secure = True
91
91
92 # Reuse the client FURL each time the controller is started. If set, you must
92 # Reuse the client FURL each time the controller is started. If set, you must
93 # also pick a specific network port above (FCClientServiceFactory.port).
93 # also pick a specific network port above (FCClientServiceFactory.port).
94 # c.FCEngineServiceFactory.reuse_furls = False
94 # c.FCEngineServiceFactory.reuse_furls = False
95
95
96 #-----------------------------------------------------------------------------
96 #-----------------------------------------------------------------------------
97 # Developer level configuration attributes
97 # Developer level configuration attributes
98 #-----------------------------------------------------------------------------
98 #-----------------------------------------------------------------------------
99
99
100 # You shouldn't have to modify anything in this section. These attributes
100 # You shouldn't have to modify anything in this section. These attributes
101 # are more for developers who want to change the behavior of the controller
101 # are more for developers who want to change the behavior of the controller
102 # at a fundamental level.
102 # at a fundamental level.
103
103
104 # c.FCClientServiceFactory.cert_file = 'ipcontroller-client.pem'
104 # c.FCClientServiceFactory.cert_file = u'ipcontroller-client.pem'
105
105
106 # default_client_interfaces = Config()
106 # default_client_interfaces = Config()
107 # default_client_interfaces.Task.interface_chain = [
107 # default_client_interfaces.Task.interface_chain = [
108 # 'IPython.kernel.task.ITaskController',
108 # 'IPython.kernel.task.ITaskController',
109 # 'IPython.kernel.taskfc.IFCTaskController'
109 # 'IPython.kernel.taskfc.IFCTaskController'
110 # ]
110 # ]
111 #
111 #
112 # default_client_interfaces.Task.furl_file = 'ipcontroller-tc.furl'
112 # default_client_interfaces.Task.furl_file = u'ipcontroller-tc.furl'
113 #
113 #
114 # default_client_interfaces.MultiEngine.interface_chain = [
114 # default_client_interfaces.MultiEngine.interface_chain = [
115 # 'IPython.kernel.multiengine.IMultiEngine',
115 # 'IPython.kernel.multiengine.IMultiEngine',
116 # 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine'
116 # 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine'
117 # ]
117 # ]
118 #
118 #
119 # default_client_interfaces.MultiEngine.furl_file = 'ipcontroller-mec.furl'
119 # default_client_interfaces.MultiEngine.furl_file = u'ipcontroller-mec.furl'
120 #
120 #
121 # c.FCEngineServiceFactory.interfaces = default_client_interfaces
121 # c.FCEngineServiceFactory.interfaces = default_client_interfaces
122
122
123 # c.FCEngineServiceFactory.cert_file = 'ipcontroller-engine.pem'
123 # c.FCEngineServiceFactory.cert_file = u'ipcontroller-engine.pem'
124
124
125 # default_engine_interfaces = Config()
125 # default_engine_interfaces = Config()
126 # default_engine_interfaces.Default.interface_chain = [
126 # default_engine_interfaces.Default.interface_chain = [
127 # 'IPython.kernel.enginefc.IFCControllerBase'
127 # 'IPython.kernel.enginefc.IFCControllerBase'
128 # ]
128 # ]
129 #
129 #
130 # default_engine_interfaces.Default.furl_file = 'ipcontroller-engine.furl'
130 # default_engine_interfaces.Default.furl_file = u'ipcontroller-engine.furl'
131 #
131 #
132 # c.FCEngineServiceFactory.interfaces = default_engine_interfaces
132 # c.FCEngineServiceFactory.interfaces = default_engine_interfaces
@@ -1,86 +1,86 b''
1 c = get_config()
1 c = get_config()
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Global configuration
4 # Global configuration
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6
6
7 # Start up messages are logged to stdout using the logging module.
7 # Start up messages are logged to stdout using the logging module.
8 # These all happen before the twisted reactor is started and are
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)
9 # useful for debugging purposes. Can be (10=DEBUG,20=INFO,30=WARN,40=CRITICAL)
10 # and smaller is more verbose.
10 # and smaller is more verbose.
11 # c.Global.log_level = 20
11 # c.Global.log_level = 20
12
12
13 # Log to a file in cluster_dir/log, otherwise just log to sys.stdout.
13 # Log to a file in cluster_dir/log, otherwise just log to sys.stdout.
14 # c.Global.log_to_file = False
14 # c.Global.log_to_file = False
15
15
16 # Remove old logs from cluster_dir/log before starting.
16 # Remove old logs from cluster_dir/log before starting.
17 # c.Global.clean_logs = True
17 # c.Global.clean_logs = True
18
18
19 # A list of strings that will be executed in the users namespace on the engine
19 # A list of strings that will be executed in the users namespace on the engine
20 # before it connects to the controller.
20 # before it connects to the controller.
21 # c.Global.exec_lines = ['import numpy']
21 # c.Global.exec_lines = ['import numpy']
22
22
23 # The engine will try to connect to the controller multiple times, to allow
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
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
25 # control the number of retries (connect_max_tries) and the initial delay
26 # (connect_delay) between attemps. The actual delay between attempts gets
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])
27 # longer each time by a factor of 1.5 (delay[i] = 1.5*delay[i-1])
28 # those attemps.
28 # those attemps.
29 # c.Global.connect_delay = 0.1
29 # c.Global.connect_delay = 0.1
30 # c.Global.connect_max_tries = 15
30 # c.Global.connect_max_tries = 15
31
31
32 # By default, the engine will look for the controller's FURL file in its own
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
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.
34 # attribute can be set to the full path of the FURL file.
35 # c.Global.furl_file = ''
35 # c.Global.furl_file = u''
36
36
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38 # MPI configuration
38 # MPI configuration
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40
40
41 # Upon starting the engine can be configured to call MPI_Init. This section
41 # Upon starting the engine can be configured to call MPI_Init. This section
42 # configures that.
42 # configures that.
43
43
44 # Select which MPI section to execute to setup MPI. The value of this
44 # Select which MPI section to execute to setup MPI. The value of this
45 # attribute must match the name of another attribute in the MPI config
45 # attribute must match the name of another attribute in the MPI config
46 # section (mpi4py, pytrilinos, etc.). This can also be set by the --mpi
46 # section (mpi4py, pytrilinos, etc.). This can also be set by the --mpi
47 # command line option.
47 # command line option.
48 # c.MPI.use = ''
48 # c.MPI.use = ''
49
49
50 # Initialize MPI using mpi4py. To use this, set c.MPI.use = 'mpi4py' to use
50 # Initialize MPI using mpi4py. To use this, set c.MPI.use = 'mpi4py' to use
51 # --mpi=mpi4py at the command line.
51 # --mpi=mpi4py at the command line.
52 # c.MPI.mpi4py = """from mpi4py import MPI as mpi
52 # c.MPI.mpi4py = """from mpi4py import MPI as mpi
53 # mpi.size = mpi.COMM_WORLD.Get_size()
53 # mpi.size = mpi.COMM_WORLD.Get_size()
54 # mpi.rank = mpi.COMM_WORLD.Get_rank()
54 # mpi.rank = mpi.COMM_WORLD.Get_rank()
55 # """
55 # """
56
56
57 # Initialize MPI using pytrilinos. To use this, set c.MPI.use = 'pytrilinos'
57 # Initialize MPI using pytrilinos. To use this, set c.MPI.use = 'pytrilinos'
58 # to use --mpi=pytrilinos at the command line.
58 # to use --mpi=pytrilinos at the command line.
59 # c.MPI.pytrilinos = """from PyTrilinos import Epetra
59 # c.MPI.pytrilinos = """from PyTrilinos import Epetra
60 # class SimpleStruct:
60 # class SimpleStruct:
61 # pass
61 # pass
62 # mpi = SimpleStruct()
62 # mpi = SimpleStruct()
63 # mpi.rank = 0
63 # mpi.rank = 0
64 # mpi.size = 0
64 # mpi.size = 0
65 # """
65 # """
66
66
67 #-----------------------------------------------------------------------------
67 #-----------------------------------------------------------------------------
68 # Developer level configuration attributes
68 # Developer level configuration attributes
69 #-----------------------------------------------------------------------------
69 #-----------------------------------------------------------------------------
70
70
71 # You shouldn't have to modify anything in this section. These attributes
71 # You shouldn't have to modify anything in this section. These attributes
72 # are more for developers who want to change the behavior of the controller
72 # are more for developers who want to change the behavior of the controller
73 # at a fundamental level.
73 # at a fundamental level.
74
74
75 # You should not have to change these attributes.
75 # You should not have to change these attributes.
76
76
77 # c.Global.shell_class = 'IPython.kernel.core.interpreter.Interpreter'
77 # c.Global.shell_class = 'IPython.kernel.core.interpreter.Interpreter'
78
78
79 # c.Global.furl_file_name = 'ipcontroller-engine.furl'
79 # c.Global.furl_file_name = u'ipcontroller-engine.furl'
80
80
81
81
82
82
83
83
84
84
85
85
86
86
@@ -1,148 +1,148 b''
1 # Get the config being loaded so we can set attributes on it
1 # Get the config being loaded so we can set attributes on it
2 c = get_config()
2 c = get_config()
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Global options
5 # Global options
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7
7
8 # c.Global.display_banner = True
8 # c.Global.display_banner = True
9
9
10 # c.Global.classic = False
10 # c.Global.classic = False
11
11
12 # c.Global.nosep = True
12 # c.Global.nosep = True
13
13
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.
16 # c.Global.log_level = 20
16 # c.Global.log_level = 20
17
17
18 # This should be a list of importable Python modules that have an
18 # This should be a list of importable Python modules that have an
19 # load_in_ipython(ip) method. This method gets called when the extension
19 # load_in_ipython(ip) method. This method gets called when the extension
20 # is loaded. You can put your extensions anywhere they can be imported
20 # is loaded. You can put your extensions anywhere they can be imported
21 # but we add the extensions subdir of the ipython directory to sys.path
21 # but we add the extensions subdir of the ipython directory to sys.path
22 # during extension loading, so you can put them there as well.
22 # during extension loading, so you can put them there as well.
23 # c.Global.extensions = [
23 # c.Global.extensions = [
24 # 'myextension'
24 # 'myextension'
25 # ]
25 # ]
26
26
27 # These lines are run in IPython in the user's namespace after extensions
27 # These lines are run in IPython in the user's namespace after extensions
28 # are loaded. They can contain full IPython syntax with magics etc.
28 # are loaded. They can contain full IPython syntax with magics etc.
29 # c.Global.exec_lines = [
29 # c.Global.exec_lines = [
30 # 'import numpy',
30 # 'import numpy',
31 # 'a = 10; b = 20',
31 # 'a = 10; b = 20',
32 # '1/0'
32 # '1/0'
33 # ]
33 # ]
34
34
35 # These files are run in IPython in the user's namespace. Files with a .py
35 # 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 have
36 # 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 ipython_dir 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'
42 # ]
42 # ]
43
43
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45 # InteractiveShell options
45 # InteractiveShell options
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47
47
48 # c.InteractiveShell.autocall = 1
48 # c.InteractiveShell.autocall = 1
49
49
50 # c.InteractiveShell.autoedit_syntax = False
50 # c.InteractiveShell.autoedit_syntax = False
51
51
52 # c.InteractiveShell.autoindent = True
52 # c.InteractiveShell.autoindent = True
53
53
54 # c.InteractiveShell.automagic = False
54 # c.InteractiveShell.automagic = False
55
55
56 # c.InteractiveShell.banner1 = 'This if for overriding the default IPython banner'
56 # c.InteractiveShell.banner1 = 'This if for overriding the default IPython banner'
57
57
58 # c.InteractiveShell.banner2 = "This is for extra banner text"
58 # c.InteractiveShell.banner2 = "This is for extra banner text"
59
59
60 # c.InteractiveShell.cache_size = 1000
60 # c.InteractiveShell.cache_size = 1000
61
61
62 # c.InteractiveShell.colors = 'LightBG'
62 # c.InteractiveShell.colors = 'LightBG'
63
63
64 # c.InteractiveShell.color_info = True
64 # c.InteractiveShell.color_info = True
65
65
66 # c.InteractiveShell.confirm_exit = True
66 # c.InteractiveShell.confirm_exit = True
67
67
68 # c.InteractiveShell.deep_reload = False
68 # c.InteractiveShell.deep_reload = False
69
69
70 # c.InteractiveShell.editor = 'nano'
70 # c.InteractiveShell.editor = 'nano'
71
71
72 # c.InteractiveShell.logstart = True
72 # c.InteractiveShell.logstart = True
73
73
74 # c.InteractiveShell.logfile = 'ipython_log.py'
74 # c.InteractiveShell.logfile = u'ipython_log.py'
75
75
76 # c.InteractiveShell.logappend = 'mylog.py'
76 # c.InteractiveShell.logappend = u'mylog.py'
77
77
78 # c.InteractiveShell.object_info_string_level = 0
78 # c.InteractiveShell.object_info_string_level = 0
79
79
80 # c.InteractiveShell.pager = 'less'
80 # c.InteractiveShell.pager = 'less'
81
81
82 # c.InteractiveShell.pdb = False
82 # c.InteractiveShell.pdb = False
83
83
84 # c.InteractiveShell.pprint = True
84 # c.InteractiveShell.pprint = True
85
85
86 # c.InteractiveShell.prompt_in1 = 'In [\#]: '
86 # c.InteractiveShell.prompt_in1 = 'In [\#]: '
87 # c.InteractiveShell.prompt_in2 = ' .\D.: '
87 # c.InteractiveShell.prompt_in2 = ' .\D.: '
88 # c.InteractiveShell.prompt_out = 'Out[\#]: '
88 # c.InteractiveShell.prompt_out = 'Out[\#]: '
89 # c.InteractiveShell.prompts_pad_left = True
89 # c.InteractiveShell.prompts_pad_left = True
90
90
91 # c.InteractiveShell.quiet = False
91 # c.InteractiveShell.quiet = False
92
92
93 # Readline
93 # Readline
94 # c.InteractiveShell.readline_use = True
94 # c.InteractiveShell.readline_use = True
95
95
96 # c.InteractiveShell.readline_parse_and_bind = [
96 # c.InteractiveShell.readline_parse_and_bind = [
97 # 'tab: complete',
97 # 'tab: complete',
98 # '"\C-l": possible-completions',
98 # '"\C-l": possible-completions',
99 # 'set show-all-if-ambiguous on',
99 # 'set show-all-if-ambiguous on',
100 # '"\C-o": tab-insert',
100 # '"\C-o": tab-insert',
101 # '"\M-i": " "',
101 # '"\M-i": " "',
102 # '"\M-o": "\d\d\d\d"',
102 # '"\M-o": "\d\d\d\d"',
103 # '"\M-I": "\d\d\d\d"',
103 # '"\M-I": "\d\d\d\d"',
104 # '"\C-r": reverse-search-history',
104 # '"\C-r": reverse-search-history',
105 # '"\C-s": forward-search-history',
105 # '"\C-s": forward-search-history',
106 # '"\C-p": history-search-backward',
106 # '"\C-p": history-search-backward',
107 # '"\C-n": history-search-forward',
107 # '"\C-n": history-search-forward',
108 # '"\e[A": history-search-backward',
108 # '"\e[A": history-search-backward',
109 # '"\e[B": history-search-forward',
109 # '"\e[B": history-search-forward',
110 # '"\C-k": kill-line',
110 # '"\C-k": kill-line',
111 # '"\C-u": unix-line-discard',
111 # '"\C-u": unix-line-discard',
112 # ]
112 # ]
113 # c.InteractiveShell.readline_remove_delims = '-/~'
113 # c.InteractiveShell.readline_remove_delims = '-/~'
114 # c.InteractiveShell.readline_merge_completions = True
114 # c.InteractiveShell.readline_merge_completions = True
115 # c.InteractiveShell.readline_omit_names = 0
115 # c.InteractiveShell.readline_omit_names = 0
116
116
117 # c.InteractiveShell.screen_length = 0
117 # c.InteractiveShell.screen_length = 0
118
118
119 # c.InteractiveShell.separate_in = '\n'
119 # c.InteractiveShell.separate_in = '\n'
120 # c.InteractiveShell.separate_out = ''
120 # c.InteractiveShell.separate_out = ''
121 # c.InteractiveShell.separate_out2 = ''
121 # c.InteractiveShell.separate_out2 = ''
122
122
123 # c.InteractiveShell.system_header = "IPython system call: "
123 # c.InteractiveShell.system_header = "IPython system call: "
124
124
125 # c.InteractiveShell.system_verbose = True
125 # c.InteractiveShell.system_verbose = True
126
126
127 # c.InteractiveShell.term_title = False
127 # c.InteractiveShell.term_title = False
128
128
129 # c.InteractiveShell.wildcards_case_sensitive = True
129 # c.InteractiveShell.wildcards_case_sensitive = True
130
130
131 # c.InteractiveShell.xmode = 'Context'
131 # c.InteractiveShell.xmode = 'Context'
132
132
133 #-----------------------------------------------------------------------------
133 #-----------------------------------------------------------------------------
134 # PrefilterManager options
134 # PrefilterManager options
135 #-----------------------------------------------------------------------------
135 #-----------------------------------------------------------------------------
136
136
137 # c.PrefilterManager.multi_line_specials = True
137 # c.PrefilterManager.multi_line_specials = True
138
138
139 #-----------------------------------------------------------------------------
139 #-----------------------------------------------------------------------------
140 # AliasManager options
140 # AliasManager options
141 #-----------------------------------------------------------------------------
141 #-----------------------------------------------------------------------------
142
142
143 # Do this to disable all defaults
143 # Do this to disable all defaults
144 # c.AliasManager.default_aliases = []
144 # c.AliasManager.default_aliases = []
145
145
146 # c.AliasManager.user_aliases = [
146 # c.AliasManager.user_aliases = [
147 # ('foo', 'echo Hi')
147 # ('foo', 'echo Hi')
148 # ] No newline at end of file
148 # ]
@@ -1,364 +1,364 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 An application for IPython.
4 An application for IPython.
5
5
6 All top-level applications should use the classes in this module for
6 All top-level applications should use the classes in this module for
7 handling configuration and creating componenets.
7 handling configuration and creating componenets.
8
8
9 The job of an :class:`Application` is to create the master configuration
9 The job of an :class:`Application` is to create the master configuration
10 object and then create the components, passing the config to them.
10 object and then create the components, passing the config to them.
11
11
12 Authors:
12 Authors:
13
13
14 * Brian Granger
14 * Brian Granger
15 * Fernando Perez
15 * Fernando Perez
16
16
17 Notes
17 Notes
18 -----
18 -----
19 """
19 """
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Copyright (C) 2008-2009 The IPython Development Team
22 # Copyright (C) 2008-2009 The IPython Development Team
23 #
23 #
24 # Distributed under the terms of the BSD License. The full license is in
24 # Distributed under the terms of the BSD License. The full license is in
25 # the file COPYING, distributed as part of this software.
25 # the file COPYING, distributed as part of this software.
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Imports
29 # Imports
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32 import logging
32 import logging
33 import os
33 import os
34 import sys
34 import sys
35
35
36 from IPython.core import release
36 from IPython.core import release
37 from IPython.utils.genutils import get_ipython_dir
37 from IPython.utils.genutils import get_ipython_dir
38 from IPython.config.loader import (
38 from IPython.config.loader import (
39 PyFileConfigLoader,
39 PyFileConfigLoader,
40 ArgParseConfigLoader,
40 ArgParseConfigLoader,
41 Config,
41 Config,
42 NoConfigDefault
42 NoConfigDefault
43 )
43 )
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # Classes and functions
46 # Classes and functions
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49
49
50 class BaseAppArgParseConfigLoader(ArgParseConfigLoader):
50 class BaseAppArgParseConfigLoader(ArgParseConfigLoader):
51 """Default command line options for IPython based applications."""
51 """Default command line options for IPython based applications."""
52
52
53 def _add_other_arguments(self):
53 def _add_other_arguments(self):
54 self.parser.add_argument('--ipython-dir',
54 self.parser.add_argument('--ipython-dir',
55 dest='Global.ipython_dir',type=str,
55 dest='Global.ipython_dir',type=unicode,
56 help='Set to override default location of Global.ipython_dir.',
56 help='Set to override default location of Global.ipython_dir.',
57 default=NoConfigDefault,
57 default=NoConfigDefault,
58 metavar='Global.ipython_dir')
58 metavar='Global.ipython_dir')
59 self.parser.add_argument('-p', '--profile',
59 self.parser.add_argument('-p', '--profile',
60 dest='Global.profile',type=str,
60 dest='Global.profile',type=unicode,
61 help='The string name of the ipython profile to be used.',
61 help='The string name of the ipython profile to be used.',
62 default=NoConfigDefault,
62 default=NoConfigDefault,
63 metavar='Global.profile')
63 metavar='Global.profile')
64 self.parser.add_argument('--log-level',
64 self.parser.add_argument('--log-level',
65 dest="Global.log_level",type=int,
65 dest="Global.log_level",type=int,
66 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.',
67 default=NoConfigDefault,
67 default=NoConfigDefault,
68 metavar='Global.log_level')
68 metavar='Global.log_level')
69 self.parser.add_argument('--config-file',
69 self.parser.add_argument('--config-file',
70 dest='Global.config_file',type=str,
70 dest='Global.config_file',type=unicode,
71 help='Set the config file name to override default.',
71 help='Set the config file name to override default.',
72 default=NoConfigDefault,
72 default=NoConfigDefault,
73 metavar='Global.config_file')
73 metavar='Global.config_file')
74
74
75
75
76 class ApplicationError(Exception):
76 class ApplicationError(Exception):
77 pass
77 pass
78
78
79
79
80 class Application(object):
80 class Application(object):
81 """Load a config, construct components and set them running."""
81 """Load a config, construct components and set them running."""
82
82
83 name = 'ipython'
83 name = u'ipython'
84 description = 'IPython: an enhanced interactive Python shell.'
84 description = 'IPython: an enhanced interactive Python shell.'
85 config_file_name = 'ipython_config.py'
85 config_file_name = u'ipython_config.py'
86 default_log_level = logging.WARN
86 default_log_level = logging.WARN
87
87
88 def __init__(self):
88 def __init__(self):
89 self._exiting = False
89 self._exiting = False
90 self.init_logger()
90 self.init_logger()
91 # Track the default and actual separately because some messages are
91 # Track the default and actual separately because some messages are
92 # only printed if we aren't using the default.
92 # only printed if we aren't using the default.
93 self.default_config_file_name = self.config_file_name
93 self.default_config_file_name = self.config_file_name
94
94
95 def init_logger(self):
95 def init_logger(self):
96 self.log = logging.getLogger(self.__class__.__name__)
96 self.log = logging.getLogger(self.__class__.__name__)
97 # 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.
98 self.log.setLevel(self.default_log_level)
98 self.log.setLevel(self.default_log_level)
99 self._log_handler = logging.StreamHandler()
99 self._log_handler = logging.StreamHandler()
100 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
100 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
101 self._log_handler.setFormatter(self._log_formatter)
101 self._log_handler.setFormatter(self._log_formatter)
102 self.log.addHandler(self._log_handler)
102 self.log.addHandler(self._log_handler)
103
103
104 def _set_log_level(self, level):
104 def _set_log_level(self, level):
105 self.log.setLevel(level)
105 self.log.setLevel(level)
106
106
107 def _get_log_level(self):
107 def _get_log_level(self):
108 return self.log.level
108 return self.log.level
109
109
110 log_level = property(_get_log_level, _set_log_level)
110 log_level = property(_get_log_level, _set_log_level)
111
111
112 def start(self):
112 def start(self):
113 """Start the application."""
113 """Start the application."""
114 self.attempt(self.create_default_config)
114 self.attempt(self.create_default_config)
115 self.log_default_config()
115 self.log_default_config()
116 self.set_default_config_log_level()
116 self.set_default_config_log_level()
117 self.attempt(self.pre_load_command_line_config)
117 self.attempt(self.pre_load_command_line_config)
118 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()
119 self.set_command_line_config_log_level()
120 self.attempt(self.post_load_command_line_config)
120 self.attempt(self.post_load_command_line_config)
121 self.log_command_line_config()
121 self.log_command_line_config()
122 self.attempt(self.find_ipython_dir)
122 self.attempt(self.find_ipython_dir)
123 self.attempt(self.find_resources)
123 self.attempt(self.find_resources)
124 self.attempt(self.find_config_file_name)
124 self.attempt(self.find_config_file_name)
125 self.attempt(self.find_config_file_paths)
125 self.attempt(self.find_config_file_paths)
126 self.attempt(self.pre_load_file_config)
126 self.attempt(self.pre_load_file_config)
127 self.attempt(self.load_file_config)
127 self.attempt(self.load_file_config)
128 self.set_file_config_log_level()
128 self.set_file_config_log_level()
129 self.attempt(self.post_load_file_config)
129 self.attempt(self.post_load_file_config)
130 self.log_file_config()
130 self.log_file_config()
131 self.attempt(self.merge_configs)
131 self.attempt(self.merge_configs)
132 self.log_master_config()
132 self.log_master_config()
133 self.attempt(self.pre_construct)
133 self.attempt(self.pre_construct)
134 self.attempt(self.construct)
134 self.attempt(self.construct)
135 self.attempt(self.post_construct)
135 self.attempt(self.post_construct)
136 self.attempt(self.start_app)
136 self.attempt(self.start_app)
137
137
138 #-------------------------------------------------------------------------
138 #-------------------------------------------------------------------------
139 # Various stages of Application creation
139 # Various stages of Application creation
140 #-------------------------------------------------------------------------
140 #-------------------------------------------------------------------------
141
141
142 def create_default_config(self):
142 def create_default_config(self):
143 """Create defaults that can't be set elsewhere.
143 """Create defaults that can't be set elsewhere.
144
144
145 For the most part, we try to set default in the class attributes
145 For the most part, we try to set default in the class attributes
146 of Components. But, defaults the top-level Application (which is
146 of Components. But, defaults the top-level Application (which is
147 not a HasTraitlets or Component) are not set in this way. Instead
147 not a HasTraitlets or Component) are not set in this way. Instead
148 we set them here. The Global section is for variables like this that
148 we set them here. The Global section is for variables like this that
149 don't belong to a particular component.
149 don't belong to a particular component.
150 """
150 """
151 self.default_config = Config()
151 self.default_config = Config()
152 self.default_config.Global.ipython_dir = get_ipython_dir()
152 self.default_config.Global.ipython_dir = get_ipython_dir()
153 self.default_config.Global.log_level = self.log_level
153 self.default_config.Global.log_level = self.log_level
154
154
155 def log_default_config(self):
155 def log_default_config(self):
156 self.log.debug('Default config loaded:')
156 self.log.debug('Default config loaded:')
157 self.log.debug(repr(self.default_config))
157 self.log.debug(repr(self.default_config))
158
158
159 def set_default_config_log_level(self):
159 def set_default_config_log_level(self):
160 try:
160 try:
161 self.log_level = self.default_config.Global.log_level
161 self.log_level = self.default_config.Global.log_level
162 except AttributeError:
162 except AttributeError:
163 # Fallback to the default_log_level class attribute
163 # Fallback to the default_log_level class attribute
164 pass
164 pass
165
165
166 def create_command_line_config(self):
166 def create_command_line_config(self):
167 """Create and return a command line config loader."""
167 """Create and return a command line config loader."""
168 return BaseAppArgParseConfigLoader(
168 return BaseAppArgParseConfigLoader(
169 description=self.description,
169 description=self.description,
170 version=release.version
170 version=release.version
171 )
171 )
172
172
173 def pre_load_command_line_config(self):
173 def pre_load_command_line_config(self):
174 """Do actions just before loading the command line config."""
174 """Do actions just before loading the command line config."""
175 pass
175 pass
176
176
177 def load_command_line_config(self):
177 def load_command_line_config(self):
178 """Load the command line config."""
178 """Load the command line config."""
179 loader = self.create_command_line_config()
179 loader = self.create_command_line_config()
180 self.command_line_config = loader.load_config()
180 self.command_line_config = loader.load_config()
181 self.extra_args = loader.get_extra_args()
181 self.extra_args = loader.get_extra_args()
182
182
183 def set_command_line_config_log_level(self):
183 def set_command_line_config_log_level(self):
184 try:
184 try:
185 self.log_level = self.command_line_config.Global.log_level
185 self.log_level = self.command_line_config.Global.log_level
186 except AttributeError:
186 except AttributeError:
187 pass
187 pass
188
188
189 def post_load_command_line_config(self):
189 def post_load_command_line_config(self):
190 """Do actions just after loading the command line config."""
190 """Do actions just after loading the command line config."""
191 pass
191 pass
192
192
193 def log_command_line_config(self):
193 def log_command_line_config(self):
194 self.log.debug("Command line config loaded:")
194 self.log.debug("Command line config loaded:")
195 self.log.debug(repr(self.command_line_config))
195 self.log.debug(repr(self.command_line_config))
196
196
197 def find_ipython_dir(self):
197 def find_ipython_dir(self):
198 """Set the IPython directory.
198 """Set the IPython directory.
199
199
200 This sets ``self.ipython_dir``, but the actual value that is passed
200 This sets ``self.ipython_dir``, but the actual value that is passed
201 to the application is kept in either ``self.default_config`` or
201 to the application is kept in either ``self.default_config`` or
202 ``self.command_line_config``. This also adds ``self.ipython_dir`` to
202 ``self.command_line_config``. This also adds ``self.ipython_dir`` to
203 ``sys.path`` so config files there can be references by other config
203 ``sys.path`` so config files there can be references by other config
204 files.
204 files.
205 """
205 """
206
206
207 try:
207 try:
208 self.ipython_dir = self.command_line_config.Global.ipython_dir
208 self.ipython_dir = self.command_line_config.Global.ipython_dir
209 except AttributeError:
209 except AttributeError:
210 self.ipython_dir = self.default_config.Global.ipython_dir
210 self.ipython_dir = self.default_config.Global.ipython_dir
211 sys.path.append(os.path.abspath(self.ipython_dir))
211 sys.path.append(os.path.abspath(self.ipython_dir))
212 if not os.path.isdir(self.ipython_dir):
212 if not os.path.isdir(self.ipython_dir):
213 os.makedirs(self.ipython_dir, mode=0777)
213 os.makedirs(self.ipython_dir, mode=0777)
214 self.log.debug("IPYTHON_DIR set to: %s" % self.ipython_dir)
214 self.log.debug("IPYTHON_DIR set to: %s" % self.ipython_dir)
215
215
216 def find_resources(self):
216 def find_resources(self):
217 """Find other resources that need to be in place.
217 """Find other resources that need to be in place.
218
218
219 Things like cluster directories need to be in place to find the
219 Things like cluster directories need to be in place to find the
220 config file. These happen right after the IPython directory has
220 config file. These happen right after the IPython directory has
221 been set.
221 been set.
222 """
222 """
223 pass
223 pass
224
224
225 def find_config_file_name(self):
225 def find_config_file_name(self):
226 """Find the config file name for this application.
226 """Find the config file name for this application.
227
227
228 This must set ``self.config_file_name`` to the filename of the
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
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
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.
231 to the config file loader where they are resolved to an absolute path.
232
232
233 If a profile has been set at the command line, this will resolve
233 If a profile has been set at the command line, this will resolve
234 it.
234 it.
235 """
235 """
236
236
237 try:
237 try:
238 self.config_file_name = self.command_line_config.Global.config_file
238 self.config_file_name = self.command_line_config.Global.config_file
239 except AttributeError:
239 except AttributeError:
240 pass
240 pass
241
241
242 try:
242 try:
243 self.profile_name = self.command_line_config.Global.profile
243 self.profile_name = self.command_line_config.Global.profile
244 name_parts = self.config_file_name.split('.')
244 name_parts = self.config_file_name.split('.')
245 name_parts.insert(1, '_' + self.profile_name + '.')
245 name_parts.insert(1, u'_' + self.profile_name + u'.')
246 self.config_file_name = ''.join(name_parts)
246 self.config_file_name = ''.join(name_parts)
247 except AttributeError:
247 except AttributeError:
248 pass
248 pass
249
249
250 def find_config_file_paths(self):
250 def find_config_file_paths(self):
251 """Set the search paths for resolving the config file.
251 """Set the search paths for resolving the config file.
252
252
253 This must set ``self.config_file_paths`` to a sequence of search
253 This must set ``self.config_file_paths`` to a sequence of search
254 paths to pass to the config file loader.
254 paths to pass to the config file loader.
255 """
255 """
256 self.config_file_paths = (os.getcwd(), self.ipython_dir)
256 self.config_file_paths = (os.getcwd(), self.ipython_dir)
257
257
258 def pre_load_file_config(self):
258 def pre_load_file_config(self):
259 """Do actions before the config file is loaded."""
259 """Do actions before the config file is loaded."""
260 pass
260 pass
261
261
262 def load_file_config(self):
262 def load_file_config(self):
263 """Load the config file.
263 """Load the config file.
264
264
265 This tries to load the config file from disk. If successful, the
265 This tries to load the config file from disk. If successful, the
266 ``CONFIG_FILE`` config variable is set to the resolved config file
266 ``CONFIG_FILE`` config variable is set to the resolved config file
267 location. If not successful, an empty config is used.
267 location. If not successful, an empty config is used.
268 """
268 """
269 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)
270 loader = PyFileConfigLoader(self.config_file_name,
270 loader = PyFileConfigLoader(self.config_file_name,
271 path=self.config_file_paths)
271 path=self.config_file_paths)
272 try:
272 try:
273 self.file_config = loader.load_config()
273 self.file_config = loader.load_config()
274 self.file_config.Global.config_file = loader.full_filename
274 self.file_config.Global.config_file = loader.full_filename
275 except IOError:
275 except IOError:
276 # Only warn if the default config file was NOT being used.
276 # Only warn if the default config file was NOT being used.
277 if not self.config_file_name==self.default_config_file_name:
277 if not self.config_file_name==self.default_config_file_name:
278 self.log.warn("Config file not found, skipping: %s" % \
278 self.log.warn("Config file not found, skipping: %s" % \
279 self.config_file_name, exc_info=True)
279 self.config_file_name, exc_info=True)
280 self.file_config = Config()
280 self.file_config = Config()
281 except:
281 except:
282 self.log.warn("Error loading config file: %s" % \
282 self.log.warn("Error loading config file: %s" % \
283 self.config_file_name, exc_info=True)
283 self.config_file_name, exc_info=True)
284 self.file_config = Config()
284 self.file_config = Config()
285
285
286 def set_file_config_log_level(self):
286 def set_file_config_log_level(self):
287 # We need to keeep self.log_level updated. But we only use the value
287 # We need to keeep self.log_level updated. But we only use the value
288 # of the file_config if a value was not specified at the command
288 # of the file_config if a value was not specified at the command
289 # line, because the command line overrides everything.
289 # line, because the command line overrides everything.
290 if not hasattr(self.command_line_config.Global, 'log_level'):
290 if not hasattr(self.command_line_config.Global, 'log_level'):
291 try:
291 try:
292 self.log_level = self.file_config.Global.log_level
292 self.log_level = self.file_config.Global.log_level
293 except AttributeError:
293 except AttributeError:
294 pass # Use existing value
294 pass # Use existing value
295
295
296 def post_load_file_config(self):
296 def post_load_file_config(self):
297 """Do actions after the config file is loaded."""
297 """Do actions after the config file is loaded."""
298 pass
298 pass
299
299
300 def log_file_config(self):
300 def log_file_config(self):
301 if hasattr(self.file_config.Global, 'config_file'):
301 if hasattr(self.file_config.Global, 'config_file'):
302 self.log.debug("Config file loaded: %s" % 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))
303 self.log.debug(repr(self.file_config))
304
304
305 def merge_configs(self):
305 def merge_configs(self):
306 """Merge the default, command line and file config objects."""
306 """Merge the default, command line and file config objects."""
307 config = Config()
307 config = Config()
308 config._merge(self.default_config)
308 config._merge(self.default_config)
309 config._merge(self.file_config)
309 config._merge(self.file_config)
310 config._merge(self.command_line_config)
310 config._merge(self.command_line_config)
311 self.master_config = config
311 self.master_config = config
312
312
313 def log_master_config(self):
313 def log_master_config(self):
314 self.log.debug("Master config created:")
314 self.log.debug("Master config created:")
315 self.log.debug(repr(self.master_config))
315 self.log.debug(repr(self.master_config))
316
316
317 def pre_construct(self):
317 def pre_construct(self):
318 """Do actions after the config has been built, but before construct."""
318 """Do actions after the config has been built, but before construct."""
319 pass
319 pass
320
320
321 def construct(self):
321 def construct(self):
322 """Construct the main components that make up this app."""
322 """Construct the main components that make up this app."""
323 self.log.debug("Constructing components for application")
323 self.log.debug("Constructing components for application")
324
324
325 def post_construct(self):
325 def post_construct(self):
326 """Do actions after construct, but before starting the app."""
326 """Do actions after construct, but before starting the app."""
327 pass
327 pass
328
328
329 def start_app(self):
329 def start_app(self):
330 """Actually start the app."""
330 """Actually start the app."""
331 self.log.debug("Starting application")
331 self.log.debug("Starting application")
332
332
333 #-------------------------------------------------------------------------
333 #-------------------------------------------------------------------------
334 # Utility methods
334 # Utility methods
335 #-------------------------------------------------------------------------
335 #-------------------------------------------------------------------------
336
336
337 def abort(self):
337 def abort(self):
338 """Abort the starting of the application."""
338 """Abort the starting of the application."""
339 if self._exiting:
339 if self._exiting:
340 pass
340 pass
341 else:
341 else:
342 self.log.critical("Aborting application: %s" % self.name, exc_info=True)
342 self.log.critical("Aborting application: %s" % self.name, exc_info=True)
343 self._exiting = True
343 self._exiting = True
344 sys.exit(1)
344 sys.exit(1)
345
345
346 def exit(self, exit_status=0):
346 def exit(self, exit_status=0):
347 if self._exiting:
347 if self._exiting:
348 pass
348 pass
349 else:
349 else:
350 self.log.debug("Exiting application: %s" % self.name)
350 self.log.debug("Exiting application: %s" % self.name)
351 self._exiting = True
351 self._exiting = True
352 sys.exit(exit_status)
352 sys.exit(exit_status)
353
353
354 def attempt(self, func, action='abort'):
354 def attempt(self, func, action='abort'):
355 try:
355 try:
356 func()
356 func()
357 except SystemExit:
357 except SystemExit:
358 raise
358 raise
359 except:
359 except:
360 if action == 'abort':
360 if action == 'abort':
361 self.abort()
361 self.abort()
362 elif action == 'exit':
362 elif action == 'exit':
363 self.exit(0)
363 self.exit(0)
364
364
@@ -1,544 +1,544 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The :class:`~IPython.core.application.Application` object for the command
4 The :class:`~IPython.core.application.Application` object for the command
5 line :command:`ipython` program.
5 line :command:`ipython` program.
6
6
7 Authors:
7 Authors:
8
8
9 * Brian Granger
9 * Brian Granger
10 * Fernando Perez
10 * Fernando Perez
11
11
12 Notes
12 Notes
13 -----
13 -----
14 """
14 """
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Copyright (C) 2008-2009 The IPython Development Team
17 # Copyright (C) 2008-2009 The IPython Development Team
18 #
18 #
19 # Distributed under the terms of the BSD License. The full license is in
19 # Distributed under the terms of the BSD License. The full license is in
20 # the file COPYING, distributed as part of this software.
20 # the file COPYING, distributed as part of this software.
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Imports
24 # Imports
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 import logging
27 import logging
28 import os
28 import os
29 import sys
29 import sys
30 import warnings
30 import warnings
31
31
32 from IPython.core.application import Application, BaseAppArgParseConfigLoader
32 from IPython.core.application import Application, BaseAppArgParseConfigLoader
33 from IPython.core import release
33 from IPython.core import release
34 from IPython.core.iplib import InteractiveShell
34 from IPython.core.iplib import InteractiveShell
35 from IPython.config.loader import (
35 from IPython.config.loader import (
36 NoConfigDefault,
36 NoConfigDefault,
37 Config,
37 Config,
38 PyFileConfigLoader
38 PyFileConfigLoader
39 )
39 )
40
40
41 from IPython.lib import inputhook
41 from IPython.lib import inputhook
42
42
43 from IPython.utils.genutils import filefind, get_ipython_dir
43 from IPython.utils.genutils import filefind, get_ipython_dir
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # Utilities and helpers
46 # Utilities and helpers
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49
49
50 ipython_desc = """
50 ipython_desc = """
51 A Python shell with automatic history (input and output), dynamic object
51 A Python shell with automatic history (input and output), dynamic object
52 introspection, easier configuration, command completion, access to the system
52 introspection, easier configuration, command completion, access to the system
53 shell and more.
53 shell and more.
54 """
54 """
55
55
56 def pylab_warning():
56 def pylab_warning():
57 msg = """
57 msg = """
58
58
59 IPython's -pylab mode has been disabled until matplotlib supports this version
59 IPython's -pylab mode has been disabled until matplotlib supports this version
60 of IPython. This version of IPython has greatly improved GUI integration that
60 of IPython. This version of IPython has greatly improved GUI integration that
61 matplotlib will soon be able to take advantage of. This will eventually
61 matplotlib will soon be able to take advantage of. This will eventually
62 result in greater stability and a richer API for matplotlib under IPython.
62 result in greater stability and a richer API for matplotlib under IPython.
63 However during this transition, you will either need to use an older version
63 However during this transition, you will either need to use an older version
64 of IPython, or do the following to use matplotlib interactively::
64 of IPython, or do the following to use matplotlib interactively::
65
65
66 import matplotlib
66 import matplotlib
67 matplotlib.interactive(True)
67 matplotlib.interactive(True)
68 matplotlib.use('wxagg') # adjust for your backend
68 matplotlib.use('wxagg') # adjust for your backend
69 %gui -a wx # adjust for your GUI
69 %gui -a wx # adjust for your GUI
70 from matplotlib import pyplot as plt
70 from matplotlib import pyplot as plt
71
71
72 See the %gui magic for information on the new interface.
72 See the %gui magic for information on the new interface.
73 """
73 """
74 warnings.warn(msg, category=DeprecationWarning, stacklevel=1)
74 warnings.warn(msg, category=DeprecationWarning, stacklevel=1)
75
75
76
76
77 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
78 # Main classes and functions
78 # Main classes and functions
79 #-----------------------------------------------------------------------------
79 #-----------------------------------------------------------------------------
80
80
81 cl_args = (
81 cl_args = (
82 (('--autocall',), dict(
82 (('--autocall',), dict(
83 type=int, dest='InteractiveShell.autocall', default=NoConfigDefault,
83 type=int, dest='InteractiveShell.autocall', default=NoConfigDefault,
84 help='Set the autocall value (0,1,2).',
84 help='Set the autocall value (0,1,2).',
85 metavar='InteractiveShell.autocall')
85 metavar='InteractiveShell.autocall')
86 ),
86 ),
87 (('--autoindent',), dict(
87 (('--autoindent',), dict(
88 action='store_true', dest='InteractiveShell.autoindent', default=NoConfigDefault,
88 action='store_true', dest='InteractiveShell.autoindent', default=NoConfigDefault,
89 help='Turn on autoindenting.')
89 help='Turn on autoindenting.')
90 ),
90 ),
91 (('--no-autoindent',), dict(
91 (('--no-autoindent',), dict(
92 action='store_false', dest='InteractiveShell.autoindent', default=NoConfigDefault,
92 action='store_false', dest='InteractiveShell.autoindent', default=NoConfigDefault,
93 help='Turn off autoindenting.')
93 help='Turn off autoindenting.')
94 ),
94 ),
95 (('--automagic',), dict(
95 (('--automagic',), dict(
96 action='store_true', dest='InteractiveShell.automagic', default=NoConfigDefault,
96 action='store_true', dest='InteractiveShell.automagic', default=NoConfigDefault,
97 help='Turn on the auto calling of magic commands.')
97 help='Turn on the auto calling of magic commands.')
98 ),
98 ),
99 (('--no-automagic',), dict(
99 (('--no-automagic',), dict(
100 action='store_false', dest='InteractiveShell.automagic', default=NoConfigDefault,
100 action='store_false', dest='InteractiveShell.automagic', default=NoConfigDefault,
101 help='Turn off the auto calling of magic commands.')
101 help='Turn off the auto calling of magic commands.')
102 ),
102 ),
103 (('--autoedit-syntax',), dict(
103 (('--autoedit-syntax',), dict(
104 action='store_true', dest='InteractiveShell.autoedit_syntax', default=NoConfigDefault,
104 action='store_true', dest='InteractiveShell.autoedit_syntax', default=NoConfigDefault,
105 help='Turn on auto editing of files with syntax errors.')
105 help='Turn on auto editing of files with syntax errors.')
106 ),
106 ),
107 (('--no-autoedit-syntax',), dict(
107 (('--no-autoedit-syntax',), dict(
108 action='store_false', dest='InteractiveShell.autoedit_syntax', default=NoConfigDefault,
108 action='store_false', dest='InteractiveShell.autoedit_syntax', default=NoConfigDefault,
109 help='Turn off auto editing of files with syntax errors.')
109 help='Turn off auto editing of files with syntax errors.')
110 ),
110 ),
111 (('--banner',), dict(
111 (('--banner',), dict(
112 action='store_true', dest='Global.display_banner', default=NoConfigDefault,
112 action='store_true', dest='Global.display_banner', default=NoConfigDefault,
113 help='Display a banner upon starting IPython.')
113 help='Display a banner upon starting IPython.')
114 ),
114 ),
115 (('--no-banner',), dict(
115 (('--no-banner',), dict(
116 action='store_false', dest='Global.display_banner', default=NoConfigDefault,
116 action='store_false', dest='Global.display_banner', default=NoConfigDefault,
117 help="Don't display a banner upon starting IPython.")
117 help="Don't display a banner upon starting IPython.")
118 ),
118 ),
119 (('--cache-size',), dict(
119 (('--cache-size',), dict(
120 type=int, dest='InteractiveShell.cache_size', default=NoConfigDefault,
120 type=int, dest='InteractiveShell.cache_size', default=NoConfigDefault,
121 help="Set the size of the output cache.",
121 help="Set the size of the output cache.",
122 metavar='InteractiveShell.cache_size')
122 metavar='InteractiveShell.cache_size')
123 ),
123 ),
124 (('--classic',), dict(
124 (('--classic',), dict(
125 action='store_true', dest='Global.classic', default=NoConfigDefault,
125 action='store_true', dest='Global.classic', default=NoConfigDefault,
126 help="Gives IPython a similar feel to the classic Python prompt.")
126 help="Gives IPython a similar feel to the classic Python prompt.")
127 ),
127 ),
128 (('--colors',), dict(
128 (('--colors',), dict(
129 type=str, dest='InteractiveShell.colors', default=NoConfigDefault,
129 type=str, dest='InteractiveShell.colors', default=NoConfigDefault,
130 help="Set the color scheme (NoColor, Linux, and LightBG).",
130 help="Set the color scheme (NoColor, Linux, and LightBG).",
131 metavar='InteractiveShell.colors')
131 metavar='InteractiveShell.colors')
132 ),
132 ),
133 (('--color-info',), dict(
133 (('--color-info',), dict(
134 action='store_true', dest='InteractiveShell.color_info', default=NoConfigDefault,
134 action='store_true', dest='InteractiveShell.color_info', default=NoConfigDefault,
135 help="Enable using colors for info related things.")
135 help="Enable using colors for info related things.")
136 ),
136 ),
137 (('--no-color-info',), dict(
137 (('--no-color-info',), dict(
138 action='store_false', dest='InteractiveShell.color_info', default=NoConfigDefault,
138 action='store_false', dest='InteractiveShell.color_info', default=NoConfigDefault,
139 help="Disable using colors for info related things.")
139 help="Disable using colors for info related things.")
140 ),
140 ),
141 (('--confirm-exit',), dict(
141 (('--confirm-exit',), dict(
142 action='store_true', dest='InteractiveShell.confirm_exit', default=NoConfigDefault,
142 action='store_true', dest='InteractiveShell.confirm_exit', default=NoConfigDefault,
143 help="Prompt the user when existing.")
143 help="Prompt the user when existing.")
144 ),
144 ),
145 (('--no-confirm-exit',), dict(
145 (('--no-confirm-exit',), dict(
146 action='store_false', dest='InteractiveShell.confirm_exit', default=NoConfigDefault,
146 action='store_false', dest='InteractiveShell.confirm_exit', default=NoConfigDefault,
147 help="Don't prompt the user when existing.")
147 help="Don't prompt the user when existing.")
148 ),
148 ),
149 (('--deep-reload',), dict(
149 (('--deep-reload',), dict(
150 action='store_true', dest='InteractiveShell.deep_reload', default=NoConfigDefault,
150 action='store_true', dest='InteractiveShell.deep_reload', default=NoConfigDefault,
151 help="Enable deep (recursive) reloading by default.")
151 help="Enable deep (recursive) reloading by default.")
152 ),
152 ),
153 (('--no-deep-reload',), dict(
153 (('--no-deep-reload',), dict(
154 action='store_false', dest='InteractiveShell.deep_reload', default=NoConfigDefault,
154 action='store_false', dest='InteractiveShell.deep_reload', default=NoConfigDefault,
155 help="Disable deep (recursive) reloading by default.")
155 help="Disable deep (recursive) reloading by default.")
156 ),
156 ),
157 (('--editor',), dict(
157 (('--editor',), dict(
158 type=str, dest='InteractiveShell.editor', default=NoConfigDefault,
158 type=str, dest='InteractiveShell.editor', default=NoConfigDefault,
159 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).",
160 metavar='InteractiveShell.editor')
160 metavar='InteractiveShell.editor')
161 ),
161 ),
162 (('--log','-l'), dict(
162 (('--log','-l'), dict(
163 action='store_true', dest='InteractiveShell.logstart', default=NoConfigDefault,
163 action='store_true', dest='InteractiveShell.logstart', default=NoConfigDefault,
164 help="Start logging to the default file (./ipython_log.py).")
164 help="Start logging to the default file (./ipython_log.py).")
165 ),
165 ),
166 (('--logfile','-lf'), dict(
166 (('--logfile','-lf'), dict(
167 type=str, dest='InteractiveShell.logfile', default=NoConfigDefault,
167 type=unicode, dest='InteractiveShell.logfile', default=NoConfigDefault,
168 help="Start logging to logfile.",
168 help="Start logging to logfile.",
169 metavar='InteractiveShell.logfile')
169 metavar='InteractiveShell.logfile')
170 ),
170 ),
171 (('--log-append','-la'), dict(
171 (('--log-append','-la'), dict(
172 type=str, dest='InteractiveShell.logappend', default=NoConfigDefault,
172 type=unicode, dest='InteractiveShell.logappend', default=NoConfigDefault,
173 help="Start logging to logappend in append mode.",
173 help="Start logging to the give file in append mode.",
174 metavar='InteractiveShell.logfile')
174 metavar='InteractiveShell.logfile')
175 ),
175 ),
176 (('--pdb',), dict(
176 (('--pdb',), dict(
177 action='store_true', dest='InteractiveShell.pdb', default=NoConfigDefault,
177 action='store_true', dest='InteractiveShell.pdb', default=NoConfigDefault,
178 help="Enable auto calling the pdb debugger after every exception.")
178 help="Enable auto calling the pdb debugger after every exception.")
179 ),
179 ),
180 (('--nopdb',), dict(
180 (('--no-pdb',), dict(
181 action='store_false', dest='InteractiveShell.pdb', default=NoConfigDefault,
181 action='store_false', dest='InteractiveShell.pdb', default=NoConfigDefault,
182 help="Disable auto calling the pdb debugger after every exception.")
182 help="Disable auto calling the pdb debugger after every exception.")
183 ),
183 ),
184 (('--pprint',), dict(
184 (('--pprint',), dict(
185 action='store_true', dest='InteractiveShell.pprint', default=NoConfigDefault,
185 action='store_true', dest='InteractiveShell.pprint', default=NoConfigDefault,
186 help="Enable auto pretty printing of results.")
186 help="Enable auto pretty printing of results.")
187 ),
187 ),
188 (('--no-pprint',), dict(
188 (('--no-pprint',), dict(
189 action='store_false', dest='InteractiveShell.pprint', default=NoConfigDefault,
189 action='store_false', dest='InteractiveShell.pprint', default=NoConfigDefault,
190 help="Disable auto auto pretty printing of results.")
190 help="Disable auto auto pretty printing of results.")
191 ),
191 ),
192 (('--prompt-in1','-pi1'), dict(
192 (('--prompt-in1','-pi1'), dict(
193 type=str, dest='InteractiveShell.prompt_in1', default=NoConfigDefault,
193 type=str, dest='InteractiveShell.prompt_in1', default=NoConfigDefault,
194 help="Set the main input prompt ('In [\#]: ')",
194 help="Set the main input prompt ('In [\#]: ')",
195 metavar='InteractiveShell.prompt_in1')
195 metavar='InteractiveShell.prompt_in1')
196 ),
196 ),
197 (('--prompt-in2','-pi2'), dict(
197 (('--prompt-in2','-pi2'), dict(
198 type=str, dest='InteractiveShell.prompt_in2', default=NoConfigDefault,
198 type=str, dest='InteractiveShell.prompt_in2', default=NoConfigDefault,
199 help="Set the secondary input prompt (' .\D.: ')",
199 help="Set the secondary input prompt (' .\D.: ')",
200 metavar='InteractiveShell.prompt_in2')
200 metavar='InteractiveShell.prompt_in2')
201 ),
201 ),
202 (('--prompt-out','-po'), dict(
202 (('--prompt-out','-po'), dict(
203 type=str, dest='InteractiveShell.prompt_out', default=NoConfigDefault,
203 type=str, dest='InteractiveShell.prompt_out', default=NoConfigDefault,
204 help="Set the output prompt ('Out[\#]:')",
204 help="Set the output prompt ('Out[\#]:')",
205 metavar='InteractiveShell.prompt_out')
205 metavar='InteractiveShell.prompt_out')
206 ),
206 ),
207 (('--quick',), dict(
207 (('--quick',), dict(
208 action='store_true', dest='Global.quick', default=NoConfigDefault,
208 action='store_true', dest='Global.quick', default=NoConfigDefault,
209 help="Enable quick startup with no config files.")
209 help="Enable quick startup with no config files.")
210 ),
210 ),
211 (('--readline',), dict(
211 (('--readline',), dict(
212 action='store_true', dest='InteractiveShell.readline_use', default=NoConfigDefault,
212 action='store_true', dest='InteractiveShell.readline_use', default=NoConfigDefault,
213 help="Enable readline for command line usage.")
213 help="Enable readline for command line usage.")
214 ),
214 ),
215 (('--no-readline',), dict(
215 (('--no-readline',), dict(
216 action='store_false', dest='InteractiveShell.readline_use', default=NoConfigDefault,
216 action='store_false', dest='InteractiveShell.readline_use', default=NoConfigDefault,
217 help="Disable readline for command line usage.")
217 help="Disable readline for command line usage.")
218 ),
218 ),
219 (('--screen-length','-sl'), dict(
219 (('--screen-length','-sl'), dict(
220 type=int, dest='InteractiveShell.screen_length', default=NoConfigDefault,
220 type=int, dest='InteractiveShell.screen_length', default=NoConfigDefault,
221 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.',
222 metavar='InteractiveShell.screen_length')
222 metavar='InteractiveShell.screen_length')
223 ),
223 ),
224 (('--separate-in','-si'), dict(
224 (('--separate-in','-si'), dict(
225 type=str, dest='InteractiveShell.separate_in', default=NoConfigDefault,
225 type=str, dest='InteractiveShell.separate_in', default=NoConfigDefault,
226 help="Separator before input prompts. Default '\n'.",
226 help="Separator before input prompts. Default '\n'.",
227 metavar='InteractiveShell.separate_in')
227 metavar='InteractiveShell.separate_in')
228 ),
228 ),
229 (('--separate-out','-so'), dict(
229 (('--separate-out','-so'), dict(
230 type=str, dest='InteractiveShell.separate_out', default=NoConfigDefault,
230 type=str, dest='InteractiveShell.separate_out', default=NoConfigDefault,
231 help="Separator before output prompts. Default 0 (nothing).",
231 help="Separator before output prompts. Default 0 (nothing).",
232 metavar='InteractiveShell.separate_out')
232 metavar='InteractiveShell.separate_out')
233 ),
233 ),
234 (('--separate-out2','-so2'), dict(
234 (('--separate-out2','-so2'), dict(
235 type=str, dest='InteractiveShell.separate_out2', default=NoConfigDefault,
235 type=str, dest='InteractiveShell.separate_out2', default=NoConfigDefault,
236 help="Separator after output prompts. Default 0 (nonight).",
236 help="Separator after output prompts. Default 0 (nonight).",
237 metavar='InteractiveShell.separate_out2')
237 metavar='InteractiveShell.separate_out2')
238 ),
238 ),
239 (('-no-sep',), dict(
239 (('-no-sep',), dict(
240 action='store_true', dest='Global.nosep', default=NoConfigDefault,
240 action='store_true', dest='Global.nosep', default=NoConfigDefault,
241 help="Eliminate all spacing between prompts.")
241 help="Eliminate all spacing between prompts.")
242 ),
242 ),
243 (('--term-title',), dict(
243 (('--term-title',), dict(
244 action='store_true', dest='InteractiveShell.term_title', default=NoConfigDefault,
244 action='store_true', dest='InteractiveShell.term_title', default=NoConfigDefault,
245 help="Enable auto setting the terminal title.")
245 help="Enable auto setting the terminal title.")
246 ),
246 ),
247 (('--no-term-title',), dict(
247 (('--no-term-title',), dict(
248 action='store_false', dest='InteractiveShell.term_title', default=NoConfigDefault,
248 action='store_false', dest='InteractiveShell.term_title', default=NoConfigDefault,
249 help="Disable auto setting the terminal title.")
249 help="Disable auto setting the terminal title.")
250 ),
250 ),
251 (('--xmode',), dict(
251 (('--xmode',), dict(
252 type=str, dest='InteractiveShell.xmode', default=NoConfigDefault,
252 type=str, dest='InteractiveShell.xmode', default=NoConfigDefault,
253 help="Exception mode ('Plain','Context','Verbose')",
253 help="Exception mode ('Plain','Context','Verbose')",
254 metavar='InteractiveShell.xmode')
254 metavar='InteractiveShell.xmode')
255 ),
255 ),
256 (('--ext',), dict(
256 (('--ext',), dict(
257 type=str, dest='Global.extra_extension', default=NoConfigDefault,
257 type=str, dest='Global.extra_extension', default=NoConfigDefault,
258 help="The dotted module name of an IPython extension to load.",
258 help="The dotted module name of an IPython extension to load.",
259 metavar='Global.extra_extension')
259 metavar='Global.extra_extension')
260 ),
260 ),
261 (('-c',), dict(
261 (('-c',), dict(
262 type=str, dest='Global.code_to_run', default=NoConfigDefault,
262 type=str, dest='Global.code_to_run', default=NoConfigDefault,
263 help="Execute the given command string.",
263 help="Execute the given command string.",
264 metavar='Global.code_to_run')
264 metavar='Global.code_to_run')
265 ),
265 ),
266 (('-i',), dict(
266 (('-i',), dict(
267 action='store_true', dest='Global.force_interact', default=NoConfigDefault,
267 action='store_true', dest='Global.force_interact', default=NoConfigDefault,
268 help="If running code from the command line, become interactive afterwards.")
268 help="If running code from the command line, become interactive afterwards.")
269 ),
269 ),
270 (('--wthread',), dict(
270 (('--wthread',), dict(
271 action='store_true', dest='Global.wthread', default=NoConfigDefault,
271 action='store_true', dest='Global.wthread', default=NoConfigDefault,
272 help="Enable wxPython event loop integration.")
272 help="Enable wxPython event loop integration.")
273 ),
273 ),
274 (('--q4thread','--qthread'), dict(
274 (('--q4thread','--qthread'), dict(
275 action='store_true', dest='Global.q4thread', default=NoConfigDefault,
275 action='store_true', dest='Global.q4thread', default=NoConfigDefault,
276 help="Enable Qt4 event loop integration. Qt3 is no longer supported.")
276 help="Enable Qt4 event loop integration. Qt3 is no longer supported.")
277 ),
277 ),
278 (('--gthread',), dict(
278 (('--gthread',), dict(
279 action='store_true', dest='Global.gthread', default=NoConfigDefault,
279 action='store_true', dest='Global.gthread', default=NoConfigDefault,
280 help="Enable GTK event loop integration.")
280 help="Enable GTK event loop integration.")
281 ),
281 ),
282 # # These are only here to get the proper deprecation warnings
282 # # These are only here to get the proper deprecation warnings
283 (('--pylab',), dict(
283 (('--pylab',), dict(
284 action='store_true', dest='Global.pylab', default=NoConfigDefault,
284 action='store_true', dest='Global.pylab', default=NoConfigDefault,
285 help="Disabled. Pylab has been disabled until matplotlib "
285 help="Disabled. Pylab has been disabled until matplotlib "
286 "supports this version of IPython.")
286 "supports this version of IPython.")
287 )
287 )
288 )
288 )
289
289
290
290
291 class IPythonAppCLConfigLoader(BaseAppArgParseConfigLoader):
291 class IPythonAppCLConfigLoader(BaseAppArgParseConfigLoader):
292
292
293 arguments = cl_args
293 arguments = cl_args
294
294
295
295
296 default_config_file_name = 'ipython_config.py'
296 default_config_file_name = u'ipython_config.py'
297
297
298
298
299 class IPythonApp(Application):
299 class IPythonApp(Application):
300 name = 'ipython'
300 name = u'ipython'
301 description = 'IPython: an enhanced interactive Python shell.'
301 description = 'IPython: an enhanced interactive Python shell.'
302 config_file_name = default_config_file_name
302 config_file_name = default_config_file_name
303
303
304 def create_default_config(self):
304 def create_default_config(self):
305 super(IPythonApp, self).create_default_config()
305 super(IPythonApp, self).create_default_config()
306 self.default_config.Global.display_banner = True
306 self.default_config.Global.display_banner = True
307
307
308 # If the -c flag is given or a file is given to run at the cmd line
308 # If the -c flag is given or a file is given to run at the cmd line
309 # like "ipython foo.py", normally we exit without starting the main
309 # like "ipython foo.py", normally we exit without starting the main
310 # loop. The force_interact config variable allows a user to override
310 # loop. The force_interact config variable allows a user to override
311 # this and interact. It is also set by the -i cmd line flag, just
311 # this and interact. It is also set by the -i cmd line flag, just
312 # like Python.
312 # like Python.
313 self.default_config.Global.force_interact = False
313 self.default_config.Global.force_interact = False
314
314
315 # By default always interact by starting the IPython mainloop.
315 # By default always interact by starting the IPython mainloop.
316 self.default_config.Global.interact = True
316 self.default_config.Global.interact = True
317
317
318 # No GUI integration by default
318 # No GUI integration by default
319 self.default_config.Global.wthread = False
319 self.default_config.Global.wthread = False
320 self.default_config.Global.q4thread = False
320 self.default_config.Global.q4thread = False
321 self.default_config.Global.gthread = False
321 self.default_config.Global.gthread = False
322
322
323 def create_command_line_config(self):
323 def create_command_line_config(self):
324 """Create and return a command line config loader."""
324 """Create and return a command line config loader."""
325 return IPythonAppCLConfigLoader(
325 return IPythonAppCLConfigLoader(
326 description=self.description,
326 description=self.description,
327 version=release.version
327 version=release.version
328 )
328 )
329
329
330 def post_load_command_line_config(self):
330 def post_load_command_line_config(self):
331 """Do actions after loading cl config."""
331 """Do actions after loading cl config."""
332 clc = self.command_line_config
332 clc = self.command_line_config
333
333
334 # Display the deprecation warnings about threaded shells
334 # Display the deprecation warnings about threaded shells
335 if hasattr(clc.Global, 'pylab'):
335 if hasattr(clc.Global, 'pylab'):
336 pylab_warning()
336 pylab_warning()
337 del clc.Global['pylab']
337 del clc.Global['pylab']
338
338
339 def load_file_config(self):
339 def load_file_config(self):
340 if hasattr(self.command_line_config.Global, 'quick'):
340 if hasattr(self.command_line_config.Global, 'quick'):
341 if self.command_line_config.Global.quick:
341 if self.command_line_config.Global.quick:
342 self.file_config = Config()
342 self.file_config = Config()
343 return
343 return
344 super(IPythonApp, self).load_file_config()
344 super(IPythonApp, self).load_file_config()
345
345
346 def post_load_file_config(self):
346 def post_load_file_config(self):
347 if hasattr(self.command_line_config.Global, 'extra_extension'):
347 if hasattr(self.command_line_config.Global, 'extra_extension'):
348 if not hasattr(self.file_config.Global, 'extensions'):
348 if not hasattr(self.file_config.Global, 'extensions'):
349 self.file_config.Global.extensions = []
349 self.file_config.Global.extensions = []
350 self.file_config.Global.extensions.append(
350 self.file_config.Global.extensions.append(
351 self.command_line_config.Global.extra_extension)
351 self.command_line_config.Global.extra_extension)
352 del self.command_line_config.Global.extra_extension
352 del self.command_line_config.Global.extra_extension
353
353
354 def pre_construct(self):
354 def pre_construct(self):
355 config = self.master_config
355 config = self.master_config
356
356
357 if hasattr(config.Global, 'classic'):
357 if hasattr(config.Global, 'classic'):
358 if config.Global.classic:
358 if config.Global.classic:
359 config.InteractiveShell.cache_size = 0
359 config.InteractiveShell.cache_size = 0
360 config.InteractiveShell.pprint = 0
360 config.InteractiveShell.pprint = 0
361 config.InteractiveShell.prompt_in1 = '>>> '
361 config.InteractiveShell.prompt_in1 = '>>> '
362 config.InteractiveShell.prompt_in2 = '... '
362 config.InteractiveShell.prompt_in2 = '... '
363 config.InteractiveShell.prompt_out = ''
363 config.InteractiveShell.prompt_out = ''
364 config.InteractiveShell.separate_in = \
364 config.InteractiveShell.separate_in = \
365 config.InteractiveShell.separate_out = \
365 config.InteractiveShell.separate_out = \
366 config.InteractiveShell.separate_out2 = ''
366 config.InteractiveShell.separate_out2 = ''
367 config.InteractiveShell.colors = 'NoColor'
367 config.InteractiveShell.colors = 'NoColor'
368 config.InteractiveShell.xmode = 'Plain'
368 config.InteractiveShell.xmode = 'Plain'
369
369
370 if hasattr(config.Global, 'nosep'):
370 if hasattr(config.Global, 'nosep'):
371 if config.Global.nosep:
371 if config.Global.nosep:
372 config.InteractiveShell.separate_in = \
372 config.InteractiveShell.separate_in = \
373 config.InteractiveShell.separate_out = \
373 config.InteractiveShell.separate_out = \
374 config.InteractiveShell.separate_out2 = ''
374 config.InteractiveShell.separate_out2 = ''
375
375
376 # if there is code of files to run from the cmd line, don't interact
376 # if there is code of files to run from the cmd line, don't interact
377 # unless the -i flag (Global.force_interact) is true.
377 # unless the -i flag (Global.force_interact) is true.
378 code_to_run = config.Global.get('code_to_run','')
378 code_to_run = config.Global.get('code_to_run','')
379 file_to_run = False
379 file_to_run = False
380 if len(self.extra_args)>=1:
380 if len(self.extra_args)>=1:
381 if self.extra_args[0]:
381 if self.extra_args[0]:
382 file_to_run = True
382 file_to_run = True
383 if file_to_run or code_to_run:
383 if file_to_run or code_to_run:
384 if not config.Global.force_interact:
384 if not config.Global.force_interact:
385 config.Global.interact = False
385 config.Global.interact = False
386
386
387 def construct(self):
387 def construct(self):
388 # I am a little hesitant to put these into InteractiveShell itself.
388 # I am a little hesitant to put these into InteractiveShell itself.
389 # But that might be the place for them
389 # But that might be the place for them
390 sys.path.insert(0, '')
390 sys.path.insert(0, '')
391
391
392 # Create an InteractiveShell instance
392 # Create an InteractiveShell instance
393 self.shell = InteractiveShell(
393 self.shell = InteractiveShell(
394 parent=None,
394 parent=None,
395 config=self.master_config
395 config=self.master_config
396 )
396 )
397
397
398 def post_construct(self):
398 def post_construct(self):
399 """Do actions after construct, but before starting the app."""
399 """Do actions after construct, but before starting the app."""
400 config = self.master_config
400 config = self.master_config
401
401
402 # shell.display_banner should always be False for the terminal
402 # shell.display_banner should always be False for the terminal
403 # based app, because we call shell.show_banner() by hand below
403 # based app, because we call shell.show_banner() by hand below
404 # so the banner shows *before* all extension loading stuff.
404 # so the banner shows *before* all extension loading stuff.
405 self.shell.display_banner = False
405 self.shell.display_banner = False
406
406
407 if config.Global.display_banner and \
407 if config.Global.display_banner and \
408 config.Global.interact:
408 config.Global.interact:
409 self.shell.show_banner()
409 self.shell.show_banner()
410
410
411 # Make sure there is a space below the banner.
411 # Make sure there is a space below the banner.
412 if self.log_level <= logging.INFO: print
412 if self.log_level <= logging.INFO: print
413
413
414 # Now a variety of things that happen after the banner is printed.
414 # Now a variety of things that happen after the banner is printed.
415 self._enable_gui()
415 self._enable_gui()
416 self._load_extensions()
416 self._load_extensions()
417 self._run_exec_lines()
417 self._run_exec_lines()
418 self._run_exec_files()
418 self._run_exec_files()
419 self._run_cmd_line_code()
419 self._run_cmd_line_code()
420
420
421 def _enable_gui(self):
421 def _enable_gui(self):
422 """Enable GUI event loop integration."""
422 """Enable GUI event loop integration."""
423 config = self.master_config
423 config = self.master_config
424 try:
424 try:
425 # Enable GUI integration
425 # Enable GUI integration
426 if config.Global.wthread:
426 if config.Global.wthread:
427 self.log.info("Enabling wx GUI event loop integration")
427 self.log.info("Enabling wx GUI event loop integration")
428 inputhook.enable_wx(app=True)
428 inputhook.enable_wx(app=True)
429 elif config.Global.q4thread:
429 elif config.Global.q4thread:
430 self.log.info("Enabling Qt4 GUI event loop integration")
430 self.log.info("Enabling Qt4 GUI event loop integration")
431 inputhook.enable_qt4(app=True)
431 inputhook.enable_qt4(app=True)
432 elif config.Global.gthread:
432 elif config.Global.gthread:
433 self.log.info("Enabling GTK GUI event loop integration")
433 self.log.info("Enabling GTK GUI event loop integration")
434 inputhook.enable_gtk(app=True)
434 inputhook.enable_gtk(app=True)
435 except:
435 except:
436 self.log.warn("Error in enabling GUI event loop integration:")
436 self.log.warn("Error in enabling GUI event loop integration:")
437 self.shell.showtraceback()
437 self.shell.showtraceback()
438
438
439 def _load_extensions(self):
439 def _load_extensions(self):
440 """Load all IPython extensions in Global.extensions.
440 """Load all IPython extensions in Global.extensions.
441
441
442 This uses the :meth:`InteractiveShell.load_extensions` to load all
442 This uses the :meth:`InteractiveShell.load_extensions` to load all
443 the extensions listed in ``self.master_config.Global.extensions``.
443 the extensions listed in ``self.master_config.Global.extensions``.
444 """
444 """
445 try:
445 try:
446 if hasattr(self.master_config.Global, 'extensions'):
446 if hasattr(self.master_config.Global, 'extensions'):
447 self.log.debug("Loading IPython extensions...")
447 self.log.debug("Loading IPython extensions...")
448 extensions = self.master_config.Global.extensions
448 extensions = self.master_config.Global.extensions
449 for ext in extensions:
449 for ext in extensions:
450 try:
450 try:
451 self.log.info("Loading IPython extension: %s" % ext)
451 self.log.info("Loading IPython extension: %s" % ext)
452 self.shell.load_extension(ext)
452 self.shell.load_extension(ext)
453 except:
453 except:
454 self.log.warn("Error in loading extension: %s" % ext)
454 self.log.warn("Error in loading extension: %s" % ext)
455 self.shell.showtraceback()
455 self.shell.showtraceback()
456 except:
456 except:
457 self.log.warn("Unknown error in loading extensions:")
457 self.log.warn("Unknown error in loading extensions:")
458 self.shell.showtraceback()
458 self.shell.showtraceback()
459
459
460 def _run_exec_lines(self):
460 def _run_exec_lines(self):
461 """Run lines of code in Global.exec_lines in the user's namespace."""
461 """Run lines of code in Global.exec_lines in the user's namespace."""
462 try:
462 try:
463 if hasattr(self.master_config.Global, 'exec_lines'):
463 if hasattr(self.master_config.Global, 'exec_lines'):
464 self.log.debug("Running code from Global.exec_lines...")
464 self.log.debug("Running code from Global.exec_lines...")
465 exec_lines = self.master_config.Global.exec_lines
465 exec_lines = self.master_config.Global.exec_lines
466 for line in exec_lines:
466 for line in exec_lines:
467 try:
467 try:
468 self.log.info("Running code in user namespace: %s" % line)
468 self.log.info("Running code in user namespace: %s" % line)
469 self.shell.runlines(line)
469 self.shell.runlines(line)
470 except:
470 except:
471 self.log.warn("Error in executing line in user namespace: %s" % line)
471 self.log.warn("Error in executing line in user namespace: %s" % line)
472 self.shell.showtraceback()
472 self.shell.showtraceback()
473 except:
473 except:
474 self.log.warn("Unknown error in handling Global.exec_lines:")
474 self.log.warn("Unknown error in handling Global.exec_lines:")
475 self.shell.showtraceback()
475 self.shell.showtraceback()
476
476
477 def _exec_file(self, fname):
477 def _exec_file(self, fname):
478 full_filename = filefind(fname, ['.', self.ipython_dir])
478 full_filename = filefind(fname, [u'.', self.ipython_dir])
479 if os.path.isfile(full_filename):
479 if os.path.isfile(full_filename):
480 if full_filename.endswith('.py'):
480 if full_filename.endswith(u'.py'):
481 self.log.info("Running file in user namespace: %s" % full_filename)
481 self.log.info("Running file in user namespace: %s" % full_filename)
482 self.shell.safe_execfile(full_filename, self.shell.user_ns)
482 self.shell.safe_execfile(full_filename, self.shell.user_ns)
483 elif full_filename.endswith('.ipy'):
483 elif full_filename.endswith('.ipy'):
484 self.log.info("Running file in user namespace: %s" % full_filename)
484 self.log.info("Running file in user namespace: %s" % full_filename)
485 self.shell.safe_execfile_ipy(full_filename)
485 self.shell.safe_execfile_ipy(full_filename)
486 else:
486 else:
487 self.log.warn("File does not have a .py or .ipy extension: <%s>" % full_filename)
487 self.log.warn("File does not have a .py or .ipy extension: <%s>" % full_filename)
488
488
489 def _run_exec_files(self):
489 def _run_exec_files(self):
490 try:
490 try:
491 if hasattr(self.master_config.Global, 'exec_files'):
491 if hasattr(self.master_config.Global, 'exec_files'):
492 self.log.debug("Running files in Global.exec_files...")
492 self.log.debug("Running files in Global.exec_files...")
493 exec_files = self.master_config.Global.exec_files
493 exec_files = self.master_config.Global.exec_files
494 for fname in exec_files:
494 for fname in exec_files:
495 self._exec_file(fname)
495 self._exec_file(fname)
496 except:
496 except:
497 self.log.warn("Unknown error in handling Global.exec_files:")
497 self.log.warn("Unknown error in handling Global.exec_files:")
498 self.shell.showtraceback()
498 self.shell.showtraceback()
499
499
500 def _run_cmd_line_code(self):
500 def _run_cmd_line_code(self):
501 if hasattr(self.master_config.Global, 'code_to_run'):
501 if hasattr(self.master_config.Global, 'code_to_run'):
502 line = self.master_config.Global.code_to_run
502 line = self.master_config.Global.code_to_run
503 try:
503 try:
504 self.log.info("Running code given at command line (-c): %s" % line)
504 self.log.info("Running code given at command line (-c): %s" % line)
505 self.shell.runlines(line)
505 self.shell.runlines(line)
506 except:
506 except:
507 self.log.warn("Error in executing line in user namespace: %s" % line)
507 self.log.warn("Error in executing line in user namespace: %s" % line)
508 self.shell.showtraceback()
508 self.shell.showtraceback()
509 return
509 return
510 # Like Python itself, ignore the second if the first of these is present
510 # Like Python itself, ignore the second if the first of these is present
511 try:
511 try:
512 fname = self.extra_args[0]
512 fname = self.extra_args[0]
513 except:
513 except:
514 pass
514 pass
515 else:
515 else:
516 try:
516 try:
517 self._exec_file(fname)
517 self._exec_file(fname)
518 except:
518 except:
519 self.log.warn("Error in executing file in user namespace: %s" % fname)
519 self.log.warn("Error in executing file in user namespace: %s" % fname)
520 self.shell.showtraceback()
520 self.shell.showtraceback()
521
521
522 def start_app(self):
522 def start_app(self):
523 if self.master_config.Global.interact:
523 if self.master_config.Global.interact:
524 self.log.debug("Starting IPython's mainloop...")
524 self.log.debug("Starting IPython's mainloop...")
525 self.shell.mainloop()
525 self.shell.mainloop()
526
526
527
527
528 def load_default_config(ipython_dir=None):
528 def load_default_config(ipython_dir=None):
529 """Load the default config file from the default ipython_dir.
529 """Load the default config file from the default ipython_dir.
530
530
531 This is useful for embedded shells.
531 This is useful for embedded shells.
532 """
532 """
533 if ipython_dir is None:
533 if ipython_dir is None:
534 ipython_dir = get_ipython_dir()
534 ipython_dir = get_ipython_dir()
535 cl = PyFileConfigLoader(default_config_file_name, ipython_dir)
535 cl = PyFileConfigLoader(default_config_file_name, ipython_dir)
536 config = cl.load_config()
536 config = cl.load_config()
537 return config
537 return config
538
538
539
539
540 def launch_new_instance():
540 def launch_new_instance():
541 """Create and run a full blown IPython instance"""
541 """Create and run a full blown IPython instance"""
542 app = IPythonApp()
542 app = IPythonApp()
543 app.start()
543 app.start()
544
544
@@ -1,464 +1,464 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The IPython cluster directory
4 The IPython cluster directory
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # 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 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 from __future__ import with_statement
18 from __future__ import with_statement
19
19
20 import os
20 import os
21 import shutil
21 import shutil
22 import sys
22 import sys
23
23
24 from twisted.python import log
24 from twisted.python import log
25
25
26 from IPython.core import release
26 from IPython.core import release
27 from IPython.config.loader import PyFileConfigLoader
27 from IPython.config.loader import PyFileConfigLoader
28 from IPython.core.application import Application
28 from IPython.core.application import Application
29 from IPython.core.component import Component
29 from IPython.core.component import Component
30 from IPython.config.loader import ArgParseConfigLoader, NoConfigDefault
30 from IPython.config.loader import ArgParseConfigLoader, NoConfigDefault
31 from IPython.utils.traitlets import Unicode, Bool
31 from IPython.utils.traitlets import Unicode, Bool
32 from IPython.utils import genutils
32 from IPython.utils import genutils
33
33
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35 # Imports
35 # Imports
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37
37
38
38
39 class ClusterDirError(Exception):
39 class ClusterDirError(Exception):
40 pass
40 pass
41
41
42
42
43 class PIDFileError(Exception):
43 class PIDFileError(Exception):
44 pass
44 pass
45
45
46
46
47 class ClusterDir(Component):
47 class ClusterDir(Component):
48 """An object to manage the cluster directory and its resources.
48 """An object to manage the cluster directory and its resources.
49
49
50 The cluster directory is used by :command:`ipcontroller`,
50 The cluster directory is used by :command:`ipcontroller`,
51 :command:`ipcontroller` and :command:`ipcontroller` to manage the
51 :command:`ipcontroller` and :command:`ipcontroller` to manage the
52 configuration, logging and security of these applications.
52 configuration, logging and security of these applications.
53
53
54 This object knows how to find, create and manage these directories. This
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.
55 should be used by any code that want's to handle cluster directories.
56 """
56 """
57
57
58 security_dir_name = Unicode('security')
58 security_dir_name = Unicode('security')
59 log_dir_name = Unicode('log')
59 log_dir_name = Unicode('log')
60 pid_dir_name = Unicode('pid')
60 pid_dir_name = Unicode('pid')
61 security_dir = Unicode(u'')
61 security_dir = Unicode(u'')
62 log_dir = Unicode(u'')
62 log_dir = Unicode(u'')
63 pid_dir = Unicode(u'')
63 pid_dir = Unicode(u'')
64 location = Unicode(u'')
64 location = Unicode(u'')
65
65
66 def __init__(self, location):
66 def __init__(self, location):
67 super(ClusterDir, self).__init__(None)
67 super(ClusterDir, self).__init__(None)
68 self.location = location
68 self.location = location
69
69
70 def _location_changed(self, name, old, new):
70 def _location_changed(self, name, old, new):
71 if not os.path.isdir(new):
71 if not os.path.isdir(new):
72 os.makedirs(new, mode=0777)
72 os.makedirs(new, mode=0777)
73 else:
73 else:
74 os.chmod(new, 0777)
74 os.chmod(new, 0777)
75 self.security_dir = os.path.join(new, self.security_dir_name)
75 self.security_dir = os.path.join(new, self.security_dir_name)
76 self.log_dir = os.path.join(new, self.log_dir_name)
76 self.log_dir = os.path.join(new, self.log_dir_name)
77 self.pid_dir = os.path.join(new, self.pid_dir_name)
77 self.pid_dir = os.path.join(new, self.pid_dir_name)
78 self.check_dirs()
78 self.check_dirs()
79
79
80 def _log_dir_changed(self, name, old, new):
80 def _log_dir_changed(self, name, old, new):
81 self.check_log_dir()
81 self.check_log_dir()
82
82
83 def check_log_dir(self):
83 def check_log_dir(self):
84 if not os.path.isdir(self.log_dir):
84 if not os.path.isdir(self.log_dir):
85 os.mkdir(self.log_dir, 0777)
85 os.mkdir(self.log_dir, 0777)
86 else:
86 else:
87 os.chmod(self.log_dir, 0777)
87 os.chmod(self.log_dir, 0777)
88
88
89 def _security_dir_changed(self, name, old, new):
89 def _security_dir_changed(self, name, old, new):
90 self.check_security_dir()
90 self.check_security_dir()
91
91
92 def check_security_dir(self):
92 def check_security_dir(self):
93 if not os.path.isdir(self.security_dir):
93 if not os.path.isdir(self.security_dir):
94 os.mkdir(self.security_dir, 0700)
94 os.mkdir(self.security_dir, 0700)
95 else:
95 else:
96 os.chmod(self.security_dir, 0700)
96 os.chmod(self.security_dir, 0700)
97
97
98 def _pid_dir_changed(self, name, old, new):
98 def _pid_dir_changed(self, name, old, new):
99 self.check_pid_dir()
99 self.check_pid_dir()
100
100
101 def check_pid_dir(self):
101 def check_pid_dir(self):
102 if not os.path.isdir(self.pid_dir):
102 if not os.path.isdir(self.pid_dir):
103 os.mkdir(self.pid_dir, 0700)
103 os.mkdir(self.pid_dir, 0700)
104 else:
104 else:
105 os.chmod(self.pid_dir, 0700)
105 os.chmod(self.pid_dir, 0700)
106
106
107 def check_dirs(self):
107 def check_dirs(self):
108 self.check_security_dir()
108 self.check_security_dir()
109 self.check_log_dir()
109 self.check_log_dir()
110 self.check_pid_dir()
110 self.check_pid_dir()
111
111
112 def load_config_file(self, filename):
112 def load_config_file(self, filename):
113 """Load a config file from the top level of the cluster dir.
113 """Load a config file from the top level of the cluster dir.
114
114
115 Parameters
115 Parameters
116 ----------
116 ----------
117 filename : unicode or str
117 filename : unicode or str
118 The filename only of the config file that must be located in
118 The filename only of the config file that must be located in
119 the top-level of the cluster directory.
119 the top-level of the cluster directory.
120 """
120 """
121 loader = PyFileConfigLoader(filename, self.location)
121 loader = PyFileConfigLoader(filename, self.location)
122 return loader.load_config()
122 return loader.load_config()
123
123
124 def copy_config_file(self, config_file, path=None, overwrite=False):
124 def copy_config_file(self, config_file, path=None, overwrite=False):
125 """Copy a default config file into the active cluster directory.
125 """Copy a default config file into the active cluster directory.
126
126
127 Default configuration files are kept in :mod:`IPython.config.default`.
127 Default configuration files are kept in :mod:`IPython.config.default`.
128 This function moves these from that location to the working cluster
128 This function moves these from that location to the working cluster
129 directory.
129 directory.
130 """
130 """
131 if path is None:
131 if path is None:
132 import IPython.config.default
132 import IPython.config.default
133 path = IPython.config.default.__file__.split(os.path.sep)[:-1]
133 path = IPython.config.default.__file__.split(os.path.sep)[:-1]
134 path = os.path.sep.join(path)
134 path = os.path.sep.join(path)
135 src = os.path.join(path, config_file)
135 src = os.path.join(path, config_file)
136 dst = os.path.join(self.location, config_file)
136 dst = os.path.join(self.location, config_file)
137 if not os.path.isfile(dst) or overwrite:
137 if not os.path.isfile(dst) or overwrite:
138 shutil.copy(src, dst)
138 shutil.copy(src, dst)
139
139
140 def copy_all_config_files(self, path=None, overwrite=False):
140 def copy_all_config_files(self, path=None, overwrite=False):
141 """Copy all config files into the active cluster directory."""
141 """Copy all config files into the active cluster directory."""
142 for f in ['ipcontroller_config.py', 'ipengine_config.py',
142 for f in [u'ipcontroller_config.py', u'ipengine_config.py',
143 'ipcluster_config.py']:
143 u'ipcluster_config.py']:
144 self.copy_config_file(f, path=path, overwrite=overwrite)
144 self.copy_config_file(f, path=path, overwrite=overwrite)
145
145
146 @classmethod
146 @classmethod
147 def create_cluster_dir(csl, cluster_dir):
147 def create_cluster_dir(csl, cluster_dir):
148 """Create a new cluster directory given a full path.
148 """Create a new cluster directory given a full path.
149
149
150 Parameters
150 Parameters
151 ----------
151 ----------
152 cluster_dir : str
152 cluster_dir : str
153 The full path to the cluster directory. If it does exist, it will
153 The full path to the cluster directory. If it does exist, it will
154 be used. If not, it will be created.
154 be used. If not, it will be created.
155 """
155 """
156 return ClusterDir(cluster_dir)
156 return ClusterDir(cluster_dir)
157
157
158 @classmethod
158 @classmethod
159 def create_cluster_dir_by_profile(cls, path, profile='default'):
159 def create_cluster_dir_by_profile(cls, path, profile=u'default'):
160 """Create a cluster dir by profile name and path.
160 """Create a cluster dir by profile name and path.
161
161
162 Parameters
162 Parameters
163 ----------
163 ----------
164 path : str
164 path : str
165 The path (directory) to put the cluster directory in.
165 The path (directory) to put the cluster directory in.
166 profile : str
166 profile : str
167 The name of the profile. The name of the cluster directory will
167 The name of the profile. The name of the cluster directory will
168 be "cluster_<profile>".
168 be "cluster_<profile>".
169 """
169 """
170 if not os.path.isdir(path):
170 if not os.path.isdir(path):
171 raise ClusterDirError('Directory not found: %s' % path)
171 raise ClusterDirError('Directory not found: %s' % path)
172 cluster_dir = os.path.join(path, 'cluster_' + profile)
172 cluster_dir = os.path.join(path, u'cluster_' + profile)
173 return ClusterDir(cluster_dir)
173 return ClusterDir(cluster_dir)
174
174
175 @classmethod
175 @classmethod
176 def find_cluster_dir_by_profile(cls, ipython_dir, profile='default'):
176 def find_cluster_dir_by_profile(cls, ipython_dir, profile=u'default'):
177 """Find an existing cluster dir by profile name, return its ClusterDir.
177 """Find an existing cluster dir by profile name, return its ClusterDir.
178
178
179 This searches through a sequence of paths for a cluster dir. If it
179 This searches through a sequence of paths for a cluster dir. If it
180 is not found, a :class:`ClusterDirError` exception will be raised.
180 is not found, a :class:`ClusterDirError` exception will be raised.
181
181
182 The search path algorithm is:
182 The search path algorithm is:
183 1. ``os.getcwd()``
183 1. ``os.getcwd()``
184 2. ``ipython_dir``
184 2. ``ipython_dir``
185 3. The directories found in the ":" separated
185 3. The directories found in the ":" separated
186 :env:`IPCLUSTER_DIR_PATH` environment variable.
186 :env:`IPCLUSTER_DIR_PATH` environment variable.
187
187
188 Parameters
188 Parameters
189 ----------
189 ----------
190 ipython_dir : unicode or str
190 ipython_dir : unicode or str
191 The IPython directory to use.
191 The IPython directory to use.
192 profile : unicode or str
192 profile : unicode or str
193 The name of the profile. The name of the cluster directory
193 The name of the profile. The name of the cluster directory
194 will be "cluster_<profile>".
194 will be "cluster_<profile>".
195 """
195 """
196 dirname = 'cluster_' + profile
196 dirname = u'cluster_' + profile
197 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
197 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
198 if cluster_dir_paths:
198 if cluster_dir_paths:
199 cluster_dir_paths = cluster_dir_paths.split(':')
199 cluster_dir_paths = cluster_dir_paths.split(':')
200 else:
200 else:
201 cluster_dir_paths = []
201 cluster_dir_paths = []
202 paths = [os.getcwd(), ipython_dir] + cluster_dir_paths
202 paths = [os.getcwd(), ipython_dir] + cluster_dir_paths
203 for p in paths:
203 for p in paths:
204 cluster_dir = os.path.join(p, dirname)
204 cluster_dir = os.path.join(p, dirname)
205 if os.path.isdir(cluster_dir):
205 if os.path.isdir(cluster_dir):
206 return ClusterDir(cluster_dir)
206 return ClusterDir(cluster_dir)
207 else:
207 else:
208 raise ClusterDirError('Cluster directory not found in paths: %s' % dirname)
208 raise ClusterDirError('Cluster directory not found in paths: %s' % dirname)
209
209
210 @classmethod
210 @classmethod
211 def find_cluster_dir(cls, cluster_dir):
211 def find_cluster_dir(cls, cluster_dir):
212 """Find/create a cluster dir and return its ClusterDir.
212 """Find/create a cluster dir and return its ClusterDir.
213
213
214 This will create the cluster directory if it doesn't exist.
214 This will create the cluster directory if it doesn't exist.
215
215
216 Parameters
216 Parameters
217 ----------
217 ----------
218 cluster_dir : unicode or str
218 cluster_dir : unicode or str
219 The path of the cluster directory. This is expanded using
219 The path of the cluster directory. This is expanded using
220 :func:`IPython.utils.genutils.expand_path`.
220 :func:`IPython.utils.genutils.expand_path`.
221 """
221 """
222 cluster_dir = genutils.expand_path(cluster_dir)
222 cluster_dir = genutils.expand_path(cluster_dir)
223 if not os.path.isdir(cluster_dir):
223 if not os.path.isdir(cluster_dir):
224 raise ClusterDirError('Cluster directory not found: %s' % cluster_dir)
224 raise ClusterDirError('Cluster directory not found: %s' % cluster_dir)
225 return ClusterDir(cluster_dir)
225 return ClusterDir(cluster_dir)
226
226
227
227
228 class AppWithClusterDirArgParseConfigLoader(ArgParseConfigLoader):
228 class AppWithClusterDirArgParseConfigLoader(ArgParseConfigLoader):
229 """Default command line options for IPython cluster applications."""
229 """Default command line options for IPython cluster applications."""
230
230
231 def _add_other_arguments(self):
231 def _add_other_arguments(self):
232 self.parser.add_argument('--ipython-dir',
232 self.parser.add_argument('--ipython-dir',
233 dest='Global.ipython_dir',type=str,
233 dest='Global.ipython_dir',type=unicode,
234 help='Set to override default location of Global.ipython_dir.',
234 help='Set to override default location of Global.ipython_dir.',
235 default=NoConfigDefault,
235 default=NoConfigDefault,
236 metavar='Global.ipython_dir'
236 metavar='Global.ipython_dir'
237 )
237 )
238 self.parser.add_argument('-p', '--profile',
238 self.parser.add_argument('-p', '--profile',
239 dest='Global.profile',type=str,
239 dest='Global.profile',type=unicode,
240 help='The string name of the profile to be used. This determines '
240 help='The string name of the profile to be used. This determines '
241 'the name of the cluster dir as: cluster_<profile>. The default profile '
241 'the name of the cluster dir as: cluster_<profile>. The default profile '
242 'is named "default". The cluster directory is resolve this way '
242 'is named "default". The cluster directory is resolve this way '
243 'if the --cluster-dir option is not used.',
243 'if the --cluster-dir option is not used.',
244 default=NoConfigDefault,
244 default=NoConfigDefault,
245 metavar='Global.profile'
245 metavar='Global.profile'
246 )
246 )
247 self.parser.add_argument('--log-level',
247 self.parser.add_argument('--log-level',
248 dest="Global.log_level",type=int,
248 dest="Global.log_level",type=int,
249 help='Set the log level (0,10,20,30,40,50). Default is 30.',
249 help='Set the log level (0,10,20,30,40,50). Default is 30.',
250 default=NoConfigDefault,
250 default=NoConfigDefault,
251 metavar="Global.log_level"
251 metavar="Global.log_level"
252 )
252 )
253 self.parser.add_argument('--cluster-dir',
253 self.parser.add_argument('--cluster-dir',
254 dest='Global.cluster_dir',type=str,
254 dest='Global.cluster_dir',type=unicode,
255 help='Set the cluster dir. This overrides the logic used by the '
255 help='Set the cluster dir. This overrides the logic used by the '
256 '--profile option.',
256 '--profile option.',
257 default=NoConfigDefault,
257 default=NoConfigDefault,
258 metavar='Global.cluster_dir'
258 metavar='Global.cluster_dir'
259 )
259 )
260 self.parser.add_argument('--clean-logs',
260 self.parser.add_argument('--clean-logs',
261 dest='Global.clean_logs', action='store_true',
261 dest='Global.clean_logs', action='store_true',
262 help='Delete old log flies before starting.',
262 help='Delete old log flies before starting.',
263 default=NoConfigDefault
263 default=NoConfigDefault
264 )
264 )
265 self.parser.add_argument('--no-clean-logs',
265 self.parser.add_argument('--no-clean-logs',
266 dest='Global.clean_logs', action='store_false',
266 dest='Global.clean_logs', action='store_false',
267 help="Don't Delete old log flies before starting.",
267 help="Don't Delete old log flies before starting.",
268 default=NoConfigDefault
268 default=NoConfigDefault
269 )
269 )
270
270
271 class ApplicationWithClusterDir(Application):
271 class ApplicationWithClusterDir(Application):
272 """An application that puts everything into a cluster directory.
272 """An application that puts everything into a cluster directory.
273
273
274 Instead of looking for things in the ipython_dir, this type of application
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"
275 will use its own private directory called the "cluster directory"
276 for things like config files, log files, etc.
276 for things like config files, log files, etc.
277
277
278 The cluster directory is resolved as follows:
278 The cluster directory is resolved as follows:
279
279
280 * If the ``--cluster-dir`` option is given, it is used.
280 * If the ``--cluster-dir`` option is given, it is used.
281 * If ``--cluster-dir`` is not given, the application directory is
281 * If ``--cluster-dir`` is not given, the application directory is
282 resolve using the profile name as ``cluster_<profile>``. The search
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
283 path for this directory is then i) cwd if it is found there
284 and ii) in ipython_dir otherwise.
284 and ii) in ipython_dir otherwise.
285
285
286 The config file for the application is to be put in the cluster
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.
287 dir and named the value of the ``config_file_name`` class attribute.
288 """
288 """
289
289
290 auto_create_cluster_dir = True
290 auto_create_cluster_dir = True
291
291
292 def create_default_config(self):
292 def create_default_config(self):
293 super(ApplicationWithClusterDir, self).create_default_config()
293 super(ApplicationWithClusterDir, self).create_default_config()
294 self.default_config.Global.profile = 'default'
294 self.default_config.Global.profile = u'default'
295 self.default_config.Global.cluster_dir = ''
295 self.default_config.Global.cluster_dir = u''
296 self.default_config.Global.log_to_file = False
296 self.default_config.Global.log_to_file = False
297 self.default_config.Global.clean_logs = False
297 self.default_config.Global.clean_logs = False
298
298
299 def create_command_line_config(self):
299 def create_command_line_config(self):
300 """Create and return a command line config loader."""
300 """Create and return a command line config loader."""
301 return AppWithClusterDirArgParseConfigLoader(
301 return AppWithClusterDirArgParseConfigLoader(
302 description=self.description,
302 description=self.description,
303 version=release.version
303 version=release.version
304 )
304 )
305
305
306 def find_resources(self):
306 def find_resources(self):
307 """This resolves the cluster directory.
307 """This resolves the cluster directory.
308
308
309 This tries to find the cluster directory and if successful, it will
309 This tries to find the cluster directory and if successful, it will
310 have done:
310 have done:
311 * Sets ``self.cluster_dir_obj`` to the :class:`ClusterDir` object for
311 * Sets ``self.cluster_dir_obj`` to the :class:`ClusterDir` object for
312 the application.
312 the application.
313 * Sets ``self.cluster_dir`` attribute of the application and config
313 * Sets ``self.cluster_dir`` attribute of the application and config
314 objects.
314 objects.
315
315
316 The algorithm used for this is as follows:
316 The algorithm used for this is as follows:
317 1. Try ``Global.cluster_dir``.
317 1. Try ``Global.cluster_dir``.
318 2. Try using ``Global.profile``.
318 2. Try using ``Global.profile``.
319 3. If both of these fail and ``self.auto_create_cluster_dir`` is
319 3. If both of these fail and ``self.auto_create_cluster_dir`` is
320 ``True``, then create the new cluster dir in the IPython directory.
320 ``True``, then create the new cluster dir in the IPython directory.
321 4. If all fails, then raise :class:`ClusterDirError`.
321 4. If all fails, then raise :class:`ClusterDirError`.
322 """
322 """
323
323
324 try:
324 try:
325 cluster_dir = self.command_line_config.Global.cluster_dir
325 cluster_dir = self.command_line_config.Global.cluster_dir
326 except AttributeError:
326 except AttributeError:
327 cluster_dir = self.default_config.Global.cluster_dir
327 cluster_dir = self.default_config.Global.cluster_dir
328 cluster_dir = genutils.expand_path(cluster_dir)
328 cluster_dir = genutils.expand_path(cluster_dir)
329 try:
329 try:
330 self.cluster_dir_obj = ClusterDir.find_cluster_dir(cluster_dir)
330 self.cluster_dir_obj = ClusterDir.find_cluster_dir(cluster_dir)
331 except ClusterDirError:
331 except ClusterDirError:
332 pass
332 pass
333 else:
333 else:
334 self.log.info('Using existing cluster dir: %s' % \
334 self.log.info('Using existing cluster dir: %s' % \
335 self.cluster_dir_obj.location
335 self.cluster_dir_obj.location
336 )
336 )
337 self.finish_cluster_dir()
337 self.finish_cluster_dir()
338 return
338 return
339
339
340 try:
340 try:
341 self.profile = self.command_line_config.Global.profile
341 self.profile = self.command_line_config.Global.profile
342 except AttributeError:
342 except AttributeError:
343 self.profile = self.default_config.Global.profile
343 self.profile = self.default_config.Global.profile
344 try:
344 try:
345 self.cluster_dir_obj = ClusterDir.find_cluster_dir_by_profile(
345 self.cluster_dir_obj = ClusterDir.find_cluster_dir_by_profile(
346 self.ipython_dir, self.profile)
346 self.ipython_dir, self.profile)
347 except ClusterDirError:
347 except ClusterDirError:
348 pass
348 pass
349 else:
349 else:
350 self.log.info('Using existing cluster dir: %s' % \
350 self.log.info('Using existing cluster dir: %s' % \
351 self.cluster_dir_obj.location
351 self.cluster_dir_obj.location
352 )
352 )
353 self.finish_cluster_dir()
353 self.finish_cluster_dir()
354 return
354 return
355
355
356 if self.auto_create_cluster_dir:
356 if self.auto_create_cluster_dir:
357 self.cluster_dir_obj = ClusterDir.create_cluster_dir_by_profile(
357 self.cluster_dir_obj = ClusterDir.create_cluster_dir_by_profile(
358 self.ipython_dir, self.profile
358 self.ipython_dir, self.profile
359 )
359 )
360 self.log.info('Creating new cluster dir: %s' % \
360 self.log.info('Creating new cluster dir: %s' % \
361 self.cluster_dir_obj.location
361 self.cluster_dir_obj.location
362 )
362 )
363 self.finish_cluster_dir()
363 self.finish_cluster_dir()
364 else:
364 else:
365 raise ClusterDirError('Could not find a valid cluster directory.')
365 raise ClusterDirError('Could not find a valid cluster directory.')
366
366
367 def finish_cluster_dir(self):
367 def finish_cluster_dir(self):
368 # Set the cluster directory
368 # Set the cluster directory
369 self.cluster_dir = self.cluster_dir_obj.location
369 self.cluster_dir = self.cluster_dir_obj.location
370
370
371 # These have to be set because they could be different from the one
371 # These have to be set because they could be different from the one
372 # that we just computed. Because command line has the highest
372 # that we just computed. Because command line has the highest
373 # priority, this will always end up in the master_config.
373 # priority, this will always end up in the master_config.
374 self.default_config.Global.cluster_dir = self.cluster_dir
374 self.default_config.Global.cluster_dir = self.cluster_dir
375 self.command_line_config.Global.cluster_dir = self.cluster_dir
375 self.command_line_config.Global.cluster_dir = self.cluster_dir
376
376
377 # Set the search path to the cluster directory
377 # Set the search path to the cluster directory
378 self.config_file_paths = (self.cluster_dir,)
378 self.config_file_paths = (self.cluster_dir,)
379
379
380 def find_config_file_name(self):
380 def find_config_file_name(self):
381 """Find the config file name for this application."""
381 """Find the config file name for this application."""
382 # For this type of Application it should be set as a class attribute.
382 # For this type of Application it should be set as a class attribute.
383 if not hasattr(self, 'config_file_name'):
383 if not hasattr(self, 'config_file_name'):
384 self.log.critical("No config filename found")
384 self.log.critical("No config filename found")
385
385
386 def find_config_file_paths(self):
386 def find_config_file_paths(self):
387 # Set the search path to the cluster directory
387 # Set the search path to the cluster directory
388 self.config_file_paths = (self.cluster_dir,)
388 self.config_file_paths = (self.cluster_dir,)
389
389
390 def pre_construct(self):
390 def pre_construct(self):
391 # The log and security dirs were set earlier, but here we put them
391 # The log and security dirs were set earlier, but here we put them
392 # into the config and log them.
392 # into the config and log them.
393 config = self.master_config
393 config = self.master_config
394 sdir = self.cluster_dir_obj.security_dir
394 sdir = self.cluster_dir_obj.security_dir
395 self.security_dir = config.Global.security_dir = sdir
395 self.security_dir = config.Global.security_dir = sdir
396 ldir = self.cluster_dir_obj.log_dir
396 ldir = self.cluster_dir_obj.log_dir
397 self.log_dir = config.Global.log_dir = ldir
397 self.log_dir = config.Global.log_dir = ldir
398 pdir = self.cluster_dir_obj.pid_dir
398 pdir = self.cluster_dir_obj.pid_dir
399 self.pid_dir = config.Global.pid_dir = pdir
399 self.pid_dir = config.Global.pid_dir = pdir
400 self.log.info("Cluster directory set to: %s" % self.cluster_dir)
400 self.log.info("Cluster directory set to: %s" % self.cluster_dir)
401
401
402 def start_logging(self):
402 def start_logging(self):
403 # Remove old log files
403 # Remove old log files
404 if self.master_config.Global.clean_logs:
404 if self.master_config.Global.clean_logs:
405 log_dir = self.master_config.Global.log_dir
405 log_dir = self.master_config.Global.log_dir
406 for f in os.listdir(log_dir):
406 for f in os.listdir(log_dir):
407 if f.startswith(self.name + '-') and f.endswith('.log'):
407 if f.startswith(self.name + u'-') and f.endswith('.log'):
408 os.remove(os.path.join(log_dir, f))
408 os.remove(os.path.join(log_dir, f))
409 # Start logging to the new log file
409 # Start logging to the new log file
410 if self.master_config.Global.log_to_file:
410 if self.master_config.Global.log_to_file:
411 log_filename = self.name + '-' + str(os.getpid()) + '.log'
411 log_filename = self.name + u'-' + str(os.getpid()) + u'.log'
412 logfile = os.path.join(self.log_dir, log_filename)
412 logfile = os.path.join(self.log_dir, log_filename)
413 open_log_file = open(logfile, 'w')
413 open_log_file = open(logfile, 'w')
414 else:
414 else:
415 open_log_file = sys.stdout
415 open_log_file = sys.stdout
416 log.startLogging(open_log_file)
416 log.startLogging(open_log_file)
417
417
418 def write_pid_file(self, overwrite=False):
418 def write_pid_file(self, overwrite=False):
419 """Create a .pid file in the pid_dir with my pid.
419 """Create a .pid file in the pid_dir with my pid.
420
420
421 This must be called after pre_construct, which sets `self.pid_dir`.
421 This must be called after pre_construct, which sets `self.pid_dir`.
422 This raises :exc:`PIDFileError` if the pid file exists already.
422 This raises :exc:`PIDFileError` if the pid file exists already.
423 """
423 """
424 pid_file = os.path.join(self.pid_dir, self.name + '.pid')
424 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
425 if os.path.isfile(pid_file):
425 if os.path.isfile(pid_file):
426 pid = self.get_pid_from_file()
426 pid = self.get_pid_from_file()
427 if not overwrite:
427 if not overwrite:
428 raise PIDFileError(
428 raise PIDFileError(
429 'The pid file [%s] already exists. \nThis could mean that this '
429 'The pid file [%s] already exists. \nThis could mean that this '
430 'server is already running with [pid=%s].' % (pid_file, pid)
430 'server is already running with [pid=%s].' % (pid_file, pid)
431 )
431 )
432 with open(pid_file, 'w') as f:
432 with open(pid_file, 'w') as f:
433 self.log.info("Creating pid file: %s" % pid_file)
433 self.log.info("Creating pid file: %s" % pid_file)
434 f.write(repr(os.getpid())+'\n')
434 f.write(repr(os.getpid())+'\n')
435
435
436 def remove_pid_file(self):
436 def remove_pid_file(self):
437 """Remove the pid file.
437 """Remove the pid file.
438
438
439 This should be called at shutdown by registering a callback with
439 This should be called at shutdown by registering a callback with
440 :func:`reactor.addSystemEventTrigger`.
440 :func:`reactor.addSystemEventTrigger`.
441 """
441 """
442 pid_file = os.path.join(self.pid_dir, self.name + '.pid')
442 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
443 if os.path.isfile(pid_file):
443 if os.path.isfile(pid_file):
444 try:
444 try:
445 self.log.info("Removing pid file: %s" % pid_file)
445 self.log.info("Removing pid file: %s" % pid_file)
446 os.remove(pid_file)
446 os.remove(pid_file)
447 except:
447 except:
448 self.log.warn("Error removing the pid file: %s" % pid_file)
448 self.log.warn("Error removing the pid file: %s" % pid_file)
449 raise
449 raise
450
450
451 def get_pid_from_file(self):
451 def get_pid_from_file(self):
452 """Get the pid from the pid file.
452 """Get the pid from the pid file.
453
453
454 If the pid file doesn't exist a :exc:`PIDFileError` is raised.
454 If the pid file doesn't exist a :exc:`PIDFileError` is raised.
455 """
455 """
456 pid_file = os.path.join(self.pid_dir, self.name + '.pid')
456 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
457 if os.path.isfile(pid_file):
457 if os.path.isfile(pid_file):
458 with open(pid_file, 'r') as f:
458 with open(pid_file, 'r') as f:
459 pid = int(f.read().strip())
459 pid = int(f.read().strip())
460 return pid
460 return pid
461 else:
461 else:
462 raise PIDFileError('pid file not found: %s' % pid_file)
462 raise PIDFileError('pid file not found: %s' % pid_file)
463
463
464
464
@@ -1,403 +1,402 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The ipcluster application.
4 The ipcluster application.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # 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 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 import logging
18 import logging
19 import os
19 import os
20 import signal
20 import signal
21 import sys
21 import sys
22
22
23 if os.name=='posix':
23 if os.name=='posix':
24 from twisted.scripts._twistd_unix import daemonize
24 from twisted.scripts._twistd_unix import daemonize
25
25
26 from IPython.core import release
26 from IPython.core import release
27 from IPython.external import argparse
27 from IPython.external import argparse
28 from IPython.config.loader import ArgParseConfigLoader, NoConfigDefault
28 from IPython.config.loader import ArgParseConfigLoader, NoConfigDefault
29 from IPython.utils.importstring import import_item
29 from IPython.utils.importstring import import_item
30
30
31 from IPython.kernel.clusterdir import (
31 from IPython.kernel.clusterdir import (
32 ApplicationWithClusterDir, ClusterDirError, PIDFileError
32 ApplicationWithClusterDir, ClusterDirError, PIDFileError
33 )
33 )
34
34
35 from twisted.internet import reactor
35 from twisted.internet import reactor
36 from twisted.python import log
36 from twisted.python import log
37
37
38
38
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40 # The ipcluster application
40 # The ipcluster application
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42
42
43
43
44 # Exit codes for ipcluster
44 # Exit codes for ipcluster
45
45
46 # This will be the exit code if the ipcluster appears to be running because
46 # This will be the exit code if the ipcluster appears to be running because
47 # a .pid file exists
47 # a .pid file exists
48 ALREADY_STARTED = 10
48 ALREADY_STARTED = 10
49
49
50 # This will be the exit code if ipcluster stop is run, but there is not .pid
50 # This will be the exit code if ipcluster stop is run, but there is not .pid
51 # file to be found.
51 # file to be found.
52 ALREADY_STOPPED = 11
52 ALREADY_STOPPED = 11
53
53
54
54
55 class IPClusterCLLoader(ArgParseConfigLoader):
55 class IPClusterCLLoader(ArgParseConfigLoader):
56
56
57 def _add_arguments(self):
57 def _add_arguments(self):
58 # This has all the common options that all subcommands use
58 # This has all the common options that all subcommands use
59 parent_parser1 = argparse.ArgumentParser(add_help=False)
59 parent_parser1 = argparse.ArgumentParser(add_help=False)
60 parent_parser1.add_argument('--ipython-dir',
60 parent_parser1.add_argument('--ipython-dir',
61 dest='Global.ipython_dir',type=str,
61 dest='Global.ipython_dir',type=unicode,
62 help='Set to override default location of Global.ipython_dir.',
62 help='Set to override default location of Global.ipython_dir.',
63 default=NoConfigDefault,
63 default=NoConfigDefault,
64 metavar='Global.ipython_dir')
64 metavar='Global.ipython_dir')
65 parent_parser1.add_argument('--log-level',
65 parent_parser1.add_argument('--log-level',
66 dest="Global.log_level",type=int,
66 dest="Global.log_level",type=int,
67 help='Set the log level (0,10,20,30,40,50). Default is 30.',
67 help='Set the log level (0,10,20,30,40,50). Default is 30.',
68 default=NoConfigDefault,
68 default=NoConfigDefault,
69 metavar='Global.log_level')
69 metavar='Global.log_level')
70
70
71 # This has all the common options that other subcommands use
71 # This has all the common options that other subcommands use
72 parent_parser2 = argparse.ArgumentParser(add_help=False)
72 parent_parser2 = argparse.ArgumentParser(add_help=False)
73 parent_parser2.add_argument('-p','--profile',
73 parent_parser2.add_argument('-p','--profile',
74 dest='Global.profile',type=str,
74 dest='Global.profile',type=unicode,
75 default=NoConfigDefault,
75 default=NoConfigDefault,
76 help='The string name of the profile to be used. This determines '
76 help='The string name of the profile to be used. This determines '
77 'the name of the cluster dir as: cluster_<profile>. The default profile '
77 'the name of the cluster dir as: cluster_<profile>. The default profile '
78 'is named "default". The cluster directory is resolve this way '
78 'is named "default". The cluster directory is resolve this way '
79 'if the --cluster-dir option is not used.',
79 'if the --cluster-dir option is not used.',
80 default=NoConfigDefault,
80 default=NoConfigDefault,
81 metavar='Global.profile')
81 metavar='Global.profile')
82 parent_parser2.add_argument('--cluster-dir',
82 parent_parser2.add_argument('--cluster-dir',
83 dest='Global.cluster_dir',type=str,
83 dest='Global.cluster_dir',type=unicode,
84 default=NoConfigDefault,
84 default=NoConfigDefault,
85 help='Set the cluster dir. This overrides the logic used by the '
85 help='Set the cluster dir. This overrides the logic used by the '
86 '--profile option.',
86 '--profile option.',
87 default=NoConfigDefault,
87 default=NoConfigDefault,
88 metavar='Global.cluster_dir')
88 metavar='Global.cluster_dir')
89 parent_parser2.add_argument('--log-to-file',
89 parent_parser2.add_argument('--log-to-file',
90 action='store_true', dest='Global.log_to_file',
90 action='store_true', dest='Global.log_to_file',
91 default=NoConfigDefault,
91 default=NoConfigDefault,
92 help='Log to a file in the log directory (default is stdout)'
92 help='Log to a file in the log directory (default is stdout)'
93 )
93 )
94
94
95 subparsers = self.parser.add_subparsers(
95 subparsers = self.parser.add_subparsers(
96 dest='Global.subcommand',
96 dest='Global.subcommand',
97 title='ipcluster subcommands',
97 title='ipcluster subcommands',
98 description='ipcluster has a variety of subcommands. '
98 description='ipcluster has a variety of subcommands. '
99 'The general way of running ipcluster is "ipcluster <cmd> '
99 'The general way of running ipcluster is "ipcluster <cmd> '
100 ' [options]""',
100 ' [options]""',
101 help='For more help, type "ipcluster <cmd> -h"')
101 help='For more help, type "ipcluster <cmd> -h"')
102
102
103 parser_list = subparsers.add_parser(
103 parser_list = subparsers.add_parser(
104 'list',
104 'list',
105 help='List all clusters in cwd and ipython_dir.',
105 help='List all clusters in cwd and ipython_dir.',
106 parents=[parent_parser1]
106 parents=[parent_parser1]
107 )
107 )
108
108
109 parser_create = subparsers.add_parser(
109 parser_create = subparsers.add_parser(
110 'create',
110 'create',
111 help='Create a new cluster directory.',
111 help='Create a new cluster directory.',
112 parents=[parent_parser1, parent_parser2]
112 parents=[parent_parser1, parent_parser2]
113 )
113 )
114 parser_create.add_argument(
114 parser_create.add_argument(
115 '--reset-config',
115 '--reset-config',
116 dest='Global.reset_config', action='store_true',
116 dest='Global.reset_config', action='store_true',
117 default=NoConfigDefault,
117 default=NoConfigDefault,
118 help='Recopy the default config files to the cluster directory. '
118 help='Recopy the default config files to the cluster directory. '
119 'You will loose any modifications you have made to these files.'
119 'You will loose any modifications you have made to these files.'
120 )
120 )
121
121
122 parser_start = subparsers.add_parser(
122 parser_start = subparsers.add_parser(
123 'start',
123 'start',
124 help='Start a cluster.',
124 help='Start a cluster.',
125 parents=[parent_parser1, parent_parser2]
125 parents=[parent_parser1, parent_parser2]
126 )
126 )
127 parser_start.add_argument(
127 parser_start.add_argument(
128 '-n', '--number',
128 '-n', '--number',
129 type=int, dest='Global.n',
129 type=int, dest='Global.n',
130 default=NoConfigDefault,
130 default=NoConfigDefault,
131 help='The number of engines to start.',
131 help='The number of engines to start.',
132 metavar='Global.n'
132 metavar='Global.n'
133 )
133 )
134 parser_start.add_argument('--clean-logs',
134 parser_start.add_argument('--clean-logs',
135 dest='Global.clean_logs', action='store_true',
135 dest='Global.clean_logs', action='store_true',
136 help='Delete old log flies before starting.',
136 help='Delete old log flies before starting.',
137 default=NoConfigDefault
137 default=NoConfigDefault
138 )
138 )
139 parser_start.add_argument('--no-clean-logs',
139 parser_start.add_argument('--no-clean-logs',
140 dest='Global.clean_logs', action='store_false',
140 dest='Global.clean_logs', action='store_false',
141 help="Don't delete old log flies before starting.",
141 help="Don't delete old log flies before starting.",
142 default=NoConfigDefault
142 default=NoConfigDefault
143 )
143 )
144 parser_start.add_argument('--daemon',
144 parser_start.add_argument('--daemon',
145 dest='Global.daemonize', action='store_true',
145 dest='Global.daemonize', action='store_true',
146 help='Daemonize the ipcluster program. This implies --log-to-file',
146 help='Daemonize the ipcluster program. This implies --log-to-file',
147 default=NoConfigDefault
147 default=NoConfigDefault
148 )
148 )
149 parser_start.add_argument('--no-daemon',
149 parser_start.add_argument('--no-daemon',
150 dest='Global.daemonize', action='store_false',
150 dest='Global.daemonize', action='store_false',
151 help="Dont't daemonize the ipcluster program.",
151 help="Dont't daemonize the ipcluster program.",
152 default=NoConfigDefault
152 default=NoConfigDefault
153 )
153 )
154
154
155 parser_start = subparsers.add_parser(
155 parser_start = subparsers.add_parser(
156 'stop',
156 'stop',
157 help='Stop a cluster.',
157 help='Stop a cluster.',
158 parents=[parent_parser1, parent_parser2]
158 parents=[parent_parser1, parent_parser2]
159 )
159 )
160 parser_start.add_argument('--signal',
160 parser_start.add_argument('--signal',
161 dest='Global.signal', type=int,
161 dest='Global.signal', type=int,
162 help="The signal number to use in stopping the cluster (default=2).",
162 help="The signal number to use in stopping the cluster (default=2).",
163 metavar="Global.signal",
163 metavar="Global.signal",
164 default=NoConfigDefault
164 default=NoConfigDefault
165 )
165 )
166
166
167
167
168 default_config_file_name = 'ipcluster_config.py'
168 default_config_file_name = u'ipcluster_config.py'
169
169
170
170
171 class IPClusterApp(ApplicationWithClusterDir):
171 class IPClusterApp(ApplicationWithClusterDir):
172
172
173 name = 'ipcluster'
173 name = u'ipcluster'
174 description = 'Start an IPython cluster (controller and engines).'
174 description = 'Start an IPython cluster (controller and engines).'
175 config_file_name = default_config_file_name
175 config_file_name = default_config_file_name
176 default_log_level = logging.INFO
176 default_log_level = logging.INFO
177 auto_create_cluster_dir = False
177 auto_create_cluster_dir = False
178
178
179 def create_default_config(self):
179 def create_default_config(self):
180 super(IPClusterApp, self).create_default_config()
180 super(IPClusterApp, self).create_default_config()
181 self.default_config.Global.controller_launcher = \
181 self.default_config.Global.controller_launcher = \
182 'IPython.kernel.launcher.LocalControllerLauncher'
182 'IPython.kernel.launcher.LocalControllerLauncher'
183 self.default_config.Global.engine_launcher = \
183 self.default_config.Global.engine_launcher = \
184 'IPython.kernel.launcher.LocalEngineSetLauncher'
184 'IPython.kernel.launcher.LocalEngineSetLauncher'
185 self.default_config.Global.n = 2
185 self.default_config.Global.n = 2
186 self.default_config.Global.reset_config = False
186 self.default_config.Global.reset_config = False
187 self.default_config.Global.clean_logs = True
187 self.default_config.Global.clean_logs = True
188 self.default_config.Global.signal = 2
188 self.default_config.Global.signal = 2
189 self.default_config.Global.daemonize = False
189 self.default_config.Global.daemonize = False
190
190
191 def create_command_line_config(self):
191 def create_command_line_config(self):
192 """Create and return a command line config loader."""
192 """Create and return a command line config loader."""
193 return IPClusterCLLoader(
193 return IPClusterCLLoader(
194 description=self.description,
194 description=self.description,
195 version=release.version
195 version=release.version
196 )
196 )
197
197
198 def find_resources(self):
198 def find_resources(self):
199 subcommand = self.command_line_config.Global.subcommand
199 subcommand = self.command_line_config.Global.subcommand
200 if subcommand=='list':
200 if subcommand=='list':
201 self.list_cluster_dirs()
201 self.list_cluster_dirs()
202 # Exit immediately because there is nothing left to do.
202 # Exit immediately because there is nothing left to do.
203 self.exit()
203 self.exit()
204 elif subcommand=='create':
204 elif subcommand=='create':
205 self.auto_create_cluster_dir = True
205 self.auto_create_cluster_dir = True
206 super(IPClusterApp, self).find_resources()
206 super(IPClusterApp, self).find_resources()
207 elif subcommand=='start' or subcommand=='stop':
207 elif subcommand=='start' or subcommand=='stop':
208 self.auto_create_cluster_dir = False
208 self.auto_create_cluster_dir = False
209 try:
209 try:
210 super(IPClusterApp, self).find_resources()
210 super(IPClusterApp, self).find_resources()
211 except ClusterDirError:
211 except ClusterDirError:
212 raise ClusterDirError(
212 raise ClusterDirError(
213 "Could not find a cluster directory. A cluster dir must "
213 "Could not find a cluster directory. A cluster dir must "
214 "be created before running 'ipcluster start'. Do "
214 "be created before running 'ipcluster start'. Do "
215 "'ipcluster create -h' or 'ipcluster list -h' for more "
215 "'ipcluster create -h' or 'ipcluster list -h' for more "
216 "information about creating and listing cluster dirs."
216 "information about creating and listing cluster dirs."
217 )
217 )
218
218
219 def list_cluster_dirs(self):
219 def list_cluster_dirs(self):
220 # Find the search paths
220 # Find the search paths
221 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
221 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
222 if cluster_dir_paths:
222 if cluster_dir_paths:
223 cluster_dir_paths = cluster_dir_paths.split(':')
223 cluster_dir_paths = cluster_dir_paths.split(':')
224 else:
224 else:
225 cluster_dir_paths = []
225 cluster_dir_paths = []
226 try:
226 try:
227 ipython_dir = self.command_line_config.Global.ipython_dir
227 ipython_dir = self.command_line_config.Global.ipython_dir
228 except AttributeError:
228 except AttributeError:
229 ipython_dir = self.default_config.Global.ipython_dir
229 ipython_dir = self.default_config.Global.ipython_dir
230 paths = [os.getcwd(), ipython_dir] + \
230 paths = [os.getcwd(), ipython_dir] + \
231 cluster_dir_paths
231 cluster_dir_paths
232 paths = list(set(paths))
232 paths = list(set(paths))
233
233
234 self.log.info('Searching for cluster dirs in paths: %r' % paths)
234 self.log.info('Searching for cluster dirs in paths: %r' % paths)
235 for path in paths:
235 for path in paths:
236 files = os.listdir(path)
236 files = os.listdir(path)
237 for f in files:
237 for f in files:
238 full_path = os.path.join(path, f)
238 full_path = os.path.join(path, f)
239 if os.path.isdir(full_path) and f.startswith('cluster_'):
239 if os.path.isdir(full_path) and f.startswith('cluster_'):
240 profile = full_path.split('_')[-1]
240 profile = full_path.split('_')[-1]
241 start_cmd = '"ipcluster start -n 4 -p %s"' % profile
241 start_cmd = '"ipcluster start -n 4 -p %s"' % profile
242 print start_cmd + " ==> " + full_path
242 print start_cmd + " ==> " + full_path
243
243
244 def pre_construct(self):
244 def pre_construct(self):
245 super(IPClusterApp, self).pre_construct()
245 super(IPClusterApp, self).pre_construct()
246 config = self.master_config
246 config = self.master_config
247 try:
247 try:
248 daemon = config.Global.daemonize
248 daemon = config.Global.daemonize
249 if daemon:
249 if daemon:
250 config.Global.log_to_file = True
250 config.Global.log_to_file = True
251 except AttributeError:
251 except AttributeError:
252 pass
252 pass
253
253
254 def construct(self):
254 def construct(self):
255 config = self.master_config
255 config = self.master_config
256 if config.Global.subcommand=='list':
256 if config.Global.subcommand=='list':
257 pass
257 pass
258 elif config.Global.subcommand=='create':
258 elif config.Global.subcommand=='create':
259 self.log.info('Copying default config files to cluster directory '
259 self.log.info('Copying default config files to cluster directory '
260 '[overwrite=%r]' % (config.Global.reset_config,))
260 '[overwrite=%r]' % (config.Global.reset_config,))
261 self.cluster_dir_obj.copy_all_config_files(overwrite=config.Global.reset_config)
261 self.cluster_dir_obj.copy_all_config_files(overwrite=config.Global.reset_config)
262 elif config.Global.subcommand=='start':
262 elif config.Global.subcommand=='start':
263 self.start_logging()
263 self.start_logging()
264 reactor.callWhenRunning(self.start_launchers)
264 reactor.callWhenRunning(self.start_launchers)
265
265
266 def start_launchers(self):
266 def start_launchers(self):
267 config = self.master_config
267 config = self.master_config
268
268
269 # Create the launchers
269 # Create the launchers
270 el_class = import_item(config.Global.engine_launcher)
270 el_class = import_item(config.Global.engine_launcher)
271 self.engine_launcher = el_class(
271 self.engine_launcher = el_class(
272 self.cluster_dir, config=config
272 self.cluster_dir, config=config
273 )
273 )
274 cl_class = import_item(config.Global.controller_launcher)
274 cl_class = import_item(config.Global.controller_launcher)
275 self.controller_launcher = cl_class(
275 self.controller_launcher = cl_class(
276 self.cluster_dir, config=config
276 self.cluster_dir, config=config
277 )
277 )
278
278
279 # Setup signals
279 # Setup signals
280 signal.signal(signal.SIGINT, self.stop_launchers)
280 signal.signal(signal.SIGINT, self.stop_launchers)
281 # signal.signal(signal.SIGKILL, self.stop_launchers)
282
281
283 # Setup the observing of stopping
282 # Setup the observing of stopping
284 d1 = self.controller_launcher.observe_stop()
283 d1 = self.controller_launcher.observe_stop()
285 d1.addCallback(self.stop_engines)
284 d1.addCallback(self.stop_engines)
286 d1.addErrback(self.err_and_stop)
285 d1.addErrback(self.err_and_stop)
287 # If this triggers, just let them die
286 # If this triggers, just let them die
288 # d2 = self.engine_launcher.observe_stop()
287 # d2 = self.engine_launcher.observe_stop()
289
288
290 # Start the controller and engines
289 # Start the controller and engines
291 d = self.controller_launcher.start(
290 d = self.controller_launcher.start(
292 profile=None, cluster_dir=config.Global.cluster_dir
291 profile=None, cluster_dir=config.Global.cluster_dir
293 )
292 )
294 d.addCallback(lambda _: self.start_engines())
293 d.addCallback(lambda _: self.start_engines())
295 d.addErrback(self.err_and_stop)
294 d.addErrback(self.err_and_stop)
296
295
297 def err_and_stop(self, f):
296 def err_and_stop(self, f):
298 log.msg('Unexpected error in ipcluster:')
297 log.msg('Unexpected error in ipcluster:')
299 log.err(f)
298 log.err(f)
300 reactor.stop()
299 reactor.stop()
301
300
302 def stop_engines(self, r):
301 def stop_engines(self, r):
303 return self.engine_launcher.stop()
302 return self.engine_launcher.stop()
304
303
305 def start_engines(self):
304 def start_engines(self):
306 config = self.master_config
305 config = self.master_config
307 d = self.engine_launcher.start(
306 d = self.engine_launcher.start(
308 config.Global.n,
307 config.Global.n,
309 profile=None, cluster_dir=config.Global.cluster_dir
308 profile=None, cluster_dir=config.Global.cluster_dir
310 )
309 )
311 return d
310 return d
312
311
313 def stop_launchers(self, signum, frame):
312 def stop_launchers(self, signum, frame):
314 log.msg("Stopping cluster")
313 log.msg("Stopping cluster")
315 d1 = self.engine_launcher.stop()
314 d1 = self.engine_launcher.stop()
316 d2 = self.controller_launcher.stop()
315 d2 = self.controller_launcher.stop()
317 # d1.addCallback(lambda _: self.controller_launcher.stop)
316 # d1.addCallback(lambda _: self.controller_launcher.stop)
318 d1.addErrback(self.err_and_stop)
317 d1.addErrback(self.err_and_stop)
319 d2.addErrback(self.err_and_stop)
318 d2.addErrback(self.err_and_stop)
320 reactor.callLater(2.0, reactor.stop)
319 reactor.callLater(2.0, reactor.stop)
321
320
322 def start_logging(self):
321 def start_logging(self):
323 # Remove old log files
322 # Remove old log files
324 if self.master_config.Global.clean_logs:
323 if self.master_config.Global.clean_logs:
325 log_dir = self.master_config.Global.log_dir
324 log_dir = self.master_config.Global.log_dir
326 for f in os.listdir(log_dir):
325 for f in os.listdir(log_dir):
327 if f.startswith('ipengine' + '-') and f.endswith('.log'):
326 if f.startswith('ipengine' + '-') and f.endswith('.log'):
328 os.remove(os.path.join(log_dir, f))
327 os.remove(os.path.join(log_dir, f))
329 for f in os.listdir(log_dir):
328 for f in os.listdir(log_dir):
330 if f.startswith('ipcontroller' + '-') and f.endswith('.log'):
329 if f.startswith('ipcontroller' + '-') and f.endswith('.log'):
331 os.remove(os.path.join(log_dir, f))
330 os.remove(os.path.join(log_dir, f))
332 super(IPClusterApp, self).start_logging()
331 super(IPClusterApp, self).start_logging()
333
332
334 def start_app(self):
333 def start_app(self):
335 """Start the application, depending on what subcommand is used."""
334 """Start the application, depending on what subcommand is used."""
336 subcmd = self.master_config.Global.subcommand
335 subcmd = self.master_config.Global.subcommand
337 if subcmd=='create' or subcmd=='list':
336 if subcmd=='create' or subcmd=='list':
338 return
337 return
339 elif subcmd=='start':
338 elif subcmd=='start':
340 self.start_app_start()
339 self.start_app_start()
341 elif subcmd=='stop':
340 elif subcmd=='stop':
342 self.start_app_stop()
341 self.start_app_stop()
343
342
344 def start_app_start(self):
343 def start_app_start(self):
345 """Start the app for the start subcommand."""
344 """Start the app for the start subcommand."""
346 config = self.master_config
345 config = self.master_config
347 # First see if the cluster is already running
346 # First see if the cluster is already running
348 try:
347 try:
349 pid = self.get_pid_from_file()
348 pid = self.get_pid_from_file()
350 except PIDFileError:
349 except PIDFileError:
351 pass
350 pass
352 else:
351 else:
353 self.log.critical(
352 self.log.critical(
354 'Cluster is already running with [pid=%s]. '
353 'Cluster is already running with [pid=%s]. '
355 'use "ipcluster stop" to stop the cluster.' % pid
354 'use "ipcluster stop" to stop the cluster.' % pid
356 )
355 )
357 # Here I exit with a unusual exit status that other processes
356 # Here I exit with a unusual exit status that other processes
358 # can watch for to learn how I existed.
357 # can watch for to learn how I existed.
359 self.exit(ALREADY_STARTED)
358 self.exit(ALREADY_STARTED)
360
359
361 # Now log and daemonize
360 # Now log and daemonize
362 self.log.info(
361 self.log.info(
363 'Starting ipcluster with [daemon=%r]' % config.Global.daemonize
362 'Starting ipcluster with [daemon=%r]' % config.Global.daemonize
364 )
363 )
365 if config.Global.daemonize:
364 if config.Global.daemonize:
366 if os.name=='posix':
365 if os.name=='posix':
367 daemonize()
366 daemonize()
368
367
369 # Now write the new pid file AFTER our new forked pid is active.
368 # Now write the new pid file AFTER our new forked pid is active.
370 self.write_pid_file()
369 self.write_pid_file()
371 # cd to the cluster_dir as our working directory.
370 # cd to the cluster_dir as our working directory.
372 os.chdir(config.Global.cluster_dir)
371 os.chdir(config.Global.cluster_dir)
373 reactor.addSystemEventTrigger('during','shutdown', self.remove_pid_file)
372 reactor.addSystemEventTrigger('during','shutdown', self.remove_pid_file)
374 reactor.run()
373 reactor.run()
375
374
376 def start_app_stop(self):
375 def start_app_stop(self):
377 """Start the app for the stop subcommand."""
376 """Start the app for the stop subcommand."""
378 config = self.master_config
377 config = self.master_config
379 try:
378 try:
380 pid = self.get_pid_from_file()
379 pid = self.get_pid_from_file()
381 except PIDFileError:
380 except PIDFileError:
382 self.log.critical(
381 self.log.critical(
383 'Problem reading pid file, cluster is probably not running.'
382 'Problem reading pid file, cluster is probably not running.'
384 )
383 )
385 # Here I exit with a unusual exit status that other processes
384 # Here I exit with a unusual exit status that other processes
386 # can watch for to learn how I existed.
385 # can watch for to learn how I existed.
387 self.exit(ALREADY_STOPPED)
386 self.exit(ALREADY_STOPPED)
388 sig = config.Global.signal
387 sig = config.Global.signal
389 self.log.info(
388 self.log.info(
390 "Stopping cluster [pid=%r] with [signal=%r]" % (pid, sig)
389 "Stopping cluster [pid=%r] with [signal=%r]" % (pid, sig)
391 )
390 )
392 os.kill(pid, sig)
391 os.kill(pid, sig)
393
392
394
393
395 def launch_new_instance():
394 def launch_new_instance():
396 """Create and run the IPython cluster."""
395 """Create and run the IPython cluster."""
397 app = IPClusterApp()
396 app = IPClusterApp()
398 app.start()
397 app.start()
399
398
400
399
401 if __name__ == '__main__':
400 if __name__ == '__main__':
402 launch_new_instance()
401 launch_new_instance()
403
402
@@ -1,268 +1,268 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The IPython controller application.
4 The IPython controller application.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # 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 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 from __future__ import with_statement
18 from __future__ import with_statement
19
19
20 import copy
20 import copy
21 import os
21 import os
22 import sys
22 import sys
23
23
24 from twisted.application import service
24 from twisted.application import service
25 from twisted.internet import reactor
25 from twisted.internet import reactor
26 from twisted.python import log
26 from twisted.python import log
27
27
28 from IPython.config.loader import Config, NoConfigDefault
28 from IPython.config.loader import Config, NoConfigDefault
29
29
30 from IPython.kernel.clusterdir import (
30 from IPython.kernel.clusterdir import (
31 ApplicationWithClusterDir,
31 ApplicationWithClusterDir,
32 AppWithClusterDirArgParseConfigLoader
32 AppWithClusterDirArgParseConfigLoader
33 )
33 )
34
34
35 from IPython.core import release
35 from IPython.core import release
36
36
37 from IPython.utils.traitlets import Str, Instance
37 from IPython.utils.traitlets import Str, Instance
38
38
39 from IPython.kernel import controllerservice
39 from IPython.kernel import controllerservice
40
40
41 from IPython.kernel.fcutil import FCServiceFactory
41 from IPython.kernel.fcutil import FCServiceFactory
42
42
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44 # Default interfaces
44 # Default interfaces
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47
47
48 # The default client interfaces for FCClientServiceFactory.interfaces
48 # The default client interfaces for FCClientServiceFactory.interfaces
49 default_client_interfaces = Config()
49 default_client_interfaces = Config()
50 default_client_interfaces.Task.interface_chain = [
50 default_client_interfaces.Task.interface_chain = [
51 'IPython.kernel.task.ITaskController',
51 'IPython.kernel.task.ITaskController',
52 'IPython.kernel.taskfc.IFCTaskController'
52 'IPython.kernel.taskfc.IFCTaskController'
53 ]
53 ]
54
54
55 default_client_interfaces.Task.furl_file = 'ipcontroller-tc.furl'
55 default_client_interfaces.Task.furl_file = 'ipcontroller-tc.furl'
56
56
57 default_client_interfaces.MultiEngine.interface_chain = [
57 default_client_interfaces.MultiEngine.interface_chain = [
58 'IPython.kernel.multiengine.IMultiEngine',
58 'IPython.kernel.multiengine.IMultiEngine',
59 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine'
59 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine'
60 ]
60 ]
61
61
62 default_client_interfaces.MultiEngine.furl_file = 'ipcontroller-mec.furl'
62 default_client_interfaces.MultiEngine.furl_file = u'ipcontroller-mec.furl'
63
63
64 # Make this a dict we can pass to Config.__init__ for the default
64 # Make this a dict we can pass to Config.__init__ for the default
65 default_client_interfaces = dict(copy.deepcopy(default_client_interfaces.items()))
65 default_client_interfaces = dict(copy.deepcopy(default_client_interfaces.items()))
66
66
67
67
68
68
69 # The default engine interfaces for FCEngineServiceFactory.interfaces
69 # The default engine interfaces for FCEngineServiceFactory.interfaces
70 default_engine_interfaces = Config()
70 default_engine_interfaces = Config()
71 default_engine_interfaces.Default.interface_chain = [
71 default_engine_interfaces.Default.interface_chain = [
72 'IPython.kernel.enginefc.IFCControllerBase'
72 'IPython.kernel.enginefc.IFCControllerBase'
73 ]
73 ]
74
74
75 default_engine_interfaces.Default.furl_file = 'ipcontroller-engine.furl'
75 default_engine_interfaces.Default.furl_file = u'ipcontroller-engine.furl'
76
76
77 # Make this a dict we can pass to Config.__init__ for the default
77 # Make this a dict we can pass to Config.__init__ for the default
78 default_engine_interfaces = dict(copy.deepcopy(default_engine_interfaces.items()))
78 default_engine_interfaces = dict(copy.deepcopy(default_engine_interfaces.items()))
79
79
80
80
81 #-----------------------------------------------------------------------------
81 #-----------------------------------------------------------------------------
82 # Service factories
82 # Service factories
83 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
84
84
85
85
86 class FCClientServiceFactory(FCServiceFactory):
86 class FCClientServiceFactory(FCServiceFactory):
87 """A Foolscap implementation of the client services."""
87 """A Foolscap implementation of the client services."""
88
88
89 cert_file = Str('ipcontroller-client.pem', config=True)
89 cert_file = Unicode(u'ipcontroller-client.pem', config=True)
90 interfaces = Instance(klass=Config, kw=default_client_interfaces,
90 interfaces = Instance(klass=Config, kw=default_client_interfaces,
91 allow_none=False, config=True)
91 allow_none=False, config=True)
92
92
93
93
94 class FCEngineServiceFactory(FCServiceFactory):
94 class FCEngineServiceFactory(FCServiceFactory):
95 """A Foolscap implementation of the engine services."""
95 """A Foolscap implementation of the engine services."""
96
96
97 cert_file = Str('ipcontroller-engine.pem', config=True)
97 cert_file = Unicode(u'ipcontroller-engine.pem', config=True)
98 interfaces = Instance(klass=dict, kw=default_engine_interfaces,
98 interfaces = Instance(klass=dict, kw=default_engine_interfaces,
99 allow_none=False, config=True)
99 allow_none=False, config=True)
100
100
101
101
102 #-----------------------------------------------------------------------------
102 #-----------------------------------------------------------------------------
103 # The main application
103 # The main application
104 #-----------------------------------------------------------------------------
104 #-----------------------------------------------------------------------------
105
105
106
106
107 cl_args = (
107 cl_args = (
108 # Client config
108 # Client config
109 (('--client-ip',), dict(
109 (('--client-ip',), dict(
110 type=str, dest='FCClientServiceFactory.ip', default=NoConfigDefault,
110 type=str, dest='FCClientServiceFactory.ip', default=NoConfigDefault,
111 help='The IP address or hostname the controller will listen on for '
111 help='The IP address or hostname the controller will listen on for '
112 'client connections.',
112 'client connections.',
113 metavar='FCClientServiceFactory.ip')
113 metavar='FCClientServiceFactory.ip')
114 ),
114 ),
115 (('--client-port',), dict(
115 (('--client-port',), dict(
116 type=int, dest='FCClientServiceFactory.port', default=NoConfigDefault,
116 type=int, dest='FCClientServiceFactory.port', default=NoConfigDefault,
117 help='The port the controller will listen on for client connections. '
117 help='The port the controller will listen on for client connections. '
118 'The default is to use 0, which will autoselect an open port.',
118 'The default is to use 0, which will autoselect an open port.',
119 metavar='FCClientServiceFactory.port')
119 metavar='FCClientServiceFactory.port')
120 ),
120 ),
121 (('--client-location',), dict(
121 (('--client-location',), dict(
122 type=str, dest='FCClientServiceFactory.location', default=NoConfigDefault,
122 type=str, dest='FCClientServiceFactory.location', default=NoConfigDefault,
123 help='The hostname or IP that clients should connect to. This does '
123 help='The hostname or IP that clients should connect to. This does '
124 'not control which interface the controller listens on. Instead, this '
124 'not control which interface the controller listens on. Instead, this '
125 'determines the hostname/IP that is listed in the FURL, which is how '
125 'determines the hostname/IP that is listed in the FURL, which is how '
126 'clients know where to connect. Useful if the controller is listening '
126 'clients know where to connect. Useful if the controller is listening '
127 'on multiple interfaces.',
127 'on multiple interfaces.',
128 metavar='FCClientServiceFactory.location')
128 metavar='FCClientServiceFactory.location')
129 ),
129 ),
130 # Engine config
130 # Engine config
131 (('--engine-ip',), dict(
131 (('--engine-ip',), dict(
132 type=str, dest='FCEngineServiceFactory.ip', default=NoConfigDefault,
132 type=str, dest='FCEngineServiceFactory.ip', default=NoConfigDefault,
133 help='The IP address or hostname the controller will listen on for '
133 help='The IP address or hostname the controller will listen on for '
134 'engine connections.',
134 'engine connections.',
135 metavar='FCEngineServiceFactory.ip')
135 metavar='FCEngineServiceFactory.ip')
136 ),
136 ),
137 (('--engine-port',), dict(
137 (('--engine-port',), dict(
138 type=int, dest='FCEngineServiceFactory.port', default=NoConfigDefault,
138 type=int, dest='FCEngineServiceFactory.port', default=NoConfigDefault,
139 help='The port the controller will listen on for engine connections. '
139 help='The port the controller will listen on for engine connections. '
140 'The default is to use 0, which will autoselect an open port.',
140 'The default is to use 0, which will autoselect an open port.',
141 metavar='FCEngineServiceFactory.port')
141 metavar='FCEngineServiceFactory.port')
142 ),
142 ),
143 (('--engine-location',), dict(
143 (('--engine-location',), dict(
144 type=str, dest='FCEngineServiceFactory.location', default=NoConfigDefault,
144 type=str, dest='FCEngineServiceFactory.location', default=NoConfigDefault,
145 help='The hostname or IP that engines should connect to. This does '
145 help='The hostname or IP that engines should connect to. This does '
146 'not control which interface the controller listens on. Instead, this '
146 'not control which interface the controller listens on. Instead, this '
147 'determines the hostname/IP that is listed in the FURL, which is how '
147 'determines the hostname/IP that is listed in the FURL, which is how '
148 'engines know where to connect. Useful if the controller is listening '
148 'engines know where to connect. Useful if the controller is listening '
149 'on multiple interfaces.',
149 'on multiple interfaces.',
150 metavar='FCEngineServiceFactory.location')
150 metavar='FCEngineServiceFactory.location')
151 ),
151 ),
152 # Global config
152 # Global config
153 (('--log-to-file',), dict(
153 (('--log-to-file',), dict(
154 action='store_true', dest='Global.log_to_file', default=NoConfigDefault,
154 action='store_true', dest='Global.log_to_file', default=NoConfigDefault,
155 help='Log to a file in the log directory (default is stdout)')
155 help='Log to a file in the log directory (default is stdout)')
156 ),
156 ),
157 (('-r','--reuse-furls'), dict(
157 (('-r','--reuse-furls'), dict(
158 action='store_true', dest='Global.reuse_furls', default=NoConfigDefault,
158 action='store_true', dest='Global.reuse_furls', default=NoConfigDefault,
159 help='Try to reuse all FURL files. If this is not set all FURL files '
159 help='Try to reuse all FURL files. If this is not set all FURL files '
160 'are deleted before the controller starts. This must be set if '
160 'are deleted before the controller starts. This must be set if '
161 'specific ports are specified by --engine-port or --client-port.')
161 'specific ports are specified by --engine-port or --client-port.')
162 ),
162 ),
163 (('--no-secure',), dict(
163 (('--no-secure',), dict(
164 action='store_false', dest='Global.secure', default=NoConfigDefault,
164 action='store_false', dest='Global.secure', default=NoConfigDefault,
165 help='Turn off SSL encryption for all connections.')
165 help='Turn off SSL encryption for all connections.')
166 ),
166 ),
167 (('--secure',), dict(
167 (('--secure',), dict(
168 action='store_true', dest='Global.secure', default=NoConfigDefault,
168 action='store_true', dest='Global.secure', default=NoConfigDefault,
169 help='Turn off SSL encryption for all connections.')
169 help='Turn off SSL encryption for all connections.')
170 )
170 )
171 )
171 )
172
172
173
173
174 class IPControllerAppCLConfigLoader(AppWithClusterDirArgParseConfigLoader):
174 class IPControllerAppCLConfigLoader(AppWithClusterDirArgParseConfigLoader):
175
175
176 arguments = cl_args
176 arguments = cl_args
177
177
178
178
179 default_config_file_name = 'ipcontroller_config.py'
179 default_config_file_name = u'ipcontroller_config.py'
180
180
181
181
182 class IPControllerApp(ApplicationWithClusterDir):
182 class IPControllerApp(ApplicationWithClusterDir):
183
183
184 name = 'ipcontroller'
184 name = u'ipcontroller'
185 description = 'Start the IPython controller for parallel computing.'
185 description = 'Start the IPython controller for parallel computing.'
186 config_file_name = default_config_file_name
186 config_file_name = default_config_file_name
187 auto_create_cluster_dir = True
187 auto_create_cluster_dir = True
188
188
189 def create_default_config(self):
189 def create_default_config(self):
190 super(IPControllerApp, self).create_default_config()
190 super(IPControllerApp, self).create_default_config()
191 self.default_config.Global.reuse_furls = False
191 self.default_config.Global.reuse_furls = False
192 self.default_config.Global.secure = True
192 self.default_config.Global.secure = True
193 self.default_config.Global.import_statements = []
193 self.default_config.Global.import_statements = []
194 self.default_config.Global.clean_logs = True
194 self.default_config.Global.clean_logs = True
195
195
196 def create_command_line_config(self):
196 def create_command_line_config(self):
197 """Create and return a command line config loader."""
197 """Create and return a command line config loader."""
198 return IPControllerAppCLConfigLoader(
198 return IPControllerAppCLConfigLoader(
199 description=self.description,
199 description=self.description,
200 version=release.version
200 version=release.version
201 )
201 )
202
202
203 def post_load_command_line_config(self):
203 def post_load_command_line_config(self):
204 # Now setup reuse_furls
204 # Now setup reuse_furls
205 c = self.command_line_config
205 c = self.command_line_config
206 if hasattr(c.Global, 'reuse_furls'):
206 if hasattr(c.Global, 'reuse_furls'):
207 c.FCClientServiceFactory.reuse_furls = c.Global.reuse_furls
207 c.FCClientServiceFactory.reuse_furls = c.Global.reuse_furls
208 c.FCEngineServiceFactory.reuse_furls = c.Global.reuse_furls
208 c.FCEngineServiceFactory.reuse_furls = c.Global.reuse_furls
209 del c.Global.reuse_furls
209 del c.Global.reuse_furls
210 if hasattr(c.Global, 'secure'):
210 if hasattr(c.Global, 'secure'):
211 c.FCClientServiceFactory.secure = c.Global.secure
211 c.FCClientServiceFactory.secure = c.Global.secure
212 c.FCEngineServiceFactory.secure = c.Global.secure
212 c.FCEngineServiceFactory.secure = c.Global.secure
213 del c.Global.secure
213 del c.Global.secure
214
214
215 def construct(self):
215 def construct(self):
216 # I am a little hesitant to put these into InteractiveShell itself.
216 # I am a little hesitant to put these into InteractiveShell itself.
217 # But that might be the place for them
217 # But that might be the place for them
218 sys.path.insert(0, '')
218 sys.path.insert(0, '')
219
219
220 self.start_logging()
220 self.start_logging()
221 self.import_statements()
221 self.import_statements()
222
222
223 # Create the service hierarchy
223 # Create the service hierarchy
224 self.main_service = service.MultiService()
224 self.main_service = service.MultiService()
225 # The controller service
225 # The controller service
226 controller_service = controllerservice.ControllerService()
226 controller_service = controllerservice.ControllerService()
227 controller_service.setServiceParent(self.main_service)
227 controller_service.setServiceParent(self.main_service)
228 # The client tub and all its refereceables
228 # The client tub and all its refereceables
229 csfactory = FCClientServiceFactory(self.master_config, controller_service)
229 csfactory = FCClientServiceFactory(self.master_config, controller_service)
230 client_service = csfactory.create()
230 client_service = csfactory.create()
231 client_service.setServiceParent(self.main_service)
231 client_service.setServiceParent(self.main_service)
232 # The engine tub
232 # The engine tub
233 esfactory = FCEngineServiceFactory(self.master_config, controller_service)
233 esfactory = FCEngineServiceFactory(self.master_config, controller_service)
234 engine_service = esfactory.create()
234 engine_service = esfactory.create()
235 engine_service.setServiceParent(self.main_service)
235 engine_service.setServiceParent(self.main_service)
236
236
237 def import_statements(self):
237 def import_statements(self):
238 statements = self.master_config.Global.import_statements
238 statements = self.master_config.Global.import_statements
239 for s in statements:
239 for s in statements:
240 try:
240 try:
241 log.msg("Executing statement: '%s'" % s)
241 log.msg("Executing statement: '%s'" % s)
242 exec s in globals(), locals()
242 exec s in globals(), locals()
243 except:
243 except:
244 log.msg("Error running statement: %s" % s)
244 log.msg("Error running statement: %s" % s)
245
245
246 def start_app(self):
246 def start_app(self):
247 # Start the controller service.
247 # Start the controller service.
248 self.main_service.startService()
248 self.main_service.startService()
249 # Write the .pid file overwriting old ones. This allow multiple
249 # Write the .pid file overwriting old ones. This allow multiple
250 # controllers to clober each other. But Windows is not cleaning
250 # controllers to clober each other. But Windows is not cleaning
251 # these up properly.
251 # these up properly.
252 self.write_pid_file(overwrite=True)
252 self.write_pid_file(overwrite=True)
253 # cd to the cluster_dir as our working directory.
253 # cd to the cluster_dir as our working directory.
254 os.chdir(self.master_config.Global.cluster_dir)
254 os.chdir(self.master_config.Global.cluster_dir)
255 # Add a trigger to delete the .pid file upon shutting down.
255 # Add a trigger to delete the .pid file upon shutting down.
256 reactor.addSystemEventTrigger('during','shutdown', self.remove_pid_file)
256 reactor.addSystemEventTrigger('during','shutdown', self.remove_pid_file)
257 reactor.run()
257 reactor.run()
258
258
259
259
260 def launch_new_instance():
260 def launch_new_instance():
261 """Create and run the IPython controller"""
261 """Create and run the IPython controller"""
262 app = IPControllerApp()
262 app = IPControllerApp()
263 app.start()
263 app.start()
264
264
265
265
266 if __name__ == '__main__':
266 if __name__ == '__main__':
267 launch_new_instance()
267 launch_new_instance()
268
268
@@ -1,240 +1,240 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The IPython controller application
4 The IPython controller application
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # 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 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 import os
18 import os
19 import sys
19 import sys
20
20
21 from twisted.application import service
21 from twisted.application import service
22 from twisted.internet import reactor
22 from twisted.internet import reactor
23 from twisted.python import log
23 from twisted.python import log
24
24
25 from IPython.config.loader import NoConfigDefault
25 from IPython.config.loader import NoConfigDefault
26
26
27 from IPython.kernel.clusterdir import (
27 from IPython.kernel.clusterdir import (
28 ApplicationWithClusterDir,
28 ApplicationWithClusterDir,
29 AppWithClusterDirArgParseConfigLoader
29 AppWithClusterDirArgParseConfigLoader
30 )
30 )
31 from IPython.core import release
31 from IPython.core import release
32
32
33 from IPython.utils.importstring import import_item
33 from IPython.utils.importstring import import_item
34
34
35 from IPython.kernel.engineservice import EngineService
35 from IPython.kernel.engineservice import EngineService
36 from IPython.kernel.fcutil import Tub
36 from IPython.kernel.fcutil import Tub
37 from IPython.kernel.engineconnector import EngineConnector
37 from IPython.kernel.engineconnector import EngineConnector
38
38
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40 # The main application
40 # The main application
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42
42
43
43
44 cl_args = (
44 cl_args = (
45 # Controller config
45 # Controller config
46 (('--furl-file',), dict(
46 (('--furl-file',), dict(
47 type=str, dest='Global.furl_file', default=NoConfigDefault,
47 type=unicode, dest='Global.furl_file', default=NoConfigDefault,
48 help='The full location of the file containing the FURL of the '
48 help='The full location of the file containing the FURL of the '
49 'controller. If this is not given, the FURL file must be in the '
49 'controller. If this is not given, the FURL file must be in the '
50 'security directory of the cluster directory. This location is '
50 'security directory of the cluster directory. This location is '
51 'resolved using the --profile and --app-dir options.',
51 'resolved using the --profile and --app-dir options.',
52 metavar='Global.furl_file')
52 metavar='Global.furl_file')
53 ),
53 ),
54 # MPI
54 # MPI
55 (('--mpi',), dict(
55 (('--mpi',), dict(
56 type=str, dest='MPI.use', default=NoConfigDefault,
56 type=str, dest='MPI.use', default=NoConfigDefault,
57 help='How to enable MPI (mpi4py, pytrilinos, or empty string to disable).',
57 help='How to enable MPI (mpi4py, pytrilinos, or empty string to disable).',
58 metavar='MPI.use')
58 metavar='MPI.use')
59 ),
59 ),
60 # Global config
60 # Global config
61 (('--log-to-file',), dict(
61 (('--log-to-file',), dict(
62 action='store_true', dest='Global.log_to_file', default=NoConfigDefault,
62 action='store_true', dest='Global.log_to_file', default=NoConfigDefault,
63 help='Log to a file in the log directory (default is stdout)')
63 help='Log to a file in the log directory (default is stdout)')
64 )
64 )
65 )
65 )
66
66
67
67
68 class IPEngineAppCLConfigLoader(AppWithClusterDirArgParseConfigLoader):
68 class IPEngineAppCLConfigLoader(AppWithClusterDirArgParseConfigLoader):
69
69
70 arguments = cl_args
70 arguments = cl_args
71
71
72
72
73 mpi4py_init = """from mpi4py import MPI as mpi
73 mpi4py_init = """from mpi4py import MPI as mpi
74 mpi.size = mpi.COMM_WORLD.Get_size()
74 mpi.size = mpi.COMM_WORLD.Get_size()
75 mpi.rank = mpi.COMM_WORLD.Get_rank()
75 mpi.rank = mpi.COMM_WORLD.Get_rank()
76 """
76 """
77
77
78 pytrilinos_init = """from PyTrilinos import Epetra
78 pytrilinos_init = """from PyTrilinos import Epetra
79 class SimpleStruct:
79 class SimpleStruct:
80 pass
80 pass
81 mpi = SimpleStruct()
81 mpi = SimpleStruct()
82 mpi.rank = 0
82 mpi.rank = 0
83 mpi.size = 0
83 mpi.size = 0
84 """
84 """
85
85
86
86
87 default_config_file_name = 'ipengine_config.py'
87 default_config_file_name = u'ipengine_config.py'
88
88
89
89
90 class IPEngineApp(ApplicationWithClusterDir):
90 class IPEngineApp(ApplicationWithClusterDir):
91
91
92 name = 'ipengine'
92 name = u'ipengine'
93 description = 'Start the IPython engine for parallel computing.'
93 description = 'Start the IPython engine for parallel computing.'
94 config_file_name = default_config_file_name
94 config_file_name = default_config_file_name
95 auto_create_cluster_dir = True
95 auto_create_cluster_dir = True
96
96
97 def create_default_config(self):
97 def create_default_config(self):
98 super(IPEngineApp, self).create_default_config()
98 super(IPEngineApp, self).create_default_config()
99
99
100 # The engine should not clean logs as we don't want to remove the
100 # The engine should not clean logs as we don't want to remove the
101 # active log files of other running engines.
101 # active log files of other running engines.
102 self.default_config.Global.clean_logs = False
102 self.default_config.Global.clean_logs = False
103
103
104 # Global config attributes
104 # Global config attributes
105 self.default_config.Global.exec_lines = []
105 self.default_config.Global.exec_lines = []
106 self.default_config.Global.shell_class = 'IPython.kernel.core.interpreter.Interpreter'
106 self.default_config.Global.shell_class = 'IPython.kernel.core.interpreter.Interpreter'
107
107
108 # Configuration related to the controller
108 # Configuration related to the controller
109 # This must match the filename (path not included) that the controller
109 # This must match the filename (path not included) that the controller
110 # used for the FURL file.
110 # used for the FURL file.
111 self.default_config.Global.furl_file_name = 'ipcontroller-engine.furl'
111 self.default_config.Global.furl_file_name = u'ipcontroller-engine.furl'
112 # If given, this is the actual location of the controller's FURL file.
112 # If given, this is the actual location of the controller's FURL file.
113 # If not, this is computed using the profile, app_dir and furl_file_name
113 # If not, this is computed using the profile, app_dir and furl_file_name
114 self.default_config.Global.furl_file = ''
114 self.default_config.Global.furl_file = u''
115
115
116 # The max number of connection attemps and the initial delay between
116 # The max number of connection attemps and the initial delay between
117 # those attemps.
117 # those attemps.
118 self.default_config.Global.connect_delay = 0.1
118 self.default_config.Global.connect_delay = 0.1
119 self.default_config.Global.connect_max_tries = 15
119 self.default_config.Global.connect_max_tries = 15
120
120
121 # MPI related config attributes
121 # MPI related config attributes
122 self.default_config.MPI.use = ''
122 self.default_config.MPI.use = ''
123 self.default_config.MPI.mpi4py = mpi4py_init
123 self.default_config.MPI.mpi4py = mpi4py_init
124 self.default_config.MPI.pytrilinos = pytrilinos_init
124 self.default_config.MPI.pytrilinos = pytrilinos_init
125
125
126 def create_command_line_config(self):
126 def create_command_line_config(self):
127 """Create and return a command line config loader."""
127 """Create and return a command line config loader."""
128 return IPEngineAppCLConfigLoader(
128 return IPEngineAppCLConfigLoader(
129 description=self.description,
129 description=self.description,
130 version=release.version
130 version=release.version
131 )
131 )
132
132
133 def post_load_command_line_config(self):
133 def post_load_command_line_config(self):
134 pass
134 pass
135
135
136 def pre_construct(self):
136 def pre_construct(self):
137 super(IPEngineApp, self).pre_construct()
137 super(IPEngineApp, self).pre_construct()
138 self.find_cont_furl_file()
138 self.find_cont_furl_file()
139
139
140 def find_cont_furl_file(self):
140 def find_cont_furl_file(self):
141 """Set the furl file.
141 """Set the furl file.
142
142
143 Here we don't try to actually see if it exists for is valid as that
143 Here we don't try to actually see if it exists for is valid as that
144 is hadled by the connection logic.
144 is hadled by the connection logic.
145 """
145 """
146 config = self.master_config
146 config = self.master_config
147 # Find the actual controller FURL file
147 # Find the actual controller FURL file
148 if not config.Global.furl_file:
148 if not config.Global.furl_file:
149 try_this = os.path.join(
149 try_this = os.path.join(
150 config.Global.cluster_dir,
150 config.Global.cluster_dir,
151 config.Global.security_dir,
151 config.Global.security_dir,
152 config.Global.furl_file_name
152 config.Global.furl_file_name
153 )
153 )
154 config.Global.furl_file = try_this
154 config.Global.furl_file = try_this
155
155
156 def construct(self):
156 def construct(self):
157 # I am a little hesitant to put these into InteractiveShell itself.
157 # I am a little hesitant to put these into InteractiveShell itself.
158 # But that might be the place for them
158 # But that might be the place for them
159 sys.path.insert(0, '')
159 sys.path.insert(0, '')
160
160
161 self.start_mpi()
161 self.start_mpi()
162 self.start_logging()
162 self.start_logging()
163
163
164 # Create the underlying shell class and EngineService
164 # Create the underlying shell class and EngineService
165 shell_class = import_item(self.master_config.Global.shell_class)
165 shell_class = import_item(self.master_config.Global.shell_class)
166 self.engine_service = EngineService(shell_class, mpi=mpi)
166 self.engine_service = EngineService(shell_class, mpi=mpi)
167
167
168 self.exec_lines()
168 self.exec_lines()
169
169
170 # Create the service hierarchy
170 # Create the service hierarchy
171 self.main_service = service.MultiService()
171 self.main_service = service.MultiService()
172 self.engine_service.setServiceParent(self.main_service)
172 self.engine_service.setServiceParent(self.main_service)
173 self.tub_service = Tub()
173 self.tub_service = Tub()
174 self.tub_service.setServiceParent(self.main_service)
174 self.tub_service.setServiceParent(self.main_service)
175 # This needs to be called before the connection is initiated
175 # This needs to be called before the connection is initiated
176 self.main_service.startService()
176 self.main_service.startService()
177
177
178 # This initiates the connection to the controller and calls
178 # This initiates the connection to the controller and calls
179 # register_engine to tell the controller we are ready to do work
179 # register_engine to tell the controller we are ready to do work
180 self.engine_connector = EngineConnector(self.tub_service)
180 self.engine_connector = EngineConnector(self.tub_service)
181
181
182 log.msg("Using furl file: %s" % self.master_config.Global.furl_file)
182 log.msg("Using furl file: %s" % self.master_config.Global.furl_file)
183
183
184 reactor.callWhenRunning(self.call_connect)
184 reactor.callWhenRunning(self.call_connect)
185
185
186 def call_connect(self):
186 def call_connect(self):
187 d = self.engine_connector.connect_to_controller(
187 d = self.engine_connector.connect_to_controller(
188 self.engine_service,
188 self.engine_service,
189 self.master_config.Global.furl_file,
189 self.master_config.Global.furl_file,
190 self.master_config.Global.connect_delay,
190 self.master_config.Global.connect_delay,
191 self.master_config.Global.connect_max_tries
191 self.master_config.Global.connect_max_tries
192 )
192 )
193
193
194 def handle_error(f):
194 def handle_error(f):
195 log.msg('Error connecting to controller. This usually means that '
195 log.msg('Error connecting to controller. This usually means that '
196 'i) the controller was not started, ii) a firewall was blocking '
196 'i) the controller was not started, ii) a firewall was blocking '
197 'the engine from connecting to the controller or iii) the engine '
197 'the engine from connecting to the controller or iii) the engine '
198 ' was not pointed at the right FURL file:')
198 ' was not pointed at the right FURL file:')
199 log.msg(f.getErrorMessage())
199 log.msg(f.getErrorMessage())
200 reactor.callLater(0.1, reactor.stop)
200 reactor.callLater(0.1, reactor.stop)
201
201
202 d.addErrback(handle_error)
202 d.addErrback(handle_error)
203
203
204 def start_mpi(self):
204 def start_mpi(self):
205 global mpi
205 global mpi
206 mpikey = self.master_config.MPI.use
206 mpikey = self.master_config.MPI.use
207 mpi_import_statement = self.master_config.MPI.get(mpikey, None)
207 mpi_import_statement = self.master_config.MPI.get(mpikey, None)
208 if mpi_import_statement is not None:
208 if mpi_import_statement is not None:
209 try:
209 try:
210 self.log.info("Initializing MPI:")
210 self.log.info("Initializing MPI:")
211 self.log.info(mpi_import_statement)
211 self.log.info(mpi_import_statement)
212 exec mpi_import_statement in globals()
212 exec mpi_import_statement in globals()
213 except:
213 except:
214 mpi = None
214 mpi = None
215 else:
215 else:
216 mpi = None
216 mpi = None
217
217
218 def exec_lines(self):
218 def exec_lines(self):
219 for line in self.master_config.Global.exec_lines:
219 for line in self.master_config.Global.exec_lines:
220 try:
220 try:
221 log.msg("Executing statement: '%s'" % line)
221 log.msg("Executing statement: '%s'" % line)
222 self.engine_service.execute(line)
222 self.engine_service.execute(line)
223 except:
223 except:
224 log.msg("Error executing statement: %s" % line)
224 log.msg("Error executing statement: %s" % line)
225
225
226 def start_app(self):
226 def start_app(self):
227 # cd to the cluster_dir as our working directory.
227 # cd to the cluster_dir as our working directory.
228 os.chdir(self.master_config.Global.cluster_dir)
228 os.chdir(self.master_config.Global.cluster_dir)
229 reactor.run()
229 reactor.run()
230
230
231
231
232 def launch_new_instance():
232 def launch_new_instance():
233 """Create and run the IPython controller"""
233 """Create and run the IPython controller"""
234 app = IPEngineApp()
234 app = IPEngineApp()
235 app.start()
235 app.start()
236
236
237
237
238 if __name__ == '__main__':
238 if __name__ == '__main__':
239 launch_new_instance()
239 launch_new_instance()
240
240
@@ -1,808 +1,808 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Facilities for launching processing asynchronously.
4 Facilities for launching processing asynchronously.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # 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 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 import os
18 import os
19 import re
19 import re
20 import sys
20 import sys
21
21
22 from IPython.core.component import Component
22 from IPython.core.component import Component
23 from IPython.external import Itpl
23 from IPython.external import Itpl
24 from IPython.utils.traitlets import Str, Int, List, Unicode, Enum
24 from IPython.utils.traitlets import Str, Int, List, Unicode, Enum
25 from IPython.utils.platutils import find_cmd
25 from IPython.utils.platutils import find_cmd
26 from IPython.kernel.twistedutil import gatherBoth, make_deferred, sleep_deferred
26 from IPython.kernel.twistedutil import gatherBoth, make_deferred, sleep_deferred
27 from IPython.kernel.winhpcjob import (
27 from IPython.kernel.winhpcjob import (
28 WinHPCJob, WinHPCTask,
28 WinHPCJob, WinHPCTask,
29 IPControllerTask, IPEngineTask
29 IPControllerTask, IPEngineTask
30 )
30 )
31
31
32 from twisted.internet import reactor, defer
32 from twisted.internet import reactor, defer
33 from twisted.internet.defer import inlineCallbacks
33 from twisted.internet.defer import inlineCallbacks
34 from twisted.internet.protocol import ProcessProtocol
34 from twisted.internet.protocol import ProcessProtocol
35 from twisted.internet.utils import getProcessOutput
35 from twisted.internet.utils import getProcessOutput
36 from twisted.internet.error import ProcessDone, ProcessTerminated
36 from twisted.internet.error import ProcessDone, ProcessTerminated
37 from twisted.python import log
37 from twisted.python import log
38 from twisted.python.failure import Failure
38 from twisted.python.failure import Failure
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Generic launchers
41 # Generic launchers
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44
44
45 class LauncherError(Exception):
45 class LauncherError(Exception):
46 pass
46 pass
47
47
48
48
49 class ProcessStateError(LauncherError):
49 class ProcessStateError(LauncherError):
50 pass
50 pass
51
51
52
52
53 class UnknownStatus(LauncherError):
53 class UnknownStatus(LauncherError):
54 pass
54 pass
55
55
56
56
57 class BaseLauncher(Component):
57 class BaseLauncher(Component):
58 """An asbtraction for starting, stopping and signaling a process."""
58 """An asbtraction for starting, stopping and signaling a process."""
59
59
60 # A directory for files related to the process. But, we don't cd to
60 # A directory for files related to the process. But, we don't cd to
61 # this directory,
61 # this directory,
62 working_dir = Unicode(u'')
62 working_dir = Unicode(u'')
63
63
64 def __init__(self, working_dir, parent=None, name=None, config=None):
64 def __init__(self, working_dir, parent=None, name=None, config=None):
65 super(BaseLauncher, self).__init__(parent, name, config)
65 super(BaseLauncher, self).__init__(parent, name, config)
66 self.working_dir = working_dir
66 self.working_dir = working_dir
67 self.state = 'before' # can be before, running, after
67 self.state = 'before' # can be before, running, after
68 self.stop_deferreds = []
68 self.stop_deferreds = []
69 self.start_data = None
69 self.start_data = None
70 self.stop_data = None
70 self.stop_data = None
71
71
72 @property
72 @property
73 def args(self):
73 def args(self):
74 """A list of cmd and args that will be used to start the process.
74 """A list of cmd and args that will be used to start the process.
75
75
76 This is what is passed to :func:`spawnProcess` and the first element
76 This is what is passed to :func:`spawnProcess` and the first element
77 will be the process name.
77 will be the process name.
78 """
78 """
79 return self.find_args()
79 return self.find_args()
80
80
81 def find_args(self):
81 def find_args(self):
82 """The ``.args`` property calls this to find the args list.
82 """The ``.args`` property calls this to find the args list.
83
83
84 Subcommand should implement this to construct the cmd and args.
84 Subcommand should implement this to construct the cmd and args.
85 """
85 """
86 raise NotImplementedError('find_args must be implemented in a subclass')
86 raise NotImplementedError('find_args must be implemented in a subclass')
87
87
88 @property
88 @property
89 def arg_str(self):
89 def arg_str(self):
90 """The string form of the program arguments."""
90 """The string form of the program arguments."""
91 return ' '.join(self.args)
91 return ' '.join(self.args)
92
92
93 @property
93 @property
94 def running(self):
94 def running(self):
95 """Am I running."""
95 """Am I running."""
96 if self.state == 'running':
96 if self.state == 'running':
97 return True
97 return True
98 else:
98 else:
99 return False
99 return False
100
100
101 def start(self):
101 def start(self):
102 """Start the process.
102 """Start the process.
103
103
104 This must return a deferred that fires with information about the
104 This must return a deferred that fires with information about the
105 process starting (like a pid, job id, etc.).
105 process starting (like a pid, job id, etc.).
106 """
106 """
107 return defer.fail(
107 return defer.fail(
108 Failure(NotImplementedError(
108 Failure(NotImplementedError(
109 'start must be implemented in a subclass')
109 'start must be implemented in a subclass')
110 )
110 )
111 )
111 )
112
112
113 def stop(self):
113 def stop(self):
114 """Stop the process and notify observers of stopping.
114 """Stop the process and notify observers of stopping.
115
115
116 This must return a deferred that fires with information about the
116 This must return a deferred that fires with information about the
117 processing stopping, like errors that occur while the process is
117 processing stopping, like errors that occur while the process is
118 attempting to be shut down. This deferred won't fire when the process
118 attempting to be shut down. This deferred won't fire when the process
119 actually stops. To observe the actual process stopping, see
119 actually stops. To observe the actual process stopping, see
120 :func:`observe_stop`.
120 :func:`observe_stop`.
121 """
121 """
122 return defer.fail(
122 return defer.fail(
123 Failure(NotImplementedError(
123 Failure(NotImplementedError(
124 'stop must be implemented in a subclass')
124 'stop must be implemented in a subclass')
125 )
125 )
126 )
126 )
127
127
128 def observe_stop(self):
128 def observe_stop(self):
129 """Get a deferred that will fire when the process stops.
129 """Get a deferred that will fire when the process stops.
130
130
131 The deferred will fire with data that contains information about
131 The deferred will fire with data that contains information about
132 the exit status of the process.
132 the exit status of the process.
133 """
133 """
134 if self.state=='after':
134 if self.state=='after':
135 return defer.succeed(self.stop_data)
135 return defer.succeed(self.stop_data)
136 else:
136 else:
137 d = defer.Deferred()
137 d = defer.Deferred()
138 self.stop_deferreds.append(d)
138 self.stop_deferreds.append(d)
139 return d
139 return d
140
140
141 def notify_start(self, data):
141 def notify_start(self, data):
142 """Call this to trigger startup actions.
142 """Call this to trigger startup actions.
143
143
144 This logs the process startup and sets the state to 'running'. It is
144 This logs the process startup and sets the state to 'running'. It is
145 a pass-through so it can be used as a callback.
145 a pass-through so it can be used as a callback.
146 """
146 """
147
147
148 log.msg('Process %r started: %r' % (self.args[0], data))
148 log.msg('Process %r started: %r' % (self.args[0], data))
149 self.start_data = data
149 self.start_data = data
150 self.state = 'running'
150 self.state = 'running'
151 return data
151 return data
152
152
153 def notify_stop(self, data):
153 def notify_stop(self, data):
154 """Call this to trigger process stop actions.
154 """Call this to trigger process stop actions.
155
155
156 This logs the process stopping and sets the state to 'after'. Call
156 This logs the process stopping and sets the state to 'after'. Call
157 this to trigger all the deferreds from :func:`observe_stop`."""
157 this to trigger all the deferreds from :func:`observe_stop`."""
158
158
159 log.msg('Process %r stopped: %r' % (self.args[0], data))
159 log.msg('Process %r stopped: %r' % (self.args[0], data))
160 self.stop_data = data
160 self.stop_data = data
161 self.state = 'after'
161 self.state = 'after'
162 for i in range(len(self.stop_deferreds)):
162 for i in range(len(self.stop_deferreds)):
163 d = self.stop_deferreds.pop()
163 d = self.stop_deferreds.pop()
164 d.callback(data)
164 d.callback(data)
165 return data
165 return data
166
166
167 def signal(self, sig):
167 def signal(self, sig):
168 """Signal the process.
168 """Signal the process.
169
169
170 Return a semi-meaningless deferred after signaling the process.
170 Return a semi-meaningless deferred after signaling the process.
171
171
172 Parameters
172 Parameters
173 ----------
173 ----------
174 sig : str or int
174 sig : str or int
175 'KILL', 'INT', etc., or any signal number
175 'KILL', 'INT', etc., or any signal number
176 """
176 """
177 return defer.fail(
177 return defer.fail(
178 Failure(NotImplementedError(
178 Failure(NotImplementedError(
179 'signal must be implemented in a subclass')
179 'signal must be implemented in a subclass')
180 )
180 )
181 )
181 )
182
182
183
183
184 class LocalProcessLauncherProtocol(ProcessProtocol):
184 class LocalProcessLauncherProtocol(ProcessProtocol):
185 """A ProcessProtocol to go with the LocalProcessLauncher."""
185 """A ProcessProtocol to go with the LocalProcessLauncher."""
186
186
187 def __init__(self, process_launcher):
187 def __init__(self, process_launcher):
188 self.process_launcher = process_launcher
188 self.process_launcher = process_launcher
189 self.pid = None
189 self.pid = None
190
190
191 def connectionMade(self):
191 def connectionMade(self):
192 self.pid = self.transport.pid
192 self.pid = self.transport.pid
193 self.process_launcher.notify_start(self.transport.pid)
193 self.process_launcher.notify_start(self.transport.pid)
194
194
195 def processEnded(self, status):
195 def processEnded(self, status):
196 value = status.value
196 value = status.value
197 if isinstance(value, ProcessDone):
197 if isinstance(value, ProcessDone):
198 self.process_launcher.notify_stop(
198 self.process_launcher.notify_stop(
199 {'exit_code':0,
199 {'exit_code':0,
200 'signal':None,
200 'signal':None,
201 'status':None,
201 'status':None,
202 'pid':self.pid
202 'pid':self.pid
203 }
203 }
204 )
204 )
205 elif isinstance(value, ProcessTerminated):
205 elif isinstance(value, ProcessTerminated):
206 self.process_launcher.notify_stop(
206 self.process_launcher.notify_stop(
207 {'exit_code':value.exitCode,
207 {'exit_code':value.exitCode,
208 'signal':value.signal,
208 'signal':value.signal,
209 'status':value.status,
209 'status':value.status,
210 'pid':self.pid
210 'pid':self.pid
211 }
211 }
212 )
212 )
213 else:
213 else:
214 raise UnknownStatus("Unknown exit status, this is probably a "
214 raise UnknownStatus("Unknown exit status, this is probably a "
215 "bug in Twisted")
215 "bug in Twisted")
216
216
217 def outReceived(self, data):
217 def outReceived(self, data):
218 log.msg(data)
218 log.msg(data)
219
219
220 def errReceived(self, data):
220 def errReceived(self, data):
221 log.err(data)
221 log.err(data)
222
222
223
223
224 class LocalProcessLauncher(BaseLauncher):
224 class LocalProcessLauncher(BaseLauncher):
225 """Start and stop an external process in an asynchronous manner."""
225 """Start and stop an external process in an asynchronous manner."""
226
226
227 # This is used to to construct self.args, which is passed to
227 # This is used to to construct self.args, which is passed to
228 # spawnProcess.
228 # spawnProcess.
229 cmd_and_args = List([])
229 cmd_and_args = List([])
230
230
231 def __init__(self, working_dir, parent=None, name=None, config=None):
231 def __init__(self, working_dir, parent=None, name=None, config=None):
232 super(LocalProcessLauncher, self).__init__(
232 super(LocalProcessLauncher, self).__init__(
233 working_dir, parent, name, config
233 working_dir, parent, name, config
234 )
234 )
235 self.process_protocol = None
235 self.process_protocol = None
236 self.start_deferred = None
236 self.start_deferred = None
237
237
238 def find_args(self):
238 def find_args(self):
239 return self.cmd_and_args
239 return self.cmd_and_args
240
240
241 def start(self):
241 def start(self):
242 if self.state == 'before':
242 if self.state == 'before':
243 self.process_protocol = LocalProcessLauncherProtocol(self)
243 self.process_protocol = LocalProcessLauncherProtocol(self)
244 self.start_deferred = defer.Deferred()
244 self.start_deferred = defer.Deferred()
245 self.process_transport = reactor.spawnProcess(
245 self.process_transport = reactor.spawnProcess(
246 self.process_protocol,
246 self.process_protocol,
247 str(self.args[0]),
247 str(self.args[0]), # twisted expects these to be str, not unicode
248 [str(a) for a in self.args],
248 [str(a) for a in self.args], # str expected, not unicode
249 env=os.environ
249 env=os.environ
250 )
250 )
251 return self.start_deferred
251 return self.start_deferred
252 else:
252 else:
253 s = 'The process was already started and has state: %r' % self.state
253 s = 'The process was already started and has state: %r' % self.state
254 return defer.fail(ProcessStateError(s))
254 return defer.fail(ProcessStateError(s))
255
255
256 def notify_start(self, data):
256 def notify_start(self, data):
257 super(LocalProcessLauncher, self).notify_start(data)
257 super(LocalProcessLauncher, self).notify_start(data)
258 self.start_deferred.callback(data)
258 self.start_deferred.callback(data)
259
259
260 def stop(self):
260 def stop(self):
261 return self.interrupt_then_kill()
261 return self.interrupt_then_kill()
262
262
263 @make_deferred
263 @make_deferred
264 def signal(self, sig):
264 def signal(self, sig):
265 if self.state == 'running':
265 if self.state == 'running':
266 self.process_transport.signalProcess(sig)
266 self.process_transport.signalProcess(sig)
267
267
268 @inlineCallbacks
268 @inlineCallbacks
269 def interrupt_then_kill(self, delay=2.0):
269 def interrupt_then_kill(self, delay=2.0):
270 """Send INT, wait a delay and then send KILL."""
270 """Send INT, wait a delay and then send KILL."""
271 yield self.signal('INT')
271 yield self.signal('INT')
272 yield sleep_deferred(delay)
272 yield sleep_deferred(delay)
273 yield self.signal('KILL')
273 yield self.signal('KILL')
274
274
275
275
276 class MPIExecLauncher(LocalProcessLauncher):
276 class MPIExecLauncher(LocalProcessLauncher):
277 """Launch an external process using mpiexec."""
277 """Launch an external process using mpiexec."""
278
278
279 # The mpiexec command to use in starting the process.
279 # The mpiexec command to use in starting the process.
280 mpi_cmd = List(['mpiexec'], config=True)
280 mpi_cmd = List(['mpiexec'], config=True)
281 # The command line arguments to pass to mpiexec.
281 # The command line arguments to pass to mpiexec.
282 mpi_args = List([], config=True)
282 mpi_args = List([], config=True)
283 # The program to start using mpiexec.
283 # The program to start using mpiexec.
284 program = List(['date'], config=True)
284 program = List(['date'], config=True)
285 # The command line argument to the program.
285 # The command line argument to the program.
286 program_args = List([], config=True)
286 program_args = List([], config=True)
287 # The number of instances of the program to start.
287 # The number of instances of the program to start.
288 n = Int(1, config=True)
288 n = Int(1, config=True)
289
289
290 def find_args(self):
290 def find_args(self):
291 """Build self.args using all the fields."""
291 """Build self.args using all the fields."""
292 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
292 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
293 self.program + self.program_args
293 self.program + self.program_args
294
294
295 def start(self, n):
295 def start(self, n):
296 """Start n instances of the program using mpiexec."""
296 """Start n instances of the program using mpiexec."""
297 self.n = n
297 self.n = n
298 return super(MPIExecLauncher, self).start()
298 return super(MPIExecLauncher, self).start()
299
299
300
300
301 class SSHLauncher(BaseLauncher):
301 class SSHLauncher(BaseLauncher):
302 """A minimal launcher for ssh.
302 """A minimal launcher for ssh.
303
303
304 To be useful this will probably have to be extended to use the ``sshx``
304 To be useful this will probably have to be extended to use the ``sshx``
305 idea for environment variables. There could be other things this needs
305 idea for environment variables. There could be other things this needs
306 as well.
306 as well.
307 """
307 """
308
308
309 ssh_cmd = List(['ssh'], config=True)
309 ssh_cmd = List(['ssh'], config=True)
310 ssh_args = List([], config=True)
310 ssh_args = List([], config=True)
311 program = List(['date'], config=True)
311 program = List(['date'], config=True)
312 program_args = List([], config=True)
312 program_args = List([], config=True)
313 hostname = Str('', config=True)
313 hostname = Str('', config=True)
314 user = Str('', config=True)
314 user = Str('', config=True)
315 location = Str('')
315 location = Str('')
316
316
317 def _hostname_changed(self, name, old, new):
317 def _hostname_changed(self, name, old, new):
318 self.location = '%s@%s' % (self.user, new)
318 self.location = '%s@%s' % (self.user, new)
319
319
320 def _user_changed(self, name, old, new):
320 def _user_changed(self, name, old, new):
321 self.location = '%s@%s' % (new, self.hostname)
321 self.location = '%s@%s' % (new, self.hostname)
322
322
323 def find_args(self):
323 def find_args(self):
324 return self.ssh_cmd + self.ssh_args + [self.location] + \
324 return self.ssh_cmd + self.ssh_args + [self.location] + \
325 self.program + self.program_args
325 self.program + self.program_args
326
326
327 def start(self, n, hostname=None, user=None):
327 def start(self, n, hostname=None, user=None):
328 if hostname is not None:
328 if hostname is not None:
329 self.hostname = hostname
329 self.hostname = hostname
330 if user is not None:
330 if user is not None:
331 self.user = user
331 self.user = user
332 return super(SSHLauncher, self).start()
332 return super(SSHLauncher, self).start()
333
333
334
334
335 class WindowsHPCLauncher(BaseLauncher):
335 class WindowsHPCLauncher(BaseLauncher):
336
336
337 # A regular expression used to get the job id from the output of the
337 # A regular expression used to get the job id from the output of the
338 # submit_command.
338 # submit_command.
339 job_id_regexp = Str('\d+', config=True)
339 job_id_regexp = Str('\d+', config=True)
340 # The filename of the instantiated job script.
340 # The filename of the instantiated job script.
341 job_file_name = Unicode(u'ipython_job.xml', config=True)
341 job_file_name = Unicode(u'ipython_job.xml', config=True)
342 # The full path to the instantiated job script. This gets made dynamically
342 # The full path to the instantiated job script. This gets made dynamically
343 # by combining the working_dir with the job_file_name.
343 # by combining the working_dir with the job_file_name.
344 job_file = Unicode(u'')
344 job_file = Unicode(u'')
345 # The hostname of the scheduler to submit the job to
345 # The hostname of the scheduler to submit the job to
346 scheduler = Str('HEADNODE', config=True)
346 scheduler = Str('HEADNODE', config=True)
347 username = Str(os.environ.get('USERNAME', ''), config=True)
347 username = Str(os.environ.get('USERNAME', ''), config=True)
348 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
348 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
349 default_value='Highest', config=True)
349 default_value='Highest', config=True)
350 requested_nodes = Str('', config=True)
350 requested_nodes = Str('', config=True)
351 project = Str('MyProject', config=True)
351 project = Str('MyProject', config=True)
352 job_cmd = Str(find_cmd('job'), config=True)
352 job_cmd = Str(find_cmd('job'), config=True)
353
353
354 def __init__(self, working_dir, parent=None, name=None, config=None):
354 def __init__(self, working_dir, parent=None, name=None, config=None):
355 super(WindowsHPCLauncher, self).__init__(
355 super(WindowsHPCLauncher, self).__init__(
356 working_dir, parent, name, config
356 working_dir, parent, name, config
357 )
357 )
358 self.job_file = os.path.join(self.working_dir, self.job_file_name)
358 self.job_file = os.path.join(self.working_dir, self.job_file_name)
359
359
360 def write_job_file(self, n):
360 def write_job_file(self, n):
361 raise NotImplementedError("Implement write_job_file in a subclass.")
361 raise NotImplementedError("Implement write_job_file in a subclass.")
362
362
363 def find_args(self):
363 def find_args(self):
364 return ['job.exe']
364 return ['job.exe']
365
365
366 def parse_job_id(self, output):
366 def parse_job_id(self, output):
367 """Take the output of the submit command and return the job id."""
367 """Take the output of the submit command and return the job id."""
368 m = re.search(self.job_id_regexp, output)
368 m = re.search(self.job_id_regexp, output)
369 if m is not None:
369 if m is not None:
370 job_id = m.group()
370 job_id = m.group()
371 else:
371 else:
372 raise LauncherError("Job id couldn't be determined: %s" % output)
372 raise LauncherError("Job id couldn't be determined: %s" % output)
373 self.job_id = job_id
373 self.job_id = job_id
374 log.msg('Job started with job id: %r' % job_id)
374 log.msg('Job started with job id: %r' % job_id)
375 return job_id
375 return job_id
376
376
377 @inlineCallbacks
377 @inlineCallbacks
378 def start(self, n):
378 def start(self, n):
379 """Start n copies of the process using the Win HPC job scheduler."""
379 """Start n copies of the process using the Win HPC job scheduler."""
380 self.write_job_file(n)
380 self.write_job_file(n)
381 args = [
381 args = [
382 'submit',
382 'submit',
383 '/jobfile:%s' % self.job_file,
383 '/jobfile:%s' % self.job_file,
384 '/scheduler:%s' % self.scheduler
384 '/scheduler:%s' % self.scheduler
385 ]
385 ]
386 log.msg("Starting Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
386 log.msg("Starting Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
387 output = yield getProcessOutput(self.job_cmd,
387 output = yield getProcessOutput(self.job_cmd,
388 args,
388 args,
389 env=os.environ,
389 env=os.environ,
390 path=self.working_dir
390 path=self.working_dir
391 )
391 )
392 job_id = self.parse_job_id(output)
392 job_id = self.parse_job_id(output)
393 self.notify_start(job_id)
393 self.notify_start(job_id)
394 defer.returnValue(job_id)
394 defer.returnValue(job_id)
395
395
396 @inlineCallbacks
396 @inlineCallbacks
397 def stop(self):
397 def stop(self):
398 args = [
398 args = [
399 'cancel',
399 'cancel',
400 self.job_id,
400 self.job_id,
401 '/scheduler:%s' % self.scheduler
401 '/scheduler:%s' % self.scheduler
402 ]
402 ]
403 log.msg("Stopping Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
403 log.msg("Stopping Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
404 try:
404 try:
405 output = yield getProcessOutput(self.job_cmd,
405 output = yield getProcessOutput(self.job_cmd,
406 args,
406 args,
407 env=os.environ,
407 env=os.environ,
408 path=self.working_dir
408 path=self.working_dir
409 )
409 )
410 except:
410 except:
411 output = 'The job already appears to be stoppped: %r' % self.job_id
411 output = 'The job already appears to be stoppped: %r' % self.job_id
412 self.notify_stop(output) # Pass the output of the kill cmd
412 self.notify_stop(output) # Pass the output of the kill cmd
413 defer.returnValue(output)
413 defer.returnValue(output)
414
414
415
415
416 class BatchSystemLauncher(BaseLauncher):
416 class BatchSystemLauncher(BaseLauncher):
417 """Launch an external process using a batch system.
417 """Launch an external process using a batch system.
418
418
419 This class is designed to work with UNIX batch systems like PBS, LSF,
419 This class is designed to work with UNIX batch systems like PBS, LSF,
420 GridEngine, etc. The overall model is that there are different commands
420 GridEngine, etc. The overall model is that there are different commands
421 like qsub, qdel, etc. that handle the starting and stopping of the process.
421 like qsub, qdel, etc. that handle the starting and stopping of the process.
422
422
423 This class also has the notion of a batch script. The ``batch_template``
423 This class also has the notion of a batch script. The ``batch_template``
424 attribute can be set to a string that is a template for the batch script.
424 attribute can be set to a string that is a template for the batch script.
425 This template is instantiated using Itpl. Thus the template can use
425 This template is instantiated using Itpl. Thus the template can use
426 ${n} fot the number of instances. Subclasses can add additional variables
426 ${n} fot the number of instances. Subclasses can add additional variables
427 to the template dict.
427 to the template dict.
428 """
428 """
429
429
430 # Subclasses must fill these in. See PBSEngineSet
430 # Subclasses must fill these in. See PBSEngineSet
431 # The name of the command line program used to submit jobs.
431 # The name of the command line program used to submit jobs.
432 submit_command = Str('', config=True)
432 submit_command = Str('', config=True)
433 # The name of the command line program used to delete jobs.
433 # The name of the command line program used to delete jobs.
434 delete_command = Str('', config=True)
434 delete_command = Str('', config=True)
435 # A regular expression used to get the job id from the output of the
435 # A regular expression used to get the job id from the output of the
436 # submit_command.
436 # submit_command.
437 job_id_regexp = Str('', config=True)
437 job_id_regexp = Str('', config=True)
438 # The string that is the batch script template itself.
438 # The string that is the batch script template itself.
439 batch_template = Str('', config=True)
439 batch_template = Str('', config=True)
440 # The filename of the instantiated batch script.
440 # The filename of the instantiated batch script.
441 batch_file_name = Unicode(u'batch_script', config=True)
441 batch_file_name = Unicode(u'batch_script', config=True)
442 # The full path to the instantiated batch script.
442 # The full path to the instantiated batch script.
443 batch_file = Unicode(u'')
443 batch_file = Unicode(u'')
444
444
445 def __init__(self, working_dir, parent=None, name=None, config=None):
445 def __init__(self, working_dir, parent=None, name=None, config=None):
446 super(BatchSystemLauncher, self).__init__(
446 super(BatchSystemLauncher, self).__init__(
447 working_dir, parent, name, config
447 working_dir, parent, name, config
448 )
448 )
449 self.batch_file = os.path.join(self.working_dir, self.batch_file_name)
449 self.batch_file = os.path.join(self.working_dir, self.batch_file_name)
450 self.context = {}
450 self.context = {}
451
451
452 def parse_job_id(self, output):
452 def parse_job_id(self, output):
453 """Take the output of the submit command and return the job id."""
453 """Take the output of the submit command and return the job id."""
454 m = re.match(self.job_id_regexp, output)
454 m = re.match(self.job_id_regexp, output)
455 if m is not None:
455 if m is not None:
456 job_id = m.group()
456 job_id = m.group()
457 else:
457 else:
458 raise LauncherError("Job id couldn't be determined: %s" % output)
458 raise LauncherError("Job id couldn't be determined: %s" % output)
459 self.job_id = job_id
459 self.job_id = job_id
460 log.msg('Job started with job id: %r' % job_id)
460 log.msg('Job started with job id: %r' % job_id)
461 return job_id
461 return job_id
462
462
463 def write_batch_script(self, n):
463 def write_batch_script(self, n):
464 """Instantiate and write the batch script to the working_dir."""
464 """Instantiate and write the batch script to the working_dir."""
465 self.context['n'] = n
465 self.context['n'] = n
466 script_as_string = Itpl.itplns(self.batch_template, self.context)
466 script_as_string = Itpl.itplns(self.batch_template, self.context)
467 log.msg('Writing instantiated batch script: %s' % self.batch_file)
467 log.msg('Writing instantiated batch script: %s' % self.batch_file)
468 f = open(self.batch_file, 'w')
468 f = open(self.batch_file, 'w')
469 f.write(script_as_string)
469 f.write(script_as_string)
470 f.close()
470 f.close()
471
471
472 @inlineCallbacks
472 @inlineCallbacks
473 def start(self, n):
473 def start(self, n):
474 """Start n copies of the process using a batch system."""
474 """Start n copies of the process using a batch system."""
475 self.write_batch_script(n)
475 self.write_batch_script(n)
476 output = yield getProcessOutput(self.submit_command,
476 output = yield getProcessOutput(self.submit_command,
477 [self.batch_file], env=os.environ)
477 [self.batch_file], env=os.environ)
478 job_id = self.parse_job_id(output)
478 job_id = self.parse_job_id(output)
479 self.notify_start(job_id)
479 self.notify_start(job_id)
480 defer.returnValue(job_id)
480 defer.returnValue(job_id)
481
481
482 @inlineCallbacks
482 @inlineCallbacks
483 def stop(self):
483 def stop(self):
484 output = yield getProcessOutput(self.delete_command,
484 output = yield getProcessOutput(self.delete_command,
485 [self.job_id], env=os.environ
485 [self.job_id], env=os.environ
486 )
486 )
487 self.notify_stop(output) # Pass the output of the kill cmd
487 self.notify_stop(output) # Pass the output of the kill cmd
488 defer.returnValue(output)
488 defer.returnValue(output)
489
489
490
490
491 class PBSLauncher(BatchSystemLauncher):
491 class PBSLauncher(BatchSystemLauncher):
492 """A BatchSystemLauncher subclass for PBS."""
492 """A BatchSystemLauncher subclass for PBS."""
493
493
494 submit_command = Str('qsub', config=True)
494 submit_command = Str('qsub', config=True)
495 delete_command = Str('qdel', config=True)
495 delete_command = Str('qdel', config=True)
496 job_id_regexp = Str('\d+', config=True)
496 job_id_regexp = Str('\d+', config=True)
497 batch_template = Str('', config=True)
497 batch_template = Str('', config=True)
498 batch_file_name = Unicode(u'pbs_batch_script', config=True)
498 batch_file_name = Unicode(u'pbs_batch_script', config=True)
499 batch_file = Unicode(u'')
499 batch_file = Unicode(u'')
500
500
501
501
502 #-----------------------------------------------------------------------------
502 #-----------------------------------------------------------------------------
503 # Controller launchers
503 # Controller launchers
504 #-----------------------------------------------------------------------------
504 #-----------------------------------------------------------------------------
505
505
506 def find_controller_cmd():
506 def find_controller_cmd():
507 """Find the command line ipcontroller program in a cross platform way."""
507 """Find the command line ipcontroller program in a cross platform way."""
508 if sys.platform == 'win32':
508 if sys.platform == 'win32':
509 # This logic is needed because the ipcontroller script doesn't
509 # This logic is needed because the ipcontroller script doesn't
510 # always get installed in the same way or in the same location.
510 # always get installed in the same way or in the same location.
511 from IPython.kernel import ipcontrollerapp
511 from IPython.kernel import ipcontrollerapp
512 script_location = ipcontrollerapp.__file__.replace('.pyc', '.py')
512 script_location = ipcontrollerapp.__file__.replace('.pyc', '.py')
513 # The -u option here turns on unbuffered output, which is required
513 # The -u option here turns on unbuffered output, which is required
514 # on Win32 to prevent wierd conflict and problems with Twisted.
514 # on Win32 to prevent wierd conflict and problems with Twisted.
515 # Also, use sys.executable to make sure we are picking up the
515 # Also, use sys.executable to make sure we are picking up the
516 # right python exe.
516 # right python exe.
517 cmd = [sys.executable, '-u', script_location]
517 cmd = [sys.executable, '-u', script_location]
518 else:
518 else:
519 # ipcontroller has to be on the PATH in this case.
519 # ipcontroller has to be on the PATH in this case.
520 cmd = ['ipcontroller']
520 cmd = ['ipcontroller']
521 return cmd
521 return cmd
522
522
523
523
524 class LocalControllerLauncher(LocalProcessLauncher):
524 class LocalControllerLauncher(LocalProcessLauncher):
525 """Launch a controller as a regular external process."""
525 """Launch a controller as a regular external process."""
526
526
527 controller_cmd = List(find_controller_cmd(), config=True)
527 controller_cmd = List(find_controller_cmd(), config=True)
528 # Command line arguments to ipcontroller.
528 # Command line arguments to ipcontroller.
529 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
529 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
530
530
531 def find_args(self):
531 def find_args(self):
532 return self.controller_cmd + self.controller_args
532 return self.controller_cmd + self.controller_args
533
533
534 def start(self, profile=None, cluster_dir=None):
534 def start(self, profile=None, cluster_dir=None):
535 """Start the controller by profile or cluster_dir."""
535 """Start the controller by profile or cluster_dir."""
536 if cluster_dir is not None:
536 if cluster_dir is not None:
537 self.controller_args.extend(['--cluster-dir', cluster_dir])
537 self.controller_args.extend(['--cluster-dir', cluster_dir])
538 if profile is not None:
538 if profile is not None:
539 self.controller_args.extend(['--profile', profile])
539 self.controller_args.extend(['--profile', profile])
540 log.msg("Starting LocalControllerLauncher: %r" % self.args)
540 log.msg("Starting LocalControllerLauncher: %r" % self.args)
541 return super(LocalControllerLauncher, self).start()
541 return super(LocalControllerLauncher, self).start()
542
542
543
543
544 class WindowsHPCControllerLauncher(WindowsHPCLauncher):
544 class WindowsHPCControllerLauncher(WindowsHPCLauncher):
545
545
546 job_file_name = Unicode(u'ipcontroller_job.xml', config=True)
546 job_file_name = Unicode(u'ipcontroller_job.xml', config=True)
547 extra_args = List([],config=False)
547 extra_args = List([],config=False)
548
548
549 def write_job_file(self, n):
549 def write_job_file(self, n):
550 job = WinHPCJob(self)
550 job = WinHPCJob(self)
551 job.job_name = "IPController"
551 job.job_name = "IPController"
552 job.username = self.username
552 job.username = self.username
553 job.priority = self.priority
553 job.priority = self.priority
554 job.requested_nodes = self.requested_nodes
554 job.requested_nodes = self.requested_nodes
555 job.project = self.project
555 job.project = self.project
556
556
557 t = IPControllerTask(self)
557 t = IPControllerTask(self)
558 t.work_directory = self.working_dir
558 t.work_directory = self.working_dir
559 # Add the --profile and --cluster-dir args from start.
559 # Add the --profile and --cluster-dir args from start.
560 t.controller_args.extend(self.extra_args)
560 t.controller_args.extend(self.extra_args)
561 job.add_task(t)
561 job.add_task(t)
562 log.msg("Writing job description file: %s" % self.job_file)
562 log.msg("Writing job description file: %s" % self.job_file)
563 job.write(self.job_file)
563 job.write(self.job_file)
564
564
565 def start(self, profile=None, cluster_dir=None):
565 def start(self, profile=None, cluster_dir=None):
566 """Start the controller by profile or cluster_dir."""
566 """Start the controller by profile or cluster_dir."""
567 if cluster_dir is not None:
567 if cluster_dir is not None:
568 self.extra_args = ['--cluster-dir', cluster_dir]
568 self.extra_args = ['--cluster-dir', cluster_dir]
569 if profile is not None:
569 if profile is not None:
570 self.extra_args = ['--profile', profile]
570 self.extra_args = ['--profile', profile]
571 return super(WindowsHPCControllerLauncher, self).start(1)
571 return super(WindowsHPCControllerLauncher, self).start(1)
572
572
573
573
574 class MPIExecControllerLauncher(MPIExecLauncher):
574 class MPIExecControllerLauncher(MPIExecLauncher):
575 """Launch a controller using mpiexec."""
575 """Launch a controller using mpiexec."""
576
576
577 controller_cmd = List(find_controller_cmd(), config=True)
577 controller_cmd = List(find_controller_cmd(), config=True)
578 # Command line arguments to ipcontroller.
578 # Command line arguments to ipcontroller.
579 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
579 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
580 n = Int(1, config=False)
580 n = Int(1, config=False)
581
581
582 def start(self, profile=None, cluster_dir=None):
582 def start(self, profile=None, cluster_dir=None):
583 """Start the controller by profile or cluster_dir."""
583 """Start the controller by profile or cluster_dir."""
584 if cluster_dir is not None:
584 if cluster_dir is not None:
585 self.controller_args.extend(['--cluster-dir', cluster_dir])
585 self.controller_args.extend(['--cluster-dir', cluster_dir])
586 if profile is not None:
586 if profile is not None:
587 self.controller_args.extend(['--profile', profile])
587 self.controller_args.extend(['--profile', profile])
588 log.msg("Starting MPIExecControllerLauncher: %r" % self.args)
588 log.msg("Starting MPIExecControllerLauncher: %r" % self.args)
589 return super(MPIExecControllerLauncher, self).start(1)
589 return super(MPIExecControllerLauncher, self).start(1)
590
590
591 def find_args(self):
591 def find_args(self):
592 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
592 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
593 self.controller_cmd + self.controller_args
593 self.controller_cmd + self.controller_args
594
594
595
595
596 class PBSControllerLauncher(PBSLauncher):
596 class PBSControllerLauncher(PBSLauncher):
597 """Launch a controller using PBS."""
597 """Launch a controller using PBS."""
598
598
599 batch_file_name = Unicode(u'pbs_batch_script_controller', config=True)
599 batch_file_name = Unicode(u'pbs_batch_script_controller', config=True)
600
600
601 def start(self, profile=None, cluster_dir=None):
601 def start(self, profile=None, cluster_dir=None):
602 """Start the controller by profile or cluster_dir."""
602 """Start the controller by profile or cluster_dir."""
603 # Here we save profile and cluster_dir in the context so they
603 # Here we save profile and cluster_dir in the context so they
604 # can be used in the batch script template as ${profile} and
604 # can be used in the batch script template as ${profile} and
605 # ${cluster_dir}
605 # ${cluster_dir}
606 if cluster_dir is not None:
606 if cluster_dir is not None:
607 self.context['cluster_dir'] = cluster_dir
607 self.context['cluster_dir'] = cluster_dir
608 if profile is not None:
608 if profile is not None:
609 self.context['profile'] = profile
609 self.context['profile'] = profile
610 log.msg("Starting PBSControllerLauncher: %r" % self.args)
610 log.msg("Starting PBSControllerLauncher: %r" % self.args)
611 return super(PBSControllerLauncher, self).start(1)
611 return super(PBSControllerLauncher, self).start(1)
612
612
613
613
614 class SSHControllerLauncher(SSHLauncher):
614 class SSHControllerLauncher(SSHLauncher):
615 pass
615 pass
616
616
617
617
618 #-----------------------------------------------------------------------------
618 #-----------------------------------------------------------------------------
619 # Engine launchers
619 # Engine launchers
620 #-----------------------------------------------------------------------------
620 #-----------------------------------------------------------------------------
621
621
622
622
623 def find_engine_cmd():
623 def find_engine_cmd():
624 """Find the command line ipengine program in a cross platform way."""
624 """Find the command line ipengine program in a cross platform way."""
625 if sys.platform == 'win32':
625 if sys.platform == 'win32':
626 # This logic is needed because the ipengine script doesn't
626 # This logic is needed because the ipengine script doesn't
627 # always get installed in the same way or in the same location.
627 # always get installed in the same way or in the same location.
628 from IPython.kernel import ipengineapp
628 from IPython.kernel import ipengineapp
629 script_location = ipengineapp.__file__.replace('.pyc', '.py')
629 script_location = ipengineapp.__file__.replace('.pyc', '.py')
630 # The -u option here turns on unbuffered output, which is required
630 # The -u option here turns on unbuffered output, which is required
631 # on Win32 to prevent wierd conflict and problems with Twisted.
631 # on Win32 to prevent wierd conflict and problems with Twisted.
632 # Also, use sys.executable to make sure we are picking up the
632 # Also, use sys.executable to make sure we are picking up the
633 # right python exe.
633 # right python exe.
634 cmd = [sys.executable, '-u', script_location]
634 cmd = [sys.executable, '-u', script_location]
635 else:
635 else:
636 # ipcontroller has to be on the PATH in this case.
636 # ipcontroller has to be on the PATH in this case.
637 cmd = ['ipengine']
637 cmd = ['ipengine']
638 return cmd
638 return cmd
639
639
640
640
641 class LocalEngineLauncher(LocalProcessLauncher):
641 class LocalEngineLauncher(LocalProcessLauncher):
642 """Launch a single engine as a regular externall process."""
642 """Launch a single engine as a regular externall process."""
643
643
644 engine_cmd = List(find_engine_cmd(), config=True)
644 engine_cmd = List(find_engine_cmd(), config=True)
645 # Command line arguments for ipengine.
645 # Command line arguments for ipengine.
646 engine_args = List(
646 engine_args = List(
647 ['--log-to-file','--log-level', '40'], config=True
647 ['--log-to-file','--log-level', '40'], config=True
648 )
648 )
649
649
650 def find_args(self):
650 def find_args(self):
651 return self.engine_cmd + self.engine_args
651 return self.engine_cmd + self.engine_args
652
652
653 def start(self, profile=None, cluster_dir=None):
653 def start(self, profile=None, cluster_dir=None):
654 """Start the engine by profile or cluster_dir."""
654 """Start the engine by profile or cluster_dir."""
655 if cluster_dir is not None:
655 if cluster_dir is not None:
656 self.engine_args.extend(['--cluster-dir', cluster_dir])
656 self.engine_args.extend(['--cluster-dir', cluster_dir])
657 if profile is not None:
657 if profile is not None:
658 self.engine_args.extend(['--profile', profile])
658 self.engine_args.extend(['--profile', profile])
659 return super(LocalEngineLauncher, self).start()
659 return super(LocalEngineLauncher, self).start()
660
660
661
661
662 class LocalEngineSetLauncher(BaseLauncher):
662 class LocalEngineSetLauncher(BaseLauncher):
663 """Launch a set of engines as regular external processes."""
663 """Launch a set of engines as regular external processes."""
664
664
665 # Command line arguments for ipengine.
665 # Command line arguments for ipengine.
666 engine_args = List(
666 engine_args = List(
667 ['--log-to-file','--log-level', '40'], config=True
667 ['--log-to-file','--log-level', '40'], config=True
668 )
668 )
669
669
670 def __init__(self, working_dir, parent=None, name=None, config=None):
670 def __init__(self, working_dir, parent=None, name=None, config=None):
671 super(LocalEngineSetLauncher, self).__init__(
671 super(LocalEngineSetLauncher, self).__init__(
672 working_dir, parent, name, config
672 working_dir, parent, name, config
673 )
673 )
674 self.launchers = []
674 self.launchers = []
675
675
676 def start(self, n, profile=None, cluster_dir=None):
676 def start(self, n, profile=None, cluster_dir=None):
677 """Start n engines by profile or cluster_dir."""
677 """Start n engines by profile or cluster_dir."""
678 dlist = []
678 dlist = []
679 for i in range(n):
679 for i in range(n):
680 el = LocalEngineLauncher(self.working_dir, self)
680 el = LocalEngineLauncher(self.working_dir, self)
681 # Copy the engine args over to each engine launcher.
681 # Copy the engine args over to each engine launcher.
682 import copy
682 import copy
683 el.engine_args = copy.deepcopy(self.engine_args)
683 el.engine_args = copy.deepcopy(self.engine_args)
684 d = el.start(profile, cluster_dir)
684 d = el.start(profile, cluster_dir)
685 if i==0:
685 if i==0:
686 log.msg("Starting LocalEngineSetLauncher: %r" % el.args)
686 log.msg("Starting LocalEngineSetLauncher: %r" % el.args)
687 self.launchers.append(el)
687 self.launchers.append(el)
688 dlist.append(d)
688 dlist.append(d)
689 # The consumeErrors here could be dangerous
689 # The consumeErrors here could be dangerous
690 dfinal = gatherBoth(dlist, consumeErrors=True)
690 dfinal = gatherBoth(dlist, consumeErrors=True)
691 dfinal.addCallback(self.notify_start)
691 dfinal.addCallback(self.notify_start)
692 return dfinal
692 return dfinal
693
693
694 def find_args(self):
694 def find_args(self):
695 return ['engine set']
695 return ['engine set']
696
696
697 def signal(self, sig):
697 def signal(self, sig):
698 dlist = []
698 dlist = []
699 for el in self.launchers:
699 for el in self.launchers:
700 d = el.signal(sig)
700 d = el.signal(sig)
701 dlist.append(d)
701 dlist.append(d)
702 dfinal = gatherBoth(dlist, consumeErrors=True)
702 dfinal = gatherBoth(dlist, consumeErrors=True)
703 return dfinal
703 return dfinal
704
704
705 def interrupt_then_kill(self, delay=1.0):
705 def interrupt_then_kill(self, delay=1.0):
706 dlist = []
706 dlist = []
707 for el in self.launchers:
707 for el in self.launchers:
708 d = el.interrupt_then_kill(delay)
708 d = el.interrupt_then_kill(delay)
709 dlist.append(d)
709 dlist.append(d)
710 dfinal = gatherBoth(dlist, consumeErrors=True)
710 dfinal = gatherBoth(dlist, consumeErrors=True)
711 return dfinal
711 return dfinal
712
712
713 def stop(self):
713 def stop(self):
714 return self.interrupt_then_kill()
714 return self.interrupt_then_kill()
715
715
716 def observe_stop(self):
716 def observe_stop(self):
717 dlist = [el.observe_stop() for el in self.launchers]
717 dlist = [el.observe_stop() for el in self.launchers]
718 dfinal = gatherBoth(dlist, consumeErrors=False)
718 dfinal = gatherBoth(dlist, consumeErrors=False)
719 dfinal.addCallback(self.notify_stop)
719 dfinal.addCallback(self.notify_stop)
720 return dfinal
720 return dfinal
721
721
722
722
723 class MPIExecEngineSetLauncher(MPIExecLauncher):
723 class MPIExecEngineSetLauncher(MPIExecLauncher):
724
724
725 engine_cmd = List(find_engine_cmd(), config=True)
725 engine_cmd = List(find_engine_cmd(), config=True)
726 # Command line arguments for ipengine.
726 # Command line arguments for ipengine.
727 engine_args = List(
727 engine_args = List(
728 ['--log-to-file','--log-level', '40'], config=True
728 ['--log-to-file','--log-level', '40'], config=True
729 )
729 )
730 n = Int(1, config=True)
730 n = Int(1, config=True)
731
731
732 def start(self, n, profile=None, cluster_dir=None):
732 def start(self, n, profile=None, cluster_dir=None):
733 """Start n engines by profile or cluster_dir."""
733 """Start n engines by profile or cluster_dir."""
734 if cluster_dir is not None:
734 if cluster_dir is not None:
735 self.engine_args.extend(['--cluster-dir', cluster_dir])
735 self.engine_args.extend(['--cluster-dir', cluster_dir])
736 if profile is not None:
736 if profile is not None:
737 self.engine_args.extend(['--profile', profile])
737 self.engine_args.extend(['--profile', profile])
738 log.msg('Starting MPIExecEngineSetLauncher: %r' % self.args)
738 log.msg('Starting MPIExecEngineSetLauncher: %r' % self.args)
739 return super(MPIExecEngineSetLauncher, self).start(n)
739 return super(MPIExecEngineSetLauncher, self).start(n)
740
740
741 def find_args(self):
741 def find_args(self):
742 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
742 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
743 self.engine_cmd + self.engine_args
743 self.engine_cmd + self.engine_args
744
744
745
745
746 class WindowsHPCEngineSetLauncher(WindowsHPCLauncher):
746 class WindowsHPCEngineSetLauncher(WindowsHPCLauncher):
747 pass
747 pass
748
748
749
749
750 class PBSEngineSetLauncher(PBSLauncher):
750 class PBSEngineSetLauncher(PBSLauncher):
751
751
752 batch_file_name = Unicode(u'pbs_batch_script_engines', config=True)
752 batch_file_name = Unicode(u'pbs_batch_script_engines', config=True)
753
753
754 def start(self, n, profile=None, cluster_dir=None):
754 def start(self, n, profile=None, cluster_dir=None):
755 """Start n engines by profile or cluster_dir."""
755 """Start n engines by profile or cluster_dir."""
756 if cluster_dir is not None:
756 if cluster_dir is not None:
757 self.program_args.extend(['--cluster-dir', cluster_dir])
757 self.program_args.extend(['--cluster-dir', cluster_dir])
758 if profile is not None:
758 if profile is not None:
759 self.program_args.extend(['-p', profile])
759 self.program_args.extend(['-p', profile])
760 log.msg('Starting PBSEngineSetLauncher: %r' % self.args)
760 log.msg('Starting PBSEngineSetLauncher: %r' % self.args)
761 return super(PBSEngineSetLauncher, self).start(n)
761 return super(PBSEngineSetLauncher, self).start(n)
762
762
763
763
764 class SSHEngineSetLauncher(BaseLauncher):
764 class SSHEngineSetLauncher(BaseLauncher):
765 pass
765 pass
766
766
767
767
768 #-----------------------------------------------------------------------------
768 #-----------------------------------------------------------------------------
769 # A launcher for ipcluster itself!
769 # A launcher for ipcluster itself!
770 #-----------------------------------------------------------------------------
770 #-----------------------------------------------------------------------------
771
771
772
772
773 def find_ipcluster_cmd():
773 def find_ipcluster_cmd():
774 """Find the command line ipcluster program in a cross platform way."""
774 """Find the command line ipcluster program in a cross platform way."""
775 if sys.platform == 'win32':
775 if sys.platform == 'win32':
776 # This logic is needed because the ipcluster script doesn't
776 # This logic is needed because the ipcluster script doesn't
777 # always get installed in the same way or in the same location.
777 # always get installed in the same way or in the same location.
778 from IPython.kernel import ipclusterapp
778 from IPython.kernel import ipclusterapp
779 script_location = ipclusterapp.__file__.replace('.pyc', '.py')
779 script_location = ipclusterapp.__file__.replace('.pyc', '.py')
780 # The -u option here turns on unbuffered output, which is required
780 # The -u option here turns on unbuffered output, which is required
781 # on Win32 to prevent wierd conflict and problems with Twisted.
781 # on Win32 to prevent wierd conflict and problems with Twisted.
782 # Also, use sys.executable to make sure we are picking up the
782 # Also, use sys.executable to make sure we are picking up the
783 # right python exe.
783 # right python exe.
784 cmd = [sys.executable, '-u', script_location]
784 cmd = [sys.executable, '-u', script_location]
785 else:
785 else:
786 # ipcontroller has to be on the PATH in this case.
786 # ipcontroller has to be on the PATH in this case.
787 cmd = ['ipcluster']
787 cmd = ['ipcluster']
788 return cmd
788 return cmd
789
789
790
790
791 class IPClusterLauncher(LocalProcessLauncher):
791 class IPClusterLauncher(LocalProcessLauncher):
792 """Launch the ipcluster program in an external process."""
792 """Launch the ipcluster program in an external process."""
793
793
794 ipcluster_cmd = List(find_ipcluster_cmd(), config=True)
794 ipcluster_cmd = List(find_ipcluster_cmd(), config=True)
795 # Command line arguments to pass to ipcluster.
795 # Command line arguments to pass to ipcluster.
796 ipcluster_args = List(
796 ipcluster_args = List(
797 ['--clean-logs', '--log-to-file', '--log-level', '40'], config=True)
797 ['--clean-logs', '--log-to-file', '--log-level', '40'], config=True)
798 ipcluster_subcommand = Str('start')
798 ipcluster_subcommand = Str('start')
799 ipcluster_n = Int(2)
799 ipcluster_n = Int(2)
800
800
801 def find_args(self):
801 def find_args(self):
802 return self.ipcluster_cmd + [self.ipcluster_subcommand] + \
802 return self.ipcluster_cmd + [self.ipcluster_subcommand] + \
803 ['-n', repr(self.ipcluster_n)] + self.ipcluster_args
803 ['-n', repr(self.ipcluster_n)] + self.ipcluster_args
804
804
805 def start(self):
805 def start(self):
806 log.msg("Starting ipcluster: %r" % self.args)
806 log.msg("Starting ipcluster: %r" % self.args)
807 return super(IPClusterLauncher, self).start()
807 return super(IPClusterLauncher, self).start()
808
808
General Comments 0
You need to be logged in to leave comments. Login now