|
|
#!/usr/bin/env python
|
|
|
# encoding: utf-8
|
|
|
|
|
|
"""Start the IPython Engine."""
|
|
|
|
|
|
__docformat__ = "restructuredtext en"
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
# Copyright (C) 2008 The IPython Development Team
|
|
|
#
|
|
|
# Distributed under the terms of the BSD License. The full license is in
|
|
|
# the file COPYING, distributed as part of this software.
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
# Imports
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
|
# Python looks for an empty string at the beginning of sys.path to enable
|
|
|
# importing from the cwd.
|
|
|
import sys
|
|
|
sys.path.insert(0, '')
|
|
|
|
|
|
from optparse import OptionParser
|
|
|
import os
|
|
|
|
|
|
from twisted.application import service
|
|
|
from twisted.internet import reactor
|
|
|
from twisted.python import log
|
|
|
|
|
|
from IPython.kernel.fcutil import Tub, UnauthenticatedTub
|
|
|
|
|
|
from IPython.kernel.core.config import config_manager as core_config_manager
|
|
|
from IPython.config.cutils import import_item
|
|
|
from IPython.kernel.engineservice import EngineService
|
|
|
|
|
|
# Create various ipython directories if they don't exist.
|
|
|
# This must be done before IPython.kernel.config is imported.
|
|
|
from IPython.iplib import user_setup
|
|
|
from IPython.utils.genutils import get_ipython_dir, get_log_dir, get_security_dir
|
|
|
if os.name == 'posix':
|
|
|
rc_suffix = ''
|
|
|
else:
|
|
|
rc_suffix = '.ini'
|
|
|
user_setup(get_ipython_dir(), rc_suffix, mode='install', interactive=False)
|
|
|
get_log_dir()
|
|
|
get_security_dir()
|
|
|
|
|
|
from IPython.kernel.config import config_manager as kernel_config_manager
|
|
|
from IPython.kernel.engineconnector import EngineConnector
|
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
# Code
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
|
def start_engine():
|
|
|
"""
|
|
|
Start the engine, by creating it and starting the Twisted reactor.
|
|
|
|
|
|
This method does:
|
|
|
|
|
|
* If it exists, runs the `mpi_import_statement` to call `MPI_Init`
|
|
|
* Starts the engine logging
|
|
|
* Creates an IPython shell and wraps it in an `EngineService`
|
|
|
* Creates a `foolscap.Tub` to use in connecting to a controller.
|
|
|
* Uses the tub and the `EngineService` along with a Foolscap URL
|
|
|
(or FURL) to connect to the controller and register the engine
|
|
|
with the controller
|
|
|
"""
|
|
|
kernel_config = kernel_config_manager.get_config_obj()
|
|
|
core_config = core_config_manager.get_config_obj()
|
|
|
|
|
|
|
|
|
# Execute the mpi import statement that needs to call MPI_Init
|
|
|
global mpi
|
|
|
mpikey = kernel_config['mpi']['default']
|
|
|
mpi_import_statement = kernel_config['mpi'].get(mpikey, None)
|
|
|
if mpi_import_statement is not None:
|
|
|
try:
|
|
|
exec mpi_import_statement in globals()
|
|
|
except:
|
|
|
mpi = None
|
|
|
else:
|
|
|
mpi = None
|
|
|
|
|
|
# Start logging
|
|
|
logfile = kernel_config['engine']['logfile']
|
|
|
if logfile:
|
|
|
logfile = logfile + str(os.getpid()) + '.log'
|
|
|
try:
|
|
|
openLogFile = open(logfile, 'w')
|
|
|
except:
|
|
|
openLogFile = sys.stdout
|
|
|
else:
|
|
|
openLogFile = sys.stdout
|
|
|
log.startLogging(openLogFile)
|
|
|
|
|
|
# Create the underlying shell class and EngineService
|
|
|
shell_class = import_item(core_config['shell']['shell_class'])
|
|
|
engine_service = EngineService(shell_class, mpi=mpi)
|
|
|
shell_import_statement = core_config['shell']['import_statement']
|
|
|
if shell_import_statement:
|
|
|
try:
|
|
|
engine_service.execute(shell_import_statement)
|
|
|
except:
|
|
|
log.msg("Error running import_statement: %s" % shell_import_statement)
|
|
|
|
|
|
# Create the service hierarchy
|
|
|
main_service = service.MultiService()
|
|
|
engine_service.setServiceParent(main_service)
|
|
|
tub_service = Tub()
|
|
|
tub_service.setServiceParent(main_service)
|
|
|
# This needs to be called before the connection is initiated
|
|
|
main_service.startService()
|
|
|
|
|
|
# This initiates the connection to the controller and calls
|
|
|
# register_engine to tell the controller we are ready to do work
|
|
|
engine_connector = EngineConnector(tub_service)
|
|
|
furl_file = kernel_config['engine']['furl_file']
|
|
|
log.msg("Using furl file: %s" % furl_file)
|
|
|
|
|
|
def call_connect(engine_service, furl_file):
|
|
|
d = engine_connector.connect_to_controller(engine_service, furl_file)
|
|
|
def handle_error(f):
|
|
|
# If this print statement is replaced by a log.err(f) I get
|
|
|
# an unhandled error, which makes no sense. I shouldn't have
|
|
|
# to use a print statement here. My only thought is that
|
|
|
# at the beginning of the process the logging is still starting up
|
|
|
print "error connecting to controller:", f.getErrorMessage()
|
|
|
reactor.callLater(0.1, reactor.stop)
|
|
|
d.addErrback(handle_error)
|
|
|
|
|
|
reactor.callWhenRunning(call_connect, engine_service, furl_file)
|
|
|
reactor.run()
|
|
|
|
|
|
|
|
|
def init_config():
|
|
|
"""
|
|
|
Initialize the configuration using default and command line options.
|
|
|
"""
|
|
|
|
|
|
parser = OptionParser("""ipengine [options]
|
|
|
|
|
|
Start an IPython engine.
|
|
|
|
|
|
Use the IPYTHONDIR environment variable to change your IPython directory
|
|
|
from the default of .ipython or _ipython. The log and security
|
|
|
subdirectories of your IPython directory will be used by this script
|
|
|
for log files and security files.""")
|
|
|
|
|
|
parser.add_option(
|
|
|
"--furl-file",
|
|
|
type="string",
|
|
|
dest="furl_file",
|
|
|
help="The filename containing the FURL of the controller"
|
|
|
)
|
|
|
parser.add_option(
|
|
|
"--mpi",
|
|
|
type="string",
|
|
|
dest="mpi",
|
|
|
help="How to enable MPI (mpi4py, pytrilinos, or empty string to disable)"
|
|
|
)
|
|
|
parser.add_option(
|
|
|
"-l",
|
|
|
"--logfile",
|
|
|
type="string",
|
|
|
dest="logfile",
|
|
|
help="log file name (default is stdout)"
|
|
|
)
|
|
|
|
|
|
(options, args) = parser.parse_args()
|
|
|
|
|
|
kernel_config = kernel_config_manager.get_config_obj()
|
|
|
# Now override with command line options
|
|
|
if options.furl_file is not None:
|
|
|
kernel_config['engine']['furl_file'] = options.furl_file
|
|
|
if options.logfile is not None:
|
|
|
kernel_config['engine']['logfile'] = options.logfile
|
|
|
if options.mpi is not None:
|
|
|
kernel_config['mpi']['default'] = options.mpi
|
|
|
|
|
|
|
|
|
def main():
|
|
|
"""
|
|
|
After creating the configuration information, start the engine.
|
|
|
"""
|
|
|
init_config()
|
|
|
start_engine()
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
main()
|
|
|
|