##// END OF EJS Templates
fix traitlets 4.2 API usage when creating parallel profiles...
Min RK -
Show More
@@ -1,314 +1,314 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 An application for managing IPython profiles.
3 An application for managing IPython profiles.
4
4
5 To be invoked as the `ipython profile` subcommand.
5 To be invoked as the `ipython profile` subcommand.
6
6
7 Authors:
7 Authors:
8
8
9 * Min RK
9 * Min RK
10
10
11 """
11 """
12 from __future__ import print_function
12 from __future__ import print_function
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Copyright (C) 2008 The IPython Development Team
15 # Copyright (C) 2008 The IPython Development Team
16 #
16 #
17 # Distributed under the terms of the BSD License. The full license is in
17 # Distributed under the terms of the BSD License. The full license is in
18 # the file COPYING, distributed as part of this software.
18 # the file COPYING, distributed as part of this software.
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Imports
22 # Imports
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 import os
25 import os
26
26
27 from traitlets.config.application import Application
27 from traitlets.config.application import Application
28 from IPython.core.application import (
28 from IPython.core.application import (
29 BaseIPythonApplication, base_flags
29 BaseIPythonApplication, base_flags
30 )
30 )
31 from IPython.core.profiledir import ProfileDir
31 from IPython.core.profiledir import ProfileDir
32 from IPython.utils.importstring import import_item
32 from IPython.utils.importstring import import_item
33 from IPython.paths import get_ipython_dir, get_ipython_package_dir
33 from IPython.paths import get_ipython_dir, get_ipython_package_dir
34 from IPython.utils import py3compat
34 from IPython.utils import py3compat
35 from traitlets import Unicode, Bool, Dict, observe
35 from traitlets import Unicode, Bool, Dict, observe
36
36
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38 # Constants
38 # Constants
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40
40
41 create_help = """Create an IPython profile by name
41 create_help = """Create an IPython profile by name
42
42
43 Create an ipython profile directory by its name or
43 Create an ipython profile directory by its name or
44 profile directory path. Profile directories contain
44 profile directory path. Profile directories contain
45 configuration, log and security related files and are named
45 configuration, log and security related files and are named
46 using the convention 'profile_<name>'. By default they are
46 using the convention 'profile_<name>'. By default they are
47 located in your ipython directory. Once created, you will
47 located in your ipython directory. Once created, you will
48 can edit the configuration files in the profile
48 can edit the configuration files in the profile
49 directory to configure IPython. Most users will create a
49 directory to configure IPython. Most users will create a
50 profile directory by name,
50 profile directory by name,
51 `ipython profile create myprofile`, which will put the directory
51 `ipython profile create myprofile`, which will put the directory
52 in `<ipython_dir>/profile_myprofile`.
52 in `<ipython_dir>/profile_myprofile`.
53 """
53 """
54 list_help = """List available IPython profiles
54 list_help = """List available IPython profiles
55
55
56 List all available profiles, by profile location, that can
56 List all available profiles, by profile location, that can
57 be found in the current working directly or in the ipython
57 be found in the current working directly or in the ipython
58 directory. Profile directories are named using the convention
58 directory. Profile directories are named using the convention
59 'profile_<profile>'.
59 'profile_<profile>'.
60 """
60 """
61 profile_help = """Manage IPython profiles
61 profile_help = """Manage IPython profiles
62
62
63 Profile directories contain
63 Profile directories contain
64 configuration, log and security related files and are named
64 configuration, log and security related files and are named
65 using the convention 'profile_<name>'. By default they are
65 using the convention 'profile_<name>'. By default they are
66 located in your ipython directory. You can create profiles
66 located in your ipython directory. You can create profiles
67 with `ipython profile create <name>`, or see the profiles you
67 with `ipython profile create <name>`, or see the profiles you
68 already have with `ipython profile list`
68 already have with `ipython profile list`
69
69
70 To get started configuring IPython, simply do:
70 To get started configuring IPython, simply do:
71
71
72 $> ipython profile create
72 $> ipython profile create
73
73
74 and IPython will create the default profile in <ipython_dir>/profile_default,
74 and IPython will create the default profile in <ipython_dir>/profile_default,
75 where you can edit ipython_config.py to start configuring IPython.
75 where you can edit ipython_config.py to start configuring IPython.
76
76
77 """
77 """
78
78
79 _list_examples = "ipython profile list # list all profiles"
79 _list_examples = "ipython profile list # list all profiles"
80
80
81 _create_examples = """
81 _create_examples = """
82 ipython profile create foo # create profile foo w/ default config files
82 ipython profile create foo # create profile foo w/ default config files
83 ipython profile create foo --reset # restage default config files over current
83 ipython profile create foo --reset # restage default config files over current
84 ipython profile create foo --parallel # also stage parallel config files
84 ipython profile create foo --parallel # also stage parallel config files
85 """
85 """
86
86
87 _main_examples = """
87 _main_examples = """
88 ipython profile create -h # show the help string for the create subcommand
88 ipython profile create -h # show the help string for the create subcommand
89 ipython profile list -h # show the help string for the list subcommand
89 ipython profile list -h # show the help string for the list subcommand
90
90
91 ipython locate profile foo # print the path to the directory for profile 'foo'
91 ipython locate profile foo # print the path to the directory for profile 'foo'
92 """
92 """
93
93
94 #-----------------------------------------------------------------------------
94 #-----------------------------------------------------------------------------
95 # Profile Application Class (for `ipython profile` subcommand)
95 # Profile Application Class (for `ipython profile` subcommand)
96 #-----------------------------------------------------------------------------
96 #-----------------------------------------------------------------------------
97
97
98
98
99 def list_profiles_in(path):
99 def list_profiles_in(path):
100 """list profiles in a given root directory"""
100 """list profiles in a given root directory"""
101 files = os.listdir(path)
101 files = os.listdir(path)
102 profiles = []
102 profiles = []
103 for f in files:
103 for f in files:
104 try:
104 try:
105 full_path = os.path.join(path, f)
105 full_path = os.path.join(path, f)
106 except UnicodeError:
106 except UnicodeError:
107 continue
107 continue
108 if os.path.isdir(full_path) and f.startswith('profile_'):
108 if os.path.isdir(full_path) and f.startswith('profile_'):
109 profiles.append(f.split('_',1)[-1])
109 profiles.append(f.split('_',1)[-1])
110 return profiles
110 return profiles
111
111
112
112
113 def list_bundled_profiles():
113 def list_bundled_profiles():
114 """list profiles that are bundled with IPython."""
114 """list profiles that are bundled with IPython."""
115 path = os.path.join(get_ipython_package_dir(), u'core', u'profile')
115 path = os.path.join(get_ipython_package_dir(), u'core', u'profile')
116 files = os.listdir(path)
116 files = os.listdir(path)
117 profiles = []
117 profiles = []
118 for profile in files:
118 for profile in files:
119 full_path = os.path.join(path, profile)
119 full_path = os.path.join(path, profile)
120 if os.path.isdir(full_path) and profile != "__pycache__":
120 if os.path.isdir(full_path) and profile != "__pycache__":
121 profiles.append(profile)
121 profiles.append(profile)
122 return profiles
122 return profiles
123
123
124
124
125 class ProfileLocate(BaseIPythonApplication):
125 class ProfileLocate(BaseIPythonApplication):
126 description = """print the path to an IPython profile dir"""
126 description = """print the path to an IPython profile dir"""
127
127
128 def parse_command_line(self, argv=None):
128 def parse_command_line(self, argv=None):
129 super(ProfileLocate, self).parse_command_line(argv)
129 super(ProfileLocate, self).parse_command_line(argv)
130 if self.extra_args:
130 if self.extra_args:
131 self.profile = self.extra_args[0]
131 self.profile = self.extra_args[0]
132
132
133 def start(self):
133 def start(self):
134 print(self.profile_dir.location)
134 print(self.profile_dir.location)
135
135
136
136
137 class ProfileList(Application):
137 class ProfileList(Application):
138 name = u'ipython-profile'
138 name = u'ipython-profile'
139 description = list_help
139 description = list_help
140 examples = _list_examples
140 examples = _list_examples
141
141
142 aliases = Dict({
142 aliases = Dict({
143 'ipython-dir' : 'ProfileList.ipython_dir',
143 'ipython-dir' : 'ProfileList.ipython_dir',
144 'log-level' : 'Application.log_level',
144 'log-level' : 'Application.log_level',
145 })
145 })
146 flags = Dict(dict(
146 flags = Dict(dict(
147 debug = ({'Application' : {'log_level' : 0}},
147 debug = ({'Application' : {'log_level' : 0}},
148 "Set Application.log_level to 0, maximizing log output."
148 "Set Application.log_level to 0, maximizing log output."
149 )
149 )
150 ))
150 ))
151
151
152 ipython_dir = Unicode(get_ipython_dir(),
152 ipython_dir = Unicode(get_ipython_dir(),
153 help="""
153 help="""
154 The name of the IPython directory. This directory is used for logging
154 The name of the IPython directory. This directory is used for logging
155 configuration (through profiles), history storage, etc. The default
155 configuration (through profiles), history storage, etc. The default
156 is usually $HOME/.ipython. This options can also be specified through
156 is usually $HOME/.ipython. This options can also be specified through
157 the environment variable IPYTHONDIR.
157 the environment variable IPYTHONDIR.
158 """
158 """
159 ).tag(config=True)
159 ).tag(config=True)
160
160
161
161
162 def _print_profiles(self, profiles):
162 def _print_profiles(self, profiles):
163 """print list of profiles, indented."""
163 """print list of profiles, indented."""
164 for profile in profiles:
164 for profile in profiles:
165 print(' %s' % profile)
165 print(' %s' % profile)
166
166
167 def list_profile_dirs(self):
167 def list_profile_dirs(self):
168 profiles = list_bundled_profiles()
168 profiles = list_bundled_profiles()
169 if profiles:
169 if profiles:
170 print()
170 print()
171 print("Available profiles in IPython:")
171 print("Available profiles in IPython:")
172 self._print_profiles(profiles)
172 self._print_profiles(profiles)
173 print()
173 print()
174 print(" The first request for a bundled profile will copy it")
174 print(" The first request for a bundled profile will copy it")
175 print(" into your IPython directory (%s)," % self.ipython_dir)
175 print(" into your IPython directory (%s)," % self.ipython_dir)
176 print(" where you can customize it.")
176 print(" where you can customize it.")
177
177
178 profiles = list_profiles_in(self.ipython_dir)
178 profiles = list_profiles_in(self.ipython_dir)
179 if profiles:
179 if profiles:
180 print()
180 print()
181 print("Available profiles in %s:" % self.ipython_dir)
181 print("Available profiles in %s:" % self.ipython_dir)
182 self._print_profiles(profiles)
182 self._print_profiles(profiles)
183
183
184 profiles = list_profiles_in(py3compat.getcwd())
184 profiles = list_profiles_in(py3compat.getcwd())
185 if profiles:
185 if profiles:
186 print()
186 print()
187 print("Available profiles in current directory (%s):" % py3compat.getcwd())
187 print("Available profiles in current directory (%s):" % py3compat.getcwd())
188 self._print_profiles(profiles)
188 self._print_profiles(profiles)
189
189
190 print()
190 print()
191 print("To use any of the above profiles, start IPython with:")
191 print("To use any of the above profiles, start IPython with:")
192 print(" ipython --profile=<name>")
192 print(" ipython --profile=<name>")
193 print()
193 print()
194
194
195 def start(self):
195 def start(self):
196 self.list_profile_dirs()
196 self.list_profile_dirs()
197
197
198
198
199 create_flags = {}
199 create_flags = {}
200 create_flags.update(base_flags)
200 create_flags.update(base_flags)
201 # don't include '--init' flag, which implies running profile create in other apps
201 # don't include '--init' flag, which implies running profile create in other apps
202 create_flags.pop('init')
202 create_flags.pop('init')
203 create_flags['reset'] = ({'ProfileCreate': {'overwrite' : True}},
203 create_flags['reset'] = ({'ProfileCreate': {'overwrite' : True}},
204 "reset config files in this profile to the defaults.")
204 "reset config files in this profile to the defaults.")
205 create_flags['parallel'] = ({'ProfileCreate': {'parallel' : True}},
205 create_flags['parallel'] = ({'ProfileCreate': {'parallel' : True}},
206 "Include the config files for parallel "
206 "Include the config files for parallel "
207 "computing apps (ipengine, ipcontroller, etc.)")
207 "computing apps (ipengine, ipcontroller, etc.)")
208
208
209
209
210 class ProfileCreate(BaseIPythonApplication):
210 class ProfileCreate(BaseIPythonApplication):
211 name = u'ipython-profile'
211 name = u'ipython-profile'
212 description = create_help
212 description = create_help
213 examples = _create_examples
213 examples = _create_examples
214 auto_create = Bool(True)
214 auto_create = Bool(True)
215 def _log_format_default(self):
215 def _log_format_default(self):
216 return "[%(name)s] %(message)s"
216 return "[%(name)s] %(message)s"
217
217
218 def _copy_config_files_default(self):
218 def _copy_config_files_default(self):
219 return True
219 return True
220
220
221 parallel = Bool(False,
221 parallel = Bool(False,
222 help="whether to include parallel computing config files"
222 help="whether to include parallel computing config files"
223 ).tag(config=True)
223 ).tag(config=True)
224
224
225 @observe('parallel')
225 @observe('parallel')
226 def _parallel_changed(self, name, old, new):
226 def _parallel_changed(self, change):
227 parallel_files = [ 'ipcontroller_config.py',
227 parallel_files = [ 'ipcontroller_config.py',
228 'ipengine_config.py',
228 'ipengine_config.py',
229 'ipcluster_config.py'
229 'ipcluster_config.py'
230 ]
230 ]
231 if new:
231 if change['new']:
232 for cf in parallel_files:
232 for cf in parallel_files:
233 self.config_files.append(cf)
233 self.config_files.append(cf)
234 else:
234 else:
235 for cf in parallel_files:
235 for cf in parallel_files:
236 if cf in self.config_files:
236 if cf in self.config_files:
237 self.config_files.remove(cf)
237 self.config_files.remove(cf)
238
238
239 def parse_command_line(self, argv):
239 def parse_command_line(self, argv):
240 super(ProfileCreate, self).parse_command_line(argv)
240 super(ProfileCreate, self).parse_command_line(argv)
241 # accept positional arg as profile name
241 # accept positional arg as profile name
242 if self.extra_args:
242 if self.extra_args:
243 self.profile = self.extra_args[0]
243 self.profile = self.extra_args[0]
244
244
245 flags = Dict(create_flags)
245 flags = Dict(create_flags)
246
246
247 classes = [ProfileDir]
247 classes = [ProfileDir]
248
248
249 def _import_app(self, app_path):
249 def _import_app(self, app_path):
250 """import an app class"""
250 """import an app class"""
251 app = None
251 app = None
252 name = app_path.rsplit('.', 1)[-1]
252 name = app_path.rsplit('.', 1)[-1]
253 try:
253 try:
254 app = import_item(app_path)
254 app = import_item(app_path)
255 except ImportError:
255 except ImportError:
256 self.log.info("Couldn't import %s, config file will be excluded", name)
256 self.log.info("Couldn't import %s, config file will be excluded", name)
257 except Exception:
257 except Exception:
258 self.log.warning('Unexpected error importing %s', name, exc_info=True)
258 self.log.warning('Unexpected error importing %s', name, exc_info=True)
259 return app
259 return app
260
260
261 def init_config_files(self):
261 def init_config_files(self):
262 super(ProfileCreate, self).init_config_files()
262 super(ProfileCreate, self).init_config_files()
263 # use local imports, since these classes may import from here
263 # use local imports, since these classes may import from here
264 from IPython.terminal.ipapp import TerminalIPythonApp
264 from IPython.terminal.ipapp import TerminalIPythonApp
265 apps = [TerminalIPythonApp]
265 apps = [TerminalIPythonApp]
266 for app_path in (
266 for app_path in (
267 'ipykernel.kernelapp.IPKernelApp',
267 'ipykernel.kernelapp.IPKernelApp',
268 ):
268 ):
269 app = self._import_app(app_path)
269 app = self._import_app(app_path)
270 if app is not None:
270 if app is not None:
271 apps.append(app)
271 apps.append(app)
272 if self.parallel:
272 if self.parallel:
273 from ipyparallel.apps.ipcontrollerapp import IPControllerApp
273 from ipyparallel.apps.ipcontrollerapp import IPControllerApp
274 from ipyparallel.apps.ipengineapp import IPEngineApp
274 from ipyparallel.apps.ipengineapp import IPEngineApp
275 from ipyparallel.apps.ipclusterapp import IPClusterStart
275 from ipyparallel.apps.ipclusterapp import IPClusterStart
276 apps.extend([
276 apps.extend([
277 IPControllerApp,
277 IPControllerApp,
278 IPEngineApp,
278 IPEngineApp,
279 IPClusterStart,
279 IPClusterStart,
280 ])
280 ])
281 for App in apps:
281 for App in apps:
282 app = App()
282 app = App()
283 app.config.update(self.config)
283 app.config.update(self.config)
284 app.log = self.log
284 app.log = self.log
285 app.overwrite = self.overwrite
285 app.overwrite = self.overwrite
286 app.copy_config_files=True
286 app.copy_config_files=True
287 app.ipython_dir=self.ipython_dir
287 app.ipython_dir=self.ipython_dir
288 app.profile_dir=self.profile_dir
288 app.profile_dir=self.profile_dir
289 app.init_config_files()
289 app.init_config_files()
290
290
291 def stage_default_config_file(self):
291 def stage_default_config_file(self):
292 pass
292 pass
293
293
294
294
295 class ProfileApp(Application):
295 class ProfileApp(Application):
296 name = u'ipython profile'
296 name = u'ipython profile'
297 description = profile_help
297 description = profile_help
298 examples = _main_examples
298 examples = _main_examples
299
299
300 subcommands = Dict(dict(
300 subcommands = Dict(dict(
301 create = (ProfileCreate, ProfileCreate.description.splitlines()[0]),
301 create = (ProfileCreate, ProfileCreate.description.splitlines()[0]),
302 list = (ProfileList, ProfileList.description.splitlines()[0]),
302 list = (ProfileList, ProfileList.description.splitlines()[0]),
303 locate = (ProfileLocate, ProfileLocate.description.splitlines()[0]),
303 locate = (ProfileLocate, ProfileLocate.description.splitlines()[0]),
304 ))
304 ))
305
305
306 def start(self):
306 def start(self):
307 if self.subapp is None:
307 if self.subapp is None:
308 print("No subcommand specified. Must specify one of: %s"%(self.subcommands.keys()))
308 print("No subcommand specified. Must specify one of: %s"%(self.subcommands.keys()))
309 print()
309 print()
310 self.print_description()
310 self.print_description()
311 self.print_subcommands()
311 self.print_subcommands()
312 self.exit(1)
312 self.exit(1)
313 else:
313 else:
314 return self.subapp.start()
314 return self.subapp.start()
General Comments 0
You need to be logged in to leave comments. Login now