##// END OF EJS Templates
The ipengine script has been refactored to use the new config system....
Brian Granger -
Show More
@@ -0,0 +1,257 b''
1 #!/usr/bin/env python
2 # encoding: utf-8
3 """
4 The IPython controller application
5 """
6
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
13
14 #-----------------------------------------------------------------------------
15 # Imports
16 #-----------------------------------------------------------------------------
17
18 import os
19 import sys
20
21 from twisted.application import service
22 from twisted.internet import reactor
23 from twisted.python import log
24
25 from IPython.config.loader import NoConfigDefault
26
27 from IPython.core.application import (
28 ApplicationWithDir,
29 AppWithDirArgParseConfigLoader
30 )
31 from IPython.core import release
32
33 from IPython.utils.importstring import import_item
34
35 from IPython.kernel.engineservice import EngineService
36 from IPython.kernel.fcutil import Tub
37 from IPython.kernel.engineconnector import EngineConnector
38
39 #-----------------------------------------------------------------------------
40 # The main application
41 #-----------------------------------------------------------------------------
42
43
44 cl_args = (
45 # Controller config
46 (('--furl-file',), dict(
47 type=str, dest='Global.furl_file', default=NoConfigDefault,
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 '
50 'security directory of the cluster directory. This location is '
51 'resolved using the --profile and --app-dir options.',
52 metavar='Global.furl_file')
53 ),
54 # MPI
55 (('--mpi',), dict(
56 type=str, dest='MPI.use', default=NoConfigDefault,
57 help='How to enable MPI (mpi4py, pytrilinos, or empty string to disable).',
58 metavar='MPI.use')
59 ),
60 # Global config
61 (('--log-to-file',), dict(
62 action='store_true', dest='Global.log_to_file', default=NoConfigDefault,
63 help='Log to a file in the log directory (default is stdout)')
64 )
65 )
66
67
68 class IPEngineAppCLConfigLoader(AppWithDirArgParseConfigLoader):
69
70 arguments = cl_args
71
72
73 mpi4py_init = """from mpi4py import MPI as mpi
74 mpi.size = mpi.COMM_WORLD.Get_size()
75 mpi.rank = mpi.COMM_WORLD.Get_rank()
76 """
77
78 pytrilinos_init = """from PyTrilinos import Epetra
79 class SimpleStruct:
80 pass
81 mpi = SimpleStruct()
82 mpi.rank = 0
83 mpi.size = 0
84 """
85
86
87 default_config_file_name = 'ipengine_config.py'
88
89
90 class IPEngineApp(ApplicationWithDir):
91
92 name = 'ipengine'
93 app_dir_basename = 'cluster'
94 description = 'Start the IPython engine for parallel computing.'
95 config_file_name = default_config_file_name
96
97 def create_default_config(self):
98 super(IPEngineApp, self).create_default_config()
99
100 # Global config attributes
101 self.default_config.Global.log_to_file = False
102 self.default_config.Global.exec_lines = []
103 # The log and security dir names must match that of the controller
104 self.default_config.Global.log_dir_name = 'log'
105 self.default_config.Global.security_dir_name = 'security'
106 self.default_config.Global.shell_class = 'IPython.kernel.core.interpreter.Interpreter'
107
108 # Configuration related to the controller
109 # This must match the filename (path not included) that the controller
110 # used for the FURL file.
111 self.default_config.Global.furl_file_name = 'ipcontroller-engine.furl'
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
114 self.default_config.Global.furl_file = ''
115
116 # MPI related config attributes
117 self.default_config.MPI.use = ''
118 self.default_config.MPI.mpi4py = mpi4py_init
119 self.default_config.MPI.pytrilinos = pytrilinos_init
120
121 def create_command_line_config(self):
122 """Create and return a command line config loader."""
123 return IPEngineAppCLConfigLoader(
124 description=self.description,
125 version=release.version
126 )
127
128 def post_load_command_line_config(self):
129 pass
130
131 def pre_construct(self):
132 config = self.master_config
133 # Now set the security_dir and log_dir and create them. We use
134 # the names an construct the absolute paths.
135 security_dir = os.path.join(config.Global.app_dir,
136 config.Global.security_dir_name)
137 log_dir = os.path.join(config.Global.app_dir,
138 config.Global.log_dir_name)
139 if not os.path.isdir(security_dir):
140 os.mkdir(security_dir, 0700)
141 else:
142 os.chmod(security_dir, 0700)
143 if not os.path.isdir(log_dir):
144 os.mkdir(log_dir, 0777)
145
146 self.security_dir = config.Global.security_dir = security_dir
147 self.log_dir = config.Global.log_dir = log_dir
148 self.log.info("Log directory set to: %s" % self.log_dir)
149 self.log.info("Security directory set to: %s" % self.security_dir)
150
151 self.find_cont_furl_file()
152
153 def find_cont_furl_file(self):
154 config = self.master_config
155 # Find the actual controller FURL file
156 if os.path.isfile(config.Global.furl_file):
157 return
158 else:
159 # We should know what the app dir is
160 try_this = os.path.join(
161 config.Global.app_dir,
162 config.Global.security_dir,
163 config.Global.furl_file_name
164 )
165 if os.path.isfile(try_this):
166 config.Global.furl_file = try_this
167 return
168 else:
169 self.log.critical("Could not find a valid controller FURL file.")
170 self.abort()
171
172 def construct(self):
173 # I am a little hesitant to put these into InteractiveShell itself.
174 # But that might be the place for them
175 sys.path.insert(0, '')
176
177 self.start_mpi()
178 self.start_logging()
179
180 # Create the underlying shell class and EngineService
181 shell_class = import_item(self.master_config.Global.shell_class)
182 self.engine_service = EngineService(shell_class, mpi=mpi)
183
184 self.exec_lines()
185
186 # Create the service hierarchy
187 self.main_service = service.MultiService()
188 self.engine_service.setServiceParent(self.main_service)
189 self.tub_service = Tub()
190 self.tub_service.setServiceParent(self.main_service)
191 # This needs to be called before the connection is initiated
192 self.main_service.startService()
193
194 # This initiates the connection to the controller and calls
195 # register_engine to tell the controller we are ready to do work
196 self.engine_connector = EngineConnector(self.tub_service)
197
198 log.msg("Using furl file: %s" % self.master_config.Global.furl_file)
199
200 reactor.callWhenRunning(self.call_connect)
201
202 def call_connect(self):
203 d = self.engine_connector.connect_to_controller(
204 self.engine_service,
205 self.master_config.Global.furl_file
206 )
207
208 def handle_error(f):
209 # If this print statement is replaced by a log.err(f) I get
210 # an unhandled error, which makes no sense. I shouldn't have
211 # to use a print statement here. My only thought is that
212 # at the beginning of the process the logging is still starting up
213 print "Error connecting to controller:", f.getErrorMessage()
214 reactor.callLater(0.1, reactor.stop)
215
216 d.addErrback(handle_error)
217
218 def start_mpi(self):
219 global mpi
220 mpikey = self.master_config.MPI.use
221 mpi_import_statement = self.master_config.MPI.get(mpikey, None)
222 if mpi_import_statement is not None:
223 try:
224 self.log.info("Initializing MPI:")
225 self.log.info(mpi_import_statement)
226 exec mpi_import_statement in globals()
227 except:
228 mpi = None
229 else:
230 mpi = None
231
232 def start_logging(self):
233 if self.master_config.Global.log_to_file:
234 log_filename = self.name + '-' + str(os.getpid()) + '.log'
235 logfile = os.path.join(self.log_dir, log_filename)
236 open_log_file = open(logfile, 'w')
237 else:
238 open_log_file = sys.stdout
239 log.startLogging(open_log_file)
240
241 def exec_lines(self):
242 for line in self.master_config.Global.exec_lines:
243 try:
244 log.msg("Executing statement: '%s'" % line)
245 self.engine_service.execute(line)
246 except:
247 log.msg("Error executing statement: %s" % line)
248
249 def start_app(self):
250 # Start the controller service and set things running
251 reactor.run()
252
253
254 def launch_new_instance():
255 """Create and run the IPython controller"""
256 app = IPEngineApp()
257 app.start()
@@ -1,19 +1,25 b''
1 c = get_config()
1 c = get_config()
2
2
3 c.MPI.default = 'mpi4py'
3 c.MPI.use = 'mpi4py'
4
4
5 c.MPI.mpi4py = """from mpi4py import MPI as mpi
5 c.MPI.mpi4py = """from mpi4py import MPI as mpi
6 mpi.size = mpi.COMM_WORLD.Get_size()
6 mpi.size = mpi.COMM_WORLD.Get_size()
7 mpi.rank = mpi.COMM_WORLD.Get_rank()
7 mpi.rank = mpi.COMM_WORLD.Get_rank()
8 """
8 """
9
9
10 c.MPI.pytrilinos = """from PyTrilinos import Epetra
10 c.MPI.pytrilinos = """from PyTrilinos import Epetra
11 class SimpleStruct:
11 class SimpleStruct:
12 pass
12 pass
13 mpi = SimpleStruct()
13 mpi = SimpleStruct()
14 mpi.rank = 0
14 mpi.rank = 0
15 mpi.size = 0
15 mpi.size = 0
16 """
16 """
17
17
18 c.Global.logfile = ''
18 c.Global.log_to_file = False
19 c.Global.furl_file = 'ipcontroller-engine.furl'
19 c.Global.exec_lines = []
20 c.Global.log_dir_name = 'log'
21 c.Global.security_dir_name = 'security'
22 c.Global.shell_class = 'IPython.kernel.core.interpreter.Interpreter'
23 self.default_config.Global.furl_file_name = 'ipcontroller-engine.furl'
24 self.default_config.Global.furl_file = ''
25
@@ -1,452 +1,454 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 Authors:
6 Authors:
7
7
8 * Brian Granger
8 * Brian Granger
9 * Fernando Perez
9 * Fernando Perez
10
10
11 Notes
11 Notes
12 -----
12 -----
13 """
13 """
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Copyright (C) 2008-2009 The IPython Development Team
16 # Copyright (C) 2008-2009 The IPython Development Team
17 #
17 #
18 # Distributed under the terms of the BSD License. The full license is in
18 # Distributed under the terms of the BSD License. The full license is in
19 # the file COPYING, distributed as part of this software.
19 # the file COPYING, distributed as part of this software.
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Imports
23 # Imports
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 import logging
26 import logging
27 import os
27 import os
28
28
29 import sys
29 import sys
30 import traceback
30 import traceback
31 from copy import deepcopy
31 from copy import deepcopy
32
32
33 from IPython.core import release
33 from IPython.core import release
34 from IPython.utils.genutils import get_ipython_dir, filefind
34 from IPython.utils.genutils import get_ipython_dir, filefind
35 from IPython.config.loader import (
35 from IPython.config.loader import (
36 PyFileConfigLoader,
36 PyFileConfigLoader,
37 ArgParseConfigLoader,
37 ArgParseConfigLoader,
38 Config,
38 Config,
39 NoConfigDefault
39 NoConfigDefault
40 )
40 )
41
41
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 # Classes and functions
43 # Classes and functions
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45
45
46
46
47 class BaseAppArgParseConfigLoader(ArgParseConfigLoader):
47 class BaseAppArgParseConfigLoader(ArgParseConfigLoader):
48 """Default command line options for IPython based applications."""
48 """Default command line options for IPython based applications."""
49
49
50 def _add_other_arguments(self):
50 def _add_other_arguments(self):
51 self.parser.add_argument('-ipythondir', '--ipython-dir',
51 self.parser.add_argument('-ipythondir', '--ipython-dir',
52 dest='Global.ipythondir',type=str,
52 dest='Global.ipythondir',type=str,
53 help='Set to override default location of Global.ipythondir.',
53 help='Set to override default location of Global.ipythondir.',
54 default=NoConfigDefault,
54 default=NoConfigDefault,
55 metavar='Global.ipythondir')
55 metavar='Global.ipythondir')
56 self.parser.add_argument('-p','-profile', '--profile',
56 self.parser.add_argument('-p','-profile', '--profile',
57 dest='Global.profile',type=str,
57 dest='Global.profile',type=str,
58 help='The string name of the ipython profile to be used.',
58 help='The string name of the ipython profile to be used.',
59 default=NoConfigDefault,
59 default=NoConfigDefault,
60 metavar='Global.profile')
60 metavar='Global.profile')
61 self.parser.add_argument('-log_level', '--log-level',
61 self.parser.add_argument('-log_level', '--log-level',
62 dest="Global.log_level",type=int,
62 dest="Global.log_level",type=int,
63 help='Set the log level (0,10,20,30,40,50). Default is 30.',
63 help='Set the log level (0,10,20,30,40,50). Default is 30.',
64 default=NoConfigDefault)
64 default=NoConfigDefault,
65 metavar='Global.log_level')
65 self.parser.add_argument('-config_file', '--config-file',
66 self.parser.add_argument('-config_file', '--config-file',
66 dest='Global.config_file',type=str,
67 dest='Global.config_file',type=str,
67 help='Set the config file name to override default.',
68 help='Set the config file name to override default.',
68 default=NoConfigDefault,
69 default=NoConfigDefault,
69 metavar='Global.config_file')
70 metavar='Global.config_file')
70
71
71
72
72 class ApplicationError(Exception):
73 class ApplicationError(Exception):
73 pass
74 pass
74
75
75
76
76 class Application(object):
77 class Application(object):
77 """Load a config, construct an app and run it.
78 """Load a config, construct an app and run it.
78 """
79 """
79
80
80 name = 'ipython'
81 name = 'ipython'
81 description = 'IPython: an enhanced interactive Python shell.'
82 description = 'IPython: an enhanced interactive Python shell.'
82 config_file_name = 'ipython_config.py'
83 config_file_name = 'ipython_config.py'
83 default_log_level = logging.WARN
84 default_log_level = logging.WARN
84
85
85
86
86 def __init__(self):
87 def __init__(self):
87 self.init_logger()
88 self.init_logger()
88 self.default_config_file_name = self.config_file_name
89 self.default_config_file_name = self.config_file_name
89
90
90 def init_logger(self):
91 def init_logger(self):
91 self.log = logging.getLogger(self.__class__.__name__)
92 self.log = logging.getLogger(self.__class__.__name__)
92 # This is used as the default until the command line arguments are read.
93 # This is used as the default until the command line arguments are read.
93 self.log.setLevel(self.default_log_level)
94 self.log.setLevel(self.default_log_level)
94 self._log_handler = logging.StreamHandler()
95 self._log_handler = logging.StreamHandler()
95 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
96 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
96 self._log_handler.setFormatter(self._log_formatter)
97 self._log_handler.setFormatter(self._log_formatter)
97 self.log.addHandler(self._log_handler)
98 self.log.addHandler(self._log_handler)
98
99
99 def _set_log_level(self, level):
100 def _set_log_level(self, level):
100 self.log.setLevel(level)
101 self.log.setLevel(level)
101
102
102 def _get_log_level(self):
103 def _get_log_level(self):
103 return self.log.level
104 return self.log.level
104
105
105 log_level = property(_get_log_level, _set_log_level)
106 log_level = property(_get_log_level, _set_log_level)
106
107
107 def start(self):
108 def start(self):
108 """Start the application."""
109 """Start the application."""
109 self.attempt(self.create_default_config)
110 self.attempt(self.create_default_config)
110 self.log_default_config()
111 self.log_default_config()
111 self.set_default_config_log_level()
112 self.set_default_config_log_level()
112 self.attempt(self.pre_load_command_line_config)
113 self.attempt(self.pre_load_command_line_config)
113 self.attempt(self.load_command_line_config, action='abort')
114 self.attempt(self.load_command_line_config, action='abort')
114 self.set_command_line_config_log_level()
115 self.set_command_line_config_log_level()
115 self.attempt(self.post_load_command_line_config)
116 self.attempt(self.post_load_command_line_config)
116 self.log_command_line_config()
117 self.log_command_line_config()
117 self.attempt(self.find_ipythondir)
118 self.attempt(self.find_ipythondir)
118 self.attempt(self.find_config_file_name)
119 self.attempt(self.find_config_file_name)
119 self.attempt(self.find_config_file_paths)
120 self.attempt(self.find_config_file_paths)
120 self.attempt(self.pre_load_file_config)
121 self.attempt(self.pre_load_file_config)
121 self.attempt(self.load_file_config)
122 self.attempt(self.load_file_config)
122 self.set_file_config_log_level()
123 self.set_file_config_log_level()
123 self.attempt(self.post_load_file_config)
124 self.attempt(self.post_load_file_config)
124 self.log_file_config()
125 self.log_file_config()
125 self.attempt(self.merge_configs)
126 self.attempt(self.merge_configs)
126 self.log_master_config()
127 self.log_master_config()
127 self.attempt(self.pre_construct)
128 self.attempt(self.pre_construct)
128 self.attempt(self.construct)
129 self.attempt(self.construct)
129 self.attempt(self.post_construct)
130 self.attempt(self.post_construct)
130 self.attempt(self.start_app)
131 self.attempt(self.start_app)
131
132
132 #-------------------------------------------------------------------------
133 #-------------------------------------------------------------------------
133 # Various stages of Application creation
134 # Various stages of Application creation
134 #-------------------------------------------------------------------------
135 #-------------------------------------------------------------------------
135
136
136 def create_default_config(self):
137 def create_default_config(self):
137 """Create defaults that can't be set elsewhere.
138 """Create defaults that can't be set elsewhere.
138
139
139 For the most part, we try to set default in the class attributes
140 For the most part, we try to set default in the class attributes
140 of Components. But, defaults the top-level Application (which is
141 of Components. But, defaults the top-level Application (which is
141 not a HasTraitlets or Component) are not set in this way. Instead
142 not a HasTraitlets or Component) are not set in this way. Instead
142 we set them here. The Global section is for variables like this that
143 we set them here. The Global section is for variables like this that
143 don't belong to a particular component.
144 don't belong to a particular component.
144 """
145 """
145 self.default_config = Config()
146 self.default_config = Config()
146 self.default_config.Global.ipythondir = get_ipython_dir()
147 self.default_config.Global.ipythondir = get_ipython_dir()
147 self.default_config.Global.log_level = self.log_level
148 self.default_config.Global.log_level = self.log_level
148
149
149 def log_default_config(self):
150 def log_default_config(self):
150 self.log.debug('Default config loaded:')
151 self.log.debug('Default config loaded:')
151 self.log.debug(repr(self.default_config))
152 self.log.debug(repr(self.default_config))
152
153
153 def set_default_config_log_level(self):
154 def set_default_config_log_level(self):
154 try:
155 try:
155 self.log_level = self.default_config.Global.log_level
156 self.log_level = self.default_config.Global.log_level
156 except AttributeError:
157 except AttributeError:
157 # Fallback to the default_log_level class attribute
158 # Fallback to the default_log_level class attribute
158 pass
159 pass
159
160
160 def create_command_line_config(self):
161 def create_command_line_config(self):
161 """Create and return a command line config loader."""
162 """Create and return a command line config loader."""
162 return BaseAppArgParseConfigLoader(
163 return BaseAppArgParseConfigLoader(
163 description=self.description,
164 description=self.description,
164 version=release.version
165 version=release.version
165 )
166 )
166
167
167 def pre_load_command_line_config(self):
168 def pre_load_command_line_config(self):
168 """Do actions just before loading the command line config."""
169 """Do actions just before loading the command line config."""
169 pass
170 pass
170
171
171 def load_command_line_config(self):
172 def load_command_line_config(self):
172 """Load the command line config."""
173 """Load the command line config."""
173 loader = self.create_command_line_config()
174 loader = self.create_command_line_config()
174 self.command_line_config = loader.load_config()
175 self.command_line_config = loader.load_config()
175 self.extra_args = loader.get_extra_args()
176 self.extra_args = loader.get_extra_args()
176
177
177 def set_command_line_config_log_level(self):
178 def set_command_line_config_log_level(self):
178 try:
179 try:
179 self.log_level = self.command_line_config.Global.log_level
180 self.log_level = self.command_line_config.Global.log_level
180 except AttributeError:
181 except AttributeError:
181 pass
182 pass
182
183
183 def post_load_command_line_config(self):
184 def post_load_command_line_config(self):
184 """Do actions just after loading the command line config."""
185 """Do actions just after loading the command line config."""
185 pass
186 pass
186
187
187 def log_command_line_config(self):
188 def log_command_line_config(self):
188 self.log.debug("Command line config loaded:")
189 self.log.debug("Command line config loaded:")
189 self.log.debug(repr(self.command_line_config))
190 self.log.debug(repr(self.command_line_config))
190
191
191 def find_ipythondir(self):
192 def find_ipythondir(self):
192 """Set the IPython directory.
193 """Set the IPython directory.
193
194
194 This sets ``self.ipythondir``, but the actual value that is passed
195 This sets ``self.ipythondir``, but the actual value that is passed
195 to the application is kept in either ``self.default_config`` or
196 to the application is kept in either ``self.default_config`` or
196 ``self.command_line_config``. This also added ``self.ipythondir`` to
197 ``self.command_line_config``. This also added ``self.ipythondir`` to
197 ``sys.path`` so config files there can be references by other config
198 ``sys.path`` so config files there can be references by other config
198 files.
199 files.
199 """
200 """
200
201
201 try:
202 try:
202 self.ipythondir = self.command_line_config.Global.ipythondir
203 self.ipythondir = self.command_line_config.Global.ipythondir
203 except AttributeError:
204 except AttributeError:
204 self.ipythondir = self.default_config.Global.ipythondir
205 self.ipythondir = self.default_config.Global.ipythondir
205 sys.path.append(os.path.abspath(self.ipythondir))
206 sys.path.append(os.path.abspath(self.ipythondir))
206 if not os.path.isdir(self.ipythondir):
207 if not os.path.isdir(self.ipythondir):
207 os.makedirs(self.ipythondir, mode=0777)
208 os.makedirs(self.ipythondir, mode=0777)
208 self.log.debug("IPYTHONDIR set to: %s" % self.ipythondir)
209 self.log.debug("IPYTHONDIR set to: %s" % self.ipythondir)
209
210
210 def find_config_file_name(self):
211 def find_config_file_name(self):
211 """Find the config file name for this application.
212 """Find the config file name for this application.
212
213
213 This must set ``self.config_file_name`` to the filename of the
214 This must set ``self.config_file_name`` to the filename of the
214 config file to use (just the filename). The search paths for the
215 config file to use (just the filename). The search paths for the
215 config file are set in :meth:`find_config_file_paths` and then passed
216 config file are set in :meth:`find_config_file_paths` and then passed
216 to the config file loader where they are resolved to an absolute path.
217 to the config file loader where they are resolved to an absolute path.
217
218
218 If a profile has been set at the command line, this will resolve
219 If a profile has been set at the command line, this will resolve
219 it.
220 it.
220 """
221 """
221
222
222 try:
223 try:
223 self.config_file_name = self.command_line_config.Global.config_file
224 self.config_file_name = self.command_line_config.Global.config_file
224 except AttributeError:
225 except AttributeError:
225 pass
226 pass
226
227
227 try:
228 try:
228 self.profile_name = self.command_line_config.Global.profile
229 self.profile_name = self.command_line_config.Global.profile
229 name_parts = self.config_file_name.split('.')
230 name_parts = self.config_file_name.split('.')
230 name_parts.insert(1, '_' + self.profile_name + '.')
231 name_parts.insert(1, '_' + self.profile_name + '.')
231 self.config_file_name = ''.join(name_parts)
232 self.config_file_name = ''.join(name_parts)
232 except AttributeError:
233 except AttributeError:
233 pass
234 pass
234
235
235 def find_config_file_paths(self):
236 def find_config_file_paths(self):
236 """Set the search paths for resolving the config file.
237 """Set the search paths for resolving the config file.
237
238
238 This must set ``self.config_file_paths`` to a sequence of search
239 This must set ``self.config_file_paths`` to a sequence of search
239 paths to pass to the config file loader.
240 paths to pass to the config file loader.
240 """
241 """
241 self.config_file_paths = (os.getcwd(), self.ipythondir)
242 self.config_file_paths = (os.getcwd(), self.ipythondir)
242
243
243 def pre_load_file_config(self):
244 def pre_load_file_config(self):
244 """Do actions before the config file is loaded."""
245 """Do actions before the config file is loaded."""
245 pass
246 pass
246
247
247 def load_file_config(self):
248 def load_file_config(self):
248 """Load the config file.
249 """Load the config file.
249
250
250 This tries to load the config file from disk. If successful, the
251 This tries to load the config file from disk. If successful, the
251 ``CONFIG_FILE`` config variable is set to the resolved config file
252 ``CONFIG_FILE`` config variable is set to the resolved config file
252 location. If not successful, an empty config is used.
253 location. If not successful, an empty config is used.
253 """
254 """
254 self.log.debug("Attempting to load config file: <%s>" % self.config_file_name)
255 self.log.debug("Attempting to load config file: %s" % self.config_file_name)
255 loader = PyFileConfigLoader(self.config_file_name,
256 loader = PyFileConfigLoader(self.config_file_name,
256 path=self.config_file_paths)
257 path=self.config_file_paths)
257 try:
258 try:
258 self.file_config = loader.load_config()
259 self.file_config = loader.load_config()
259 self.file_config.Global.config_file = loader.full_filename
260 self.file_config.Global.config_file = loader.full_filename
260 except IOError:
261 except IOError:
261 # Only warn if the default config file was NOT being used.
262 # Only warn if the default config file was NOT being used.
262 if not self.config_file_name==self.default_config_file_name:
263 if not self.config_file_name==self.default_config_file_name:
263 self.log.warn("Config file not found, skipping: <%s>" % \
264 self.log.warn("Config file not found, skipping: %s" % \
264 self.config_file_name, exc_info=True)
265 self.config_file_name, exc_info=True)
265 self.file_config = Config()
266 self.file_config = Config()
266 except:
267 except:
267 self.log.warn("Error loading config file: <%s>" % \
268 self.log.warn("Error loading config file: %s" % \
268 self.config_file_name, exc_info=True)
269 self.config_file_name, exc_info=True)
269 self.file_config = Config()
270 self.file_config = Config()
270
271
271 def set_file_config_log_level(self):
272 def set_file_config_log_level(self):
272 # We need to keeep self.log_level updated. But we only use the value
273 # We need to keeep self.log_level updated. But we only use the value
273 # of the file_config if a value was not specified at the command
274 # of the file_config if a value was not specified at the command
274 # line, because the command line overrides everything.
275 # line, because the command line overrides everything.
275 if not hasattr(self.command_line_config.Global, 'log_level'):
276 if not hasattr(self.command_line_config.Global, 'log_level'):
276 try:
277 try:
277 self.log_level = self.file_config.Global.log_level
278 self.log_level = self.file_config.Global.log_level
278 except AttributeError:
279 except AttributeError:
279 pass # Use existing value
280 pass # Use existing value
280
281
281 def post_load_file_config(self):
282 def post_load_file_config(self):
282 """Do actions after the config file is loaded."""
283 """Do actions after the config file is loaded."""
283 pass
284 pass
284
285
285 def log_file_config(self):
286 def log_file_config(self):
286 if hasattr(self.file_config.Global, 'config_file'):
287 if hasattr(self.file_config.Global, 'config_file'):
287 self.log.debug("Config file loaded: <%s>" % self.file_config.Global.config_file)
288 self.log.debug("Config file loaded: %s" % self.file_config.Global.config_file)
288 self.log.debug(repr(self.file_config))
289 self.log.debug(repr(self.file_config))
289
290
290 def merge_configs(self):
291 def merge_configs(self):
291 """Merge the default, command line and file config objects."""
292 """Merge the default, command line and file config objects."""
292 config = Config()
293 config = Config()
293 config._merge(self.default_config)
294 config._merge(self.default_config)
294 config._merge(self.file_config)
295 config._merge(self.file_config)
295 config._merge(self.command_line_config)
296 config._merge(self.command_line_config)
296 self.master_config = config
297 self.master_config = config
297
298
298 def log_master_config(self):
299 def log_master_config(self):
299 self.log.debug("Master config created:")
300 self.log.debug("Master config created:")
300 self.log.debug(repr(self.master_config))
301 self.log.debug(repr(self.master_config))
301
302
302 def pre_construct(self):
303 def pre_construct(self):
303 """Do actions after the config has been built, but before construct."""
304 """Do actions after the config has been built, but before construct."""
304 pass
305 pass
305
306
306 def construct(self):
307 def construct(self):
307 """Construct the main components that make up this app."""
308 """Construct the main components that make up this app."""
308 self.log.debug("Constructing components for application")
309 self.log.debug("Constructing components for application")
309
310
310 def post_construct(self):
311 def post_construct(self):
311 """Do actions after construct, but before starting the app."""
312 """Do actions after construct, but before starting the app."""
312 pass
313 pass
313
314
314 def start_app(self):
315 def start_app(self):
315 """Actually start the app."""
316 """Actually start the app."""
316 self.log.debug("Starting application")
317 self.log.debug("Starting application")
317
318
318 #-------------------------------------------------------------------------
319 #-------------------------------------------------------------------------
319 # Utility methods
320 # Utility methods
320 #-------------------------------------------------------------------------
321 #-------------------------------------------------------------------------
321
322
322 def abort(self):
323 def abort(self):
323 """Abort the starting of the application."""
324 """Abort the starting of the application."""
324 self.log.critical("Aborting application: %s" % self.name, exc_info=True)
325 self.log.critical("Aborting application: %s" % self.name, exc_info=True)
325 sys.exit(1)
326 sys.exit(1)
326
327
327 def exit(self):
328 def exit(self):
328 self.log.critical("Aborting application: %s" % self.name)
329 self.log.critical("Aborting application: %s" % self.name)
329 sys.exit(1)
330 sys.exit(1)
330
331
331 def attempt(self, func, action='abort'):
332 def attempt(self, func, action='abort'):
332 try:
333 try:
333 func()
334 func()
334 except SystemExit:
335 except SystemExit:
335 self.exit()
336 self.exit()
336 except:
337 except:
337 if action == 'abort':
338 if action == 'abort':
338 self.abort()
339 self.abort()
339 elif action == 'exit':
340 elif action == 'exit':
340 self.exit()
341 self.exit()
341
342
342
343
343 class AppWithDirArgParseConfigLoader(ArgParseConfigLoader):
344 class AppWithDirArgParseConfigLoader(ArgParseConfigLoader):
344 """Default command line options for IPython based applications."""
345 """Default command line options for IPython based applications."""
345
346
346 def _add_other_arguments(self):
347 def _add_other_arguments(self):
347 self.parser.add_argument('-ipythondir', '--ipython-dir',
348 self.parser.add_argument('-ipythondir', '--ipython-dir',
348 dest='Global.ipythondir',type=str,
349 dest='Global.ipythondir',type=str,
349 help='Set to override default location of Global.ipythondir.',
350 help='Set to override default location of Global.ipythondir.',
350 default=NoConfigDefault,
351 default=NoConfigDefault,
351 metavar='Global.ipythondir')
352 metavar='Global.ipythondir')
352 self.parser.add_argument('-p','-profile', '--profile',
353 self.parser.add_argument('-p','-profile', '--profile',
353 dest='Global.profile',type=str,
354 dest='Global.profile',type=str,
354 help='The string name of the profile to be used. This determines '
355 help='The string name of the profile to be used. This determines '
355 'the name of the application dir: basename_<profile>. The basename is '
356 'the name of the application dir: basename_<profile>. The basename is '
356 'determined by the particular application. The default profile '
357 'determined by the particular application. The default profile '
357 'is named "default". This convention is used if the -app_dir '
358 'is named "default". This convention is used if the -app_dir '
358 'option is not used.',
359 'option is not used.',
359 default=NoConfigDefault,
360 default=NoConfigDefault,
360 metavar='Global.profile')
361 metavar='Global.profile')
361 self.parser.add_argument('-log_level', '--log-level',
362 self.parser.add_argument('-log_level', '--log-level',
362 dest="Global.log_level",type=int,
363 dest="Global.log_level",type=int,
363 help='Set the log level (0,10,20,30,40,50). Default is 30.',
364 help='Set the log level (0,10,20,30,40,50). Default is 30.',
364 default=NoConfigDefault)
365 default=NoConfigDefault)
365 self.parser.add_argument('-app_dir', '--app-dir',
366 self.parser.add_argument('-app_dir', '--app-dir',
366 dest='Global.app_dir',type=str,
367 dest='Global.app_dir',type=str,
367 help='Set the application dir where everything for this '
368 help='Set the application dir where everything for this '
368 'application will be found (including the config file). This '
369 'application will be found (including the config file). This '
369 'overrides the logic used by the profile option.',
370 'overrides the logic used by the profile option.',
370 default=NoConfigDefault,
371 default=NoConfigDefault,
371 metavar='Global.app_dir')
372 metavar='Global.app_dir')
372
373
373
374
374 class ApplicationWithDir(Application):
375 class ApplicationWithDir(Application):
375 """An application that puts everything into a application directory.
376 """An application that puts everything into a application directory.
376
377
377 Instead of looking for things in the ipythondir, this type of application
378 Instead of looking for things in the ipythondir, this type of application
378 will use its own private directory called the "application directory"
379 will use its own private directory called the "application directory"
379 for things like config files, log files, etc.
380 for things like config files, log files, etc.
380
381
381 The application directory is resolved as follows:
382 The application directory is resolved as follows:
382
383
383 * If the ``--app-dir`` option is given, it is used.
384 * If the ``--app-dir`` option is given, it is used.
384 * If ``--app-dir`` is not given, the application directory is resolve using
385 * If ``--app-dir`` is not given, the application directory is resolve using
385 ``app_dir_basename`` and ``profile`` as ``<app_dir_basename>_<profile>``.
386 ``app_dir_basename`` and ``profile`` as ``<app_dir_basename>_<profile>``.
386 The search path for this directory is then i) cwd if it is found there
387 The search path for this directory is then i) cwd if it is found there
387 and ii) in ipythondir otherwise.
388 and ii) in ipythondir otherwise.
388
389
389 The config file for the application is to be put in the application
390 The config file for the application is to be put in the application
390 dir and named the value of the ``config_file_name`` class attribute.
391 dir and named the value of the ``config_file_name`` class attribute.
391 """
392 """
392
393
393 # The basename used for the application dir: <app_dir_basename>_<profile>
394 # The basename used for the application dir: <app_dir_basename>_<profile>
394 app_dir_basename = 'cluster'
395 app_dir_basename = 'cluster'
395
396
396 def create_default_config(self):
397 def create_default_config(self):
397 super(ApplicationWithDir, self).create_default_config()
398 super(ApplicationWithDir, self).create_default_config()
398 self.default_config.Global.profile = 'default'
399 self.default_config.Global.profile = 'default'
399 # The application dir. This is empty initially so the default is to
400 # The application dir. This is empty initially so the default is to
400 # try to resolve this using the profile.
401 # try to resolve this using the profile.
401 self.default_config.Global.app_dir = ''
402 self.default_config.Global.app_dir = ''
402
403
403 def create_command_line_config(self):
404 def create_command_line_config(self):
404 """Create and return a command line config loader."""
405 """Create and return a command line config loader."""
405 return AppWithDirArgParseConfigLoader(
406 return AppWithDirArgParseConfigLoader(
406 description=self.description,
407 description=self.description,
407 version=release.version
408 version=release.version
408 )
409 )
409
410
410 def find_config_file_name(self):
411 def find_config_file_name(self):
411 """Find the config file name for this application."""
412 """Find the config file name for this application."""
412 self.find_app_dir()
413 self.find_app_dir()
413 self.create_app_dir()
414 self.create_app_dir()
414
415
415 def find_app_dir(self):
416 def find_app_dir(self):
416 """This resolves the app directory.
417 """This resolves the app directory.
417
418
418 This method must set ``self.app_dir`` to the location of the app
419 This method must set ``self.app_dir`` to the location of the app
419 dir.
420 dir.
420 """
421 """
421 # Instead, first look for an explicit app_dir
422 # Instead, first look for an explicit app_dir
422 try:
423 try:
423 self.app_dir = self.command_line_config.Global.app_dir
424 self.app_dir = self.command_line_config.Global.app_dir
424 except AttributeError:
425 except AttributeError:
425 self.app_dir = self.default_config.Global.app_dir
426 self.app_dir = self.default_config.Global.app_dir
426 self.app_dir = os.path.expandvars(os.path.expanduser(self.app_dir))
427 self.app_dir = os.path.expandvars(os.path.expanduser(self.app_dir))
427 if not self.app_dir:
428 if not self.app_dir:
428 # Then look for a profile
429 # Then look for a profile
429 try:
430 try:
430 self.profile = self.command_line_config.Global.profile
431 self.profile = self.command_line_config.Global.profile
431 except AttributeError:
432 except AttributeError:
432 self.profile = self.default_config.Global.profile
433 self.profile = self.default_config.Global.profile
433 app_dir_name = self.app_dir_basename + '_' + self.profile
434 app_dir_name = self.app_dir_basename + '_' + self.profile
434 try_this = os.path.join(os.getcwd(), app_dir_name)
435 try_this = os.path.join(os.getcwd(), app_dir_name)
435 if os.path.isdir(try_this):
436 if os.path.isdir(try_this):
436 self.app_dir = try_this
437 self.app_dir = try_this
437 else:
438 else:
438 self.app_dir = os.path.join(self.ipythondir, app_dir_name)
439 self.app_dir = os.path.join(self.ipythondir, app_dir_name)
439 # These have to be set because they could be different from the one
440 # These have to be set because they could be different from the one
440 # that we just computed. Because command line has the highest
441 # that we just computed. Because command line has the highest
441 # priority, this will always end up in the master_config.
442 # priority, this will always end up in the master_config.
442 self.default_config.Global.app_dir = self.app_dir
443 self.default_config.Global.app_dir = self.app_dir
443 self.command_line_config.Global.app_dir = self.app_dir
444 self.command_line_config.Global.app_dir = self.app_dir
445 self.log.info("Application directory set to: %s" % self.app_dir)
444
446
445 def create_app_dir(self):
447 def create_app_dir(self):
446 """Make sure that the app dir exists."""
448 """Make sure that the app dir exists."""
447 if not os.path.isdir(self.app_dir):
449 if not os.path.isdir(self.app_dir):
448 os.makedirs(self.app_dir, mode=0777)
450 os.makedirs(self.app_dir, mode=0777)
449
451
450 def find_config_file_paths(self):
452 def find_config_file_paths(self):
451 """Set the search paths for resolving the config file."""
453 """Set the search paths for resolving the config file."""
452 self.config_file_paths = (self.app_dir,)
454 self.config_file_paths = (self.app_dir,)
@@ -1,273 +1,275 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 copy
18 import copy
19 import logging
19 import logging
20 import os
20 import os
21 import sys
21 import sys
22
22
23 from twisted.application import service
23 from twisted.application import service
24 from twisted.internet import reactor, defer
24 from twisted.internet import reactor, defer
25 from twisted.python import log
25 from twisted.python import log
26
26
27 from IPython.config.loader import Config, NoConfigDefault
27 from IPython.config.loader import Config, NoConfigDefault
28
28
29 from IPython.core.application import (
29 from IPython.core.application import (
30 ApplicationWithDir,
30 ApplicationWithDir,
31 AppWithDirArgParseConfigLoader
31 AppWithDirArgParseConfigLoader
32 )
32 )
33
33
34 from IPython.core import release
34 from IPython.core import release
35
35
36 from IPython.utils.traitlets import Int, Str, Bool, Instance
36 from IPython.utils.traitlets import Int, Str, Bool, Instance
37 from IPython.utils.importstring import import_item
37 from IPython.utils.importstring import import_item
38
38
39 from IPython.kernel import controllerservice
39 from IPython.kernel import controllerservice
40 from IPython.kernel.configobjfactory import (
40 from IPython.kernel.configobjfactory import (
41 ConfiguredObjectFactory,
41 ConfiguredObjectFactory,
42 AdaptedConfiguredObjectFactory
42 AdaptedConfiguredObjectFactory
43 )
43 )
44
44
45 from IPython.kernel.fcutil import FCServiceFactory
45 from IPython.kernel.fcutil import FCServiceFactory
46
46
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48 # Default interfaces
48 # Default interfaces
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50
50
51
51
52 # The default client interfaces for FCClientServiceFactory.interfaces
52 # The default client interfaces for FCClientServiceFactory.interfaces
53 default_client_interfaces = Config()
53 default_client_interfaces = Config()
54 default_client_interfaces.Task.interface_chain = [
54 default_client_interfaces.Task.interface_chain = [
55 'IPython.kernel.task.ITaskController',
55 'IPython.kernel.task.ITaskController',
56 'IPython.kernel.taskfc.IFCTaskController'
56 'IPython.kernel.taskfc.IFCTaskController'
57 ]
57 ]
58
58
59 default_client_interfaces.Task.furl_file = 'ipcontroller-tc.furl'
59 default_client_interfaces.Task.furl_file = 'ipcontroller-tc.furl'
60
60
61 default_client_interfaces.MultiEngine.interface_chain = [
61 default_client_interfaces.MultiEngine.interface_chain = [
62 'IPython.kernel.multiengine.IMultiEngine',
62 'IPython.kernel.multiengine.IMultiEngine',
63 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine'
63 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine'
64 ]
64 ]
65
65
66 default_client_interfaces.MultiEngine.furl_file = 'ipcontroller-mec.furl'
66 default_client_interfaces.MultiEngine.furl_file = 'ipcontroller-mec.furl'
67
67
68 # Make this a dict we can pass to Config.__init__ for the default
68 # Make this a dict we can pass to Config.__init__ for the default
69 default_client_interfaces = dict(copy.deepcopy(default_client_interfaces.items()))
69 default_client_interfaces = dict(copy.deepcopy(default_client_interfaces.items()))
70
70
71
71
72
72
73 # The default engine interfaces for FCEngineServiceFactory.interfaces
73 # The default engine interfaces for FCEngineServiceFactory.interfaces
74 default_engine_interfaces = Config()
74 default_engine_interfaces = Config()
75 default_engine_interfaces.Default.interface_chain = [
75 default_engine_interfaces.Default.interface_chain = [
76 'IPython.kernel.enginefc.IFCControllerBase'
76 'IPython.kernel.enginefc.IFCControllerBase'
77 ]
77 ]
78
78
79 default_engine_interfaces.Default.furl_file = 'ipcontroller-engine.furl'
79 default_engine_interfaces.Default.furl_file = 'ipcontroller-engine.furl'
80
80
81 # Make this a dict we can pass to Config.__init__ for the default
81 # Make this a dict we can pass to Config.__init__ for the default
82 default_engine_interfaces = dict(copy.deepcopy(default_engine_interfaces.items()))
82 default_engine_interfaces = dict(copy.deepcopy(default_engine_interfaces.items()))
83
83
84
84
85 #-----------------------------------------------------------------------------
85 #-----------------------------------------------------------------------------
86 # Service factories
86 # Service factories
87 #-----------------------------------------------------------------------------
87 #-----------------------------------------------------------------------------
88
88
89
89
90 class FCClientServiceFactory(FCServiceFactory):
90 class FCClientServiceFactory(FCServiceFactory):
91 """A Foolscap implementation of the client services."""
91 """A Foolscap implementation of the client services."""
92
92
93 cert_file = Str('ipcontroller-client.pem', config=True)
93 cert_file = Str('ipcontroller-client.pem', config=True)
94 interfaces = Instance(klass=Config, kw=default_client_interfaces,
94 interfaces = Instance(klass=Config, kw=default_client_interfaces,
95 allow_none=False, config=True)
95 allow_none=False, config=True)
96
96
97
97
98 class FCEngineServiceFactory(FCServiceFactory):
98 class FCEngineServiceFactory(FCServiceFactory):
99 """A Foolscap implementation of the engine services."""
99 """A Foolscap implementation of the engine services."""
100
100
101 cert_file = Str('ipcontroller-engine.pem', config=True)
101 cert_file = Str('ipcontroller-engine.pem', config=True)
102 interfaces = Instance(klass=dict, kw=default_engine_interfaces,
102 interfaces = Instance(klass=dict, kw=default_engine_interfaces,
103 allow_none=False, config=True)
103 allow_none=False, config=True)
104
104
105
105
106 #-----------------------------------------------------------------------------
106 #-----------------------------------------------------------------------------
107 # The main application
107 # The main application
108 #-----------------------------------------------------------------------------
108 #-----------------------------------------------------------------------------
109
109
110
110
111 cl_args = (
111 cl_args = (
112 # Client config
112 # Client config
113 (('--client-ip',), dict(
113 (('--client-ip',), dict(
114 type=str, dest='FCClientServiceFactory.ip', default=NoConfigDefault,
114 type=str, dest='FCClientServiceFactory.ip', default=NoConfigDefault,
115 help='The IP address or hostname the controller will listen on for client connections.',
115 help='The IP address or hostname the controller will listen on for client connections.',
116 metavar='FCClientServiceFactory.ip')
116 metavar='FCClientServiceFactory.ip')
117 ),
117 ),
118 (('--client-port',), dict(
118 (('--client-port',), dict(
119 type=int, dest='FCClientServiceFactory.port', default=NoConfigDefault,
119 type=int, dest='FCClientServiceFactory.port', default=NoConfigDefault,
120 help='The port the controller will listen on for client connections.',
120 help='The port the controller will listen on for client connections.',
121 metavar='FCClientServiceFactory.port')
121 metavar='FCClientServiceFactory.port')
122 ),
122 ),
123 (('--client-location',), dict(
123 (('--client-location',), dict(
124 type=str, dest='FCClientServiceFactory.location', default=NoConfigDefault,
124 type=str, dest='FCClientServiceFactory.location', default=NoConfigDefault,
125 help='The hostname or ip that clients should connect to.',
125 help='The hostname or ip that clients should connect to.',
126 metavar='FCClientServiceFactory.location')
126 metavar='FCClientServiceFactory.location')
127 ),
127 ),
128 # Engine config
128 # Engine config
129 (('--engine-ip',), dict(
129 (('--engine-ip',), dict(
130 type=str, dest='FCEngineServiceFactory.ip', default=NoConfigDefault,
130 type=str, dest='FCEngineServiceFactory.ip', default=NoConfigDefault,
131 help='The IP address or hostname the controller will listen on for engine connections.',
131 help='The IP address or hostname the controller will listen on for engine connections.',
132 metavar='FCEngineServiceFactory.ip')
132 metavar='FCEngineServiceFactory.ip')
133 ),
133 ),
134 (('--engine-port',), dict(
134 (('--engine-port',), dict(
135 type=int, dest='FCEngineServiceFactory.port', default=NoConfigDefault,
135 type=int, dest='FCEngineServiceFactory.port', default=NoConfigDefault,
136 help='The port the controller will listen on for engine connections.',
136 help='The port the controller will listen on for engine connections.',
137 metavar='FCEngineServiceFactory.port')
137 metavar='FCEngineServiceFactory.port')
138 ),
138 ),
139 (('--engine-location',), dict(
139 (('--engine-location',), dict(
140 type=str, dest='FCEngineServiceFactory.location', default=NoConfigDefault,
140 type=str, dest='FCEngineServiceFactory.location', default=NoConfigDefault,
141 help='The hostname or ip that engines should connect to.',
141 help='The hostname or ip that engines should connect to.',
142 metavar='FCEngineServiceFactory.location')
142 metavar='FCEngineServiceFactory.location')
143 ),
143 ),
144 # Global config
144 # Global config
145 (('--log-to-file',), dict(
145 (('--log-to-file',), dict(
146 action='store_true', dest='Global.log_to_file', default=NoConfigDefault,
146 action='store_true', dest='Global.log_to_file', default=NoConfigDefault,
147 help='Log to a file in the log directory (default is stdout)')
147 help='Log to a file in the log directory (default is stdout)')
148 ),
148 ),
149 (('-r','--reuse-furls'), dict(
149 (('-r','--reuse-furls'), dict(
150 action='store_true', dest='Global.reuse_furls', default=NoConfigDefault,
150 action='store_true', dest='Global.reuse_furls', default=NoConfigDefault,
151 help='Try to reuse all FURL files.')
151 help='Try to reuse all FURL files.')
152 ),
152 ),
153 (('-ns','--no-security'), dict(
153 (('-ns','--no-security'), dict(
154 action='store_false', dest='Global.secure', default=NoConfigDefault,
154 action='store_false', dest='Global.secure', default=NoConfigDefault,
155 help='Turn off SSL encryption for all connections.')
155 help='Turn off SSL encryption for all connections.')
156 )
156 )
157 )
157 )
158
158
159
159
160 class IPControllerAppCLConfigLoader(AppWithDirArgParseConfigLoader):
160 class IPControllerAppCLConfigLoader(AppWithDirArgParseConfigLoader):
161
161
162 arguments = cl_args
162 arguments = cl_args
163
163
164
164
165 default_config_file_name = 'ipcontroller_config.py'
165 default_config_file_name = 'ipcontroller_config.py'
166
166
167
167
168 class IPControllerApp(ApplicationWithDir):
168 class IPControllerApp(ApplicationWithDir):
169
169
170 name = 'ipcontroller'
170 name = 'ipcontroller'
171 app_dir_basename = 'cluster'
171 app_dir_basename = 'cluster'
172 description = 'Start the IPython controller for parallel computing.'
172 description = 'Start the IPython controller for parallel computing.'
173 config_file_name = default_config_file_name
173 config_file_name = default_config_file_name
174 default_log_level = logging.WARN
175
174
176 def create_default_config(self):
175 def create_default_config(self):
177 super(IPControllerApp, self).create_default_config()
176 super(IPControllerApp, self).create_default_config()
178 self.default_config.Global.reuse_furls = False
177 self.default_config.Global.reuse_furls = False
179 self.default_config.Global.secure = True
178 self.default_config.Global.secure = True
180 self.default_config.Global.import_statements = []
179 self.default_config.Global.import_statements = []
181 self.default_config.Global.log_dir_name = 'log'
180 self.default_config.Global.log_dir_name = 'log'
182 self.default_config.Global.security_dir_name = 'security'
181 self.default_config.Global.security_dir_name = 'security'
183 self.default_config.Global.log_to_file = False
182 self.default_config.Global.log_to_file = False
184
183
185 def create_command_line_config(self):
184 def create_command_line_config(self):
186 """Create and return a command line config loader."""
185 """Create and return a command line config loader."""
187 return IPControllerAppCLConfigLoader(
186 return IPControllerAppCLConfigLoader(
188 description=self.description,
187 description=self.description,
189 version=release.version
188 version=release.version
190 )
189 )
191
190
192 def post_load_command_line_config(self):
191 def post_load_command_line_config(self):
193 # Now setup reuse_furls
192 # Now setup reuse_furls
194 if hasattr(self.command_line_config.Global, 'reuse_furls'):
193 if hasattr(self.command_line_config.Global, 'reuse_furls'):
195 self.command_line_config.FCClientServiceFactory.reuse_furls = \
194 self.command_line_config.FCClientServiceFactory.reuse_furls = \
196 self.command_line_config.Global.reuse_furls
195 self.command_line_config.Global.reuse_furls
197 self.command_line_config.FCEngineServiceFactory.reuse_furls = \
196 self.command_line_config.FCEngineServiceFactory.reuse_furls = \
198 self.command_line_config.Global.reuse_furls
197 self.command_line_config.Global.reuse_furls
199 del self.command_line_config.Global.reuse_furls
198 del self.command_line_config.Global.reuse_furls
200 if hasattr(self.command_line_config.Global, 'secure'):
199 if hasattr(self.command_line_config.Global, 'secure'):
201 self.command_line_config.FCClientServiceFactory.secure = \
200 self.command_line_config.FCClientServiceFactory.secure = \
202 self.command_line_config.Global.secure
201 self.command_line_config.Global.secure
203 self.command_line_config.FCEngineServiceFactory.secure = \
202 self.command_line_config.FCEngineServiceFactory.secure = \
204 self.command_line_config.Global.secure
203 self.command_line_config.Global.secure
205 del self.command_line_config.Global.secure
204 del self.command_line_config.Global.secure
206
205
207 def pre_construct(self):
206 def pre_construct(self):
207 config = self.master_config
208 # Now set the security_dir and log_dir and create them. We use
208 # Now set the security_dir and log_dir and create them. We use
209 # the names an construct the absolute paths.
209 # the names an construct the absolute paths.
210 security_dir = os.path.join(self.master_config.Global.app_dir,
210 security_dir = os.path.join(config.Global.app_dir,
211 self.master_config.Global.security_dir_name)
211 config.Global.security_dir_name)
212 log_dir = os.path.join(self.master_config.Global.app_dir,
212 log_dir = os.path.join(config.Global.app_dir,
213 self.master_config.Global.log_dir_name)
213 config.Global.log_dir_name)
214 if not os.path.isdir(security_dir):
214 if not os.path.isdir(security_dir):
215 os.mkdir(security_dir, 0700)
215 os.mkdir(security_dir, 0700)
216 else:
216 else:
217 os.chmod(security_dir, 0700)
217 os.chmod(security_dir, 0700)
218 if not os.path.isdir(log_dir):
218 if not os.path.isdir(log_dir):
219 os.mkdir(log_dir, 0777)
219 os.mkdir(log_dir, 0777)
220
220
221 self.security_dir = self.master_config.Global.security_dir = security_dir
221 self.security_dir = config.Global.security_dir = security_dir
222 self.log_dir = self.master_config.Global.log_dir = log_dir
222 self.log_dir = config.Global.log_dir = log_dir
223 self.log.info("Log directory set to: %s" % self.log_dir)
224 self.log.info("Security directory set to: %s" % self.security_dir)
223
225
224 def construct(self):
226 def construct(self):
225 # I am a little hesitant to put these into InteractiveShell itself.
227 # I am a little hesitant to put these into InteractiveShell itself.
226 # But that might be the place for them
228 # But that might be the place for them
227 sys.path.insert(0, '')
229 sys.path.insert(0, '')
228
230
229 self.start_logging()
231 self.start_logging()
230 self.import_statements()
232 self.import_statements()
231
233
232 # Create the service hierarchy
234 # Create the service hierarchy
233 self.main_service = service.MultiService()
235 self.main_service = service.MultiService()
234 # The controller service
236 # The controller service
235 controller_service = controllerservice.ControllerService()
237 controller_service = controllerservice.ControllerService()
236 controller_service.setServiceParent(self.main_service)
238 controller_service.setServiceParent(self.main_service)
237 # The client tub and all its refereceables
239 # The client tub and all its refereceables
238 csfactory = FCClientServiceFactory(self.master_config, controller_service)
240 csfactory = FCClientServiceFactory(self.master_config, controller_service)
239 client_service = csfactory.create()
241 client_service = csfactory.create()
240 client_service.setServiceParent(self.main_service)
242 client_service.setServiceParent(self.main_service)
241 # The engine tub
243 # The engine tub
242 esfactory = FCEngineServiceFactory(self.master_config, controller_service)
244 esfactory = FCEngineServiceFactory(self.master_config, controller_service)
243 engine_service = esfactory.create()
245 engine_service = esfactory.create()
244 engine_service.setServiceParent(self.main_service)
246 engine_service.setServiceParent(self.main_service)
245
247
246 def start_logging(self):
248 def start_logging(self):
247 if self.master_config.Global.log_to_file:
249 if self.master_config.Global.log_to_file:
248 log_filename = self.name + '-' + str(os.getpid()) + '.log'
250 log_filename = self.name + '-' + str(os.getpid()) + '.log'
249 logfile = os.path.join(self.log_dir, log_filename)
251 logfile = os.path.join(self.log_dir, log_filename)
250 open_log_file = open(logfile, 'w')
252 open_log_file = open(logfile, 'w')
251 else:
253 else:
252 open_log_file = sys.stdout
254 open_log_file = sys.stdout
253 log.startLogging(open_log_file)
255 log.startLogging(open_log_file)
254
256
255 def import_statements(self):
257 def import_statements(self):
256 statements = self.master_config.Global.import_statements
258 statements = self.master_config.Global.import_statements
257 for s in statements:
259 for s in statements:
258 try:
260 try:
259 log.msg("Executing statement: '%s'" % s)
261 log.msg("Executing statement: '%s'" % s)
260 exec s in globals(), locals()
262 exec s in globals(), locals()
261 except:
263 except:
262 log.msg("Error running statement: %s" % s)
264 log.msg("Error running statement: %s" % s)
263
265
264 def start_app(self):
266 def start_app(self):
265 # Start the controller service and set things running
267 # Start the controller service and set things running
266 self.main_service.startService()
268 self.main_service.startService()
267 reactor.run()
269 reactor.run()
268
270
269
271
270 def launch_new_instance():
272 def launch_new_instance():
271 """Create and run the IPython controller"""
273 """Create and run the IPython controller"""
272 app = IPControllerApp()
274 app = IPControllerApp()
273 app.start()
275 app.start()
@@ -1,20 +1,20 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3
3
4 __docformat__ = "restructuredtext en"
4 #-----------------------------------------------------------------------------
5
5 # Copyright (C) 2008-2009 The IPython Development Team
6 #-------------------------------------------------------------------------------
7 # Copyright (C) 2008 The IPython Development Team
8 #
6 #
9 # Distributed under the terms of the BSD License. The full license is in
7 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
8 # the file COPYING, distributed as part of this software.
11 #-------------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
12
10
13 #-------------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
14 # Imports
12 # Imports
15 #-------------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
15
16 from IPython.kernel.ipengineapp import launch_new_instance
17
18 launch_new_instance()
16
19
17 if __name__ == '__main__':
18 from IPython.kernel.scripts import ipengine
19 ipengine.main()
20
20
@@ -1,210 +1,210 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
2 # -*- coding: utf-8 -*-
3 """Setup script for IPython.
3 """Setup script for IPython.
4
4
5 Under Posix environments it works like a typical setup.py script.
5 Under Posix environments it works like a typical setup.py script.
6 Under Windows, the command sdist is not supported, since IPython
6 Under Windows, the command sdist is not supported, since IPython
7 requires utilities which are not available under Windows."""
7 requires utilities which are not available under Windows."""
8
8
9 #-------------------------------------------------------------------------------
9 #-------------------------------------------------------------------------------
10 # Copyright (C) 2008 The IPython Development Team
10 # Copyright (C) 2008 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-------------------------------------------------------------------------------
14 #-------------------------------------------------------------------------------
15
15
16 #-------------------------------------------------------------------------------
16 #-------------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-------------------------------------------------------------------------------
18 #-------------------------------------------------------------------------------
19
19
20 # Stdlib imports
20 # Stdlib imports
21 import os
21 import os
22 import sys
22 import sys
23
23
24 from glob import glob
24 from glob import glob
25
25
26 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
26 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
27 # update it when the contents of directories change.
27 # update it when the contents of directories change.
28 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
28 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
29
29
30 from distutils.core import setup
30 from distutils.core import setup
31
31
32 from IPython.utils.genutils import target_update
32 from IPython.utils.genutils import target_update
33
33
34 from setupbase import (
34 from setupbase import (
35 setup_args,
35 setup_args,
36 find_packages,
36 find_packages,
37 find_package_data,
37 find_package_data,
38 find_scripts,
38 find_scripts,
39 find_data_files,
39 find_data_files,
40 check_for_dependencies
40 check_for_dependencies
41 )
41 )
42
42
43 isfile = os.path.isfile
43 isfile = os.path.isfile
44 pjoin = os.path.join
44 pjoin = os.path.join
45
45
46 #-------------------------------------------------------------------------------
46 #-------------------------------------------------------------------------------
47 # Handle OS specific things
47 # Handle OS specific things
48 #-------------------------------------------------------------------------------
48 #-------------------------------------------------------------------------------
49
49
50 if os.name == 'posix':
50 if os.name == 'posix':
51 os_name = 'posix'
51 os_name = 'posix'
52 elif os.name in ['nt','dos']:
52 elif os.name in ['nt','dos']:
53 os_name = 'windows'
53 os_name = 'windows'
54 else:
54 else:
55 print 'Unsupported operating system:',os.name
55 print 'Unsupported operating system:',os.name
56 sys.exit(1)
56 sys.exit(1)
57
57
58 # Under Windows, 'sdist' has not been supported. Now that the docs build with
58 # Under Windows, 'sdist' has not been supported. Now that the docs build with
59 # Sphinx it might work, but let's not turn it on until someone confirms that it
59 # Sphinx it might work, but let's not turn it on until someone confirms that it
60 # actually works.
60 # actually works.
61 if os_name == 'windows' and 'sdist' in sys.argv:
61 if os_name == 'windows' and 'sdist' in sys.argv:
62 print 'The sdist command is not available under Windows. Exiting.'
62 print 'The sdist command is not available under Windows. Exiting.'
63 sys.exit(1)
63 sys.exit(1)
64
64
65 #-------------------------------------------------------------------------------
65 #-------------------------------------------------------------------------------
66 # Things related to the IPython documentation
66 # Things related to the IPython documentation
67 #-------------------------------------------------------------------------------
67 #-------------------------------------------------------------------------------
68
68
69 # update the manuals when building a source dist
69 # update the manuals when building a source dist
70 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
70 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
71 import textwrap
71 import textwrap
72
72
73 # List of things to be updated. Each entry is a triplet of args for
73 # List of things to be updated. Each entry is a triplet of args for
74 # target_update()
74 # target_update()
75 to_update = [
75 to_update = [
76 # FIXME - Disabled for now: we need to redo an automatic way
76 # FIXME - Disabled for now: we need to redo an automatic way
77 # of generating the magic info inside the rst.
77 # of generating the magic info inside the rst.
78 #('docs/magic.tex',
78 #('docs/magic.tex',
79 #['IPython/Magic.py'],
79 #['IPython/Magic.py'],
80 #"cd doc && ./update_magic.sh" ),
80 #"cd doc && ./update_magic.sh" ),
81
81
82 ('docs/man/ipcluster.1.gz',
82 ('docs/man/ipcluster.1.gz',
83 ['docs/man/ipcluster.1'],
83 ['docs/man/ipcluster.1'],
84 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
84 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
85
85
86 ('docs/man/ipcontroller.1.gz',
86 ('docs/man/ipcontroller.1.gz',
87 ['docs/man/ipcontroller.1'],
87 ['docs/man/ipcontroller.1'],
88 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
88 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
89
89
90 ('docs/man/ipengine.1.gz',
90 ('docs/man/ipengine.1.gz',
91 ['docs/man/ipengine.1'],
91 ['docs/man/ipengine.1'],
92 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
92 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
93
93
94 ('docs/man/ipython.1.gz',
94 ('docs/man/ipython.1.gz',
95 ['docs/man/ipython.1'],
95 ['docs/man/ipython.1'],
96 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
96 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
97
97
98 ('docs/man/ipython-wx.1.gz',
98 ('docs/man/ipython-wx.1.gz',
99 ['docs/man/ipython-wx.1'],
99 ['docs/man/ipython-wx.1'],
100 'cd docs/man && gzip -9c ipython-wx.1 > ipython-wx.1.gz'),
100 'cd docs/man && gzip -9c ipython-wx.1 > ipython-wx.1.gz'),
101
101
102 ('docs/man/ipythonx.1.gz',
102 ('docs/man/ipythonx.1.gz',
103 ['docs/man/ipythonx.1'],
103 ['docs/man/ipythonx.1'],
104 'cd docs/man && gzip -9c ipythonx.1 > ipythonx.1.gz'),
104 'cd docs/man && gzip -9c ipythonx.1 > ipythonx.1.gz'),
105
105
106 ('docs/man/irunner.1.gz',
106 ('docs/man/irunner.1.gz',
107 ['docs/man/irunner.1'],
107 ['docs/man/irunner.1'],
108 'cd docs/man && gzip -9c irunner.1 > irunner.1.gz'),
108 'cd docs/man && gzip -9c irunner.1 > irunner.1.gz'),
109
109
110 ('docs/man/pycolor.1.gz',
110 ('docs/man/pycolor.1.gz',
111 ['docs/man/pycolor.1'],
111 ['docs/man/pycolor.1'],
112 'cd docs/man && gzip -9c pycolor.1 > pycolor.1.gz'),
112 'cd docs/man && gzip -9c pycolor.1 > pycolor.1.gz'),
113 ]
113 ]
114
114
115 # Only build the docs if sphinx is present
115 # Only build the docs if sphinx is present
116 try:
116 try:
117 import sphinx
117 import sphinx
118 except ImportError:
118 except ImportError:
119 pass
119 pass
120 else:
120 else:
121 # The Makefile calls the do_sphinx scripts to build html and pdf, so
121 # The Makefile calls the do_sphinx scripts to build html and pdf, so
122 # just one target is enough to cover all manual generation
122 # just one target is enough to cover all manual generation
123
123
124 # First, compute all the dependencies that can force us to rebuild the
124 # First, compute all the dependencies that can force us to rebuild the
125 # docs. Start with the main release file that contains metadata
125 # docs. Start with the main release file that contains metadata
126 docdeps = ['IPython/core/release.py']
126 docdeps = ['IPython/core/release.py']
127 # Inculde all the reST sources
127 # Inculde all the reST sources
128 pjoin = os.path.join
128 pjoin = os.path.join
129 for dirpath,dirnames,filenames in os.walk('docs/source'):
129 for dirpath,dirnames,filenames in os.walk('docs/source'):
130 if dirpath in ['_static','_templates']:
130 if dirpath in ['_static','_templates']:
131 continue
131 continue
132 docdeps += [ pjoin(dirpath,f) for f in filenames
132 docdeps += [ pjoin(dirpath,f) for f in filenames
133 if f.endswith('.txt') ]
133 if f.endswith('.txt') ]
134 # and the examples
134 # and the examples
135 for dirpath,dirnames,filenames in os.walk('docs/example'):
135 for dirpath,dirnames,filenames in os.walk('docs/example'):
136 docdeps += [ pjoin(dirpath,f) for f in filenames
136 docdeps += [ pjoin(dirpath,f) for f in filenames
137 if not f.endswith('~') ]
137 if not f.endswith('~') ]
138 # then, make them all dependencies for the main PDF (the html will get
138 # then, make them all dependencies for the main PDF (the html will get
139 # auto-generated as well).
139 # auto-generated as well).
140 to_update.append(
140 to_update.append(
141 ('docs/dist/ipython.pdf',
141 ('docs/dist/ipython.pdf',
142 docdeps,
142 docdeps,
143 "cd docs && make dist")
143 "cd docs && make dist")
144 )
144 )
145
145
146 [ target_update(*t) for t in to_update ]
146 [ target_update(*t) for t in to_update ]
147
147
148
148
149 #---------------------------------------------------------------------------
149 #---------------------------------------------------------------------------
150 # Find all the packages, package data, scripts and data_files
150 # Find all the packages, package data, scripts and data_files
151 #---------------------------------------------------------------------------
151 #---------------------------------------------------------------------------
152
152
153 packages = find_packages()
153 packages = find_packages()
154 package_data = find_package_data()
154 package_data = find_package_data()
155 scripts = find_scripts()
155 scripts = find_scripts()
156 data_files = find_data_files()
156 data_files = find_data_files()
157
157
158 #---------------------------------------------------------------------------
158 #---------------------------------------------------------------------------
159 # Handle dependencies and setuptools specific things
159 # Handle dependencies and setuptools specific things
160 #---------------------------------------------------------------------------
160 #---------------------------------------------------------------------------
161
161
162 # This dict is used for passing extra arguments that are setuptools
162 # This dict is used for passing extra arguments that are setuptools
163 # specific to setup
163 # specific to setup
164 setuptools_extra_args = {}
164 setuptools_extra_args = {}
165
165
166 if 'setuptools' in sys.modules:
166 if 'setuptools' in sys.modules:
167 setuptools_extra_args['zip_safe'] = False
167 setuptools_extra_args['zip_safe'] = False
168 setuptools_extra_args['entry_points'] = {
168 setuptools_extra_args['entry_points'] = {
169 'console_scripts': [
169 'console_scripts': [
170 'ipython = IPython.core.ipapp:launch_new_instance',
170 'ipython = IPython.core.ipapp:launch_new_instance',
171 'pycolor = IPython.utils.PyColorize:main',
171 'pycolor = IPython.utils.PyColorize:main',
172 'ipcontroller = IPython.kernel.ipcontrollerapp:launch_new_instance',
172 'ipcontroller = IPython.kernel.ipcontrollerapp:launch_new_instance',
173 'ipengine = IPython.kernel.scripts.ipengine:main',
173 'ipengine = IPython.kernel.ipengineapp:launch_new_instance',
174 'ipcluster = IPython.kernel.scripts.ipcluster:main',
174 'ipcluster = IPython.kernel.scripts.ipcluster:main',
175 'ipythonx = IPython.frontend.wx.ipythonx:main',
175 'ipythonx = IPython.frontend.wx.ipythonx:main',
176 'iptest = IPython.testing.iptest:main',
176 'iptest = IPython.testing.iptest:main',
177 'irunner = IPython.lib.irunner:main'
177 'irunner = IPython.lib.irunner:main'
178 ]
178 ]
179 }
179 }
180 setup_args['extras_require'] = dict(
180 setup_args['extras_require'] = dict(
181 kernel = [
181 kernel = [
182 'zope.interface>=3.4.1',
182 'zope.interface>=3.4.1',
183 'Twisted>=8.0.1',
183 'Twisted>=8.0.1',
184 'foolscap>=0.2.6'
184 'foolscap>=0.2.6'
185 ],
185 ],
186 doc='Sphinx>=0.3',
186 doc='Sphinx>=0.3',
187 test='nose>=0.10.1',
187 test='nose>=0.10.1',
188 security='pyOpenSSL>=0.6'
188 security='pyOpenSSL>=0.6'
189 )
189 )
190 # Allow setuptools to handle the scripts
190 # Allow setuptools to handle the scripts
191 scripts = []
191 scripts = []
192 else:
192 else:
193 # If we are running without setuptools, call this function which will
193 # If we are running without setuptools, call this function which will
194 # check for dependencies an inform the user what is needed. This is
194 # check for dependencies an inform the user what is needed. This is
195 # just to make life easy for users.
195 # just to make life easy for users.
196 check_for_dependencies()
196 check_for_dependencies()
197
197
198
198
199 #---------------------------------------------------------------------------
199 #---------------------------------------------------------------------------
200 # Do the actual setup now
200 # Do the actual setup now
201 #---------------------------------------------------------------------------
201 #---------------------------------------------------------------------------
202
202
203 setup_args['packages'] = packages
203 setup_args['packages'] = packages
204 setup_args['package_data'] = package_data
204 setup_args['package_data'] = package_data
205 setup_args['scripts'] = scripts
205 setup_args['scripts'] = scripts
206 setup_args['data_files'] = data_files
206 setup_args['data_files'] = data_files
207 setup_args.update(setuptools_extra_args)
207 setup_args.update(setuptools_extra_args)
208
208
209 if __name__ == '__main__':
209 if __name__ == '__main__':
210 setup(**setup_args)
210 setup(**setup_args)
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now