##// END OF EJS Templates
add startup_dir to profiles...
MinRK -
Show More
@@ -1,213 +1,223 b''
1 1 # encoding: utf-8
2 2 """
3 3 An object for managing IPython profile directories.
4 4
5 5 Authors:
6 6
7 7 * Brian Granger
8 8 * Fernando Perez
9 9 * Min RK
10 10
11 11 """
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Copyright (C) 2008-2011 The IPython Development Team
15 15 #
16 16 # Distributed under the terms of the BSD License. The full license is in
17 17 # the file COPYING, distributed as part of this software.
18 18 #-----------------------------------------------------------------------------
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Imports
22 22 #-----------------------------------------------------------------------------
23 23
24 24 import os
25 25 import shutil
26 26 import sys
27 27
28 28 from IPython.config.configurable import LoggingConfigurable
29 29 from IPython.config.loader import Config
30 30 from IPython.utils.path import get_ipython_package_dir, expand_path
31 31 from IPython.utils.traitlets import List, Unicode, Bool
32 32
33 33 #-----------------------------------------------------------------------------
34 34 # Classes and functions
35 35 #-----------------------------------------------------------------------------
36 36
37 37
38 38 #-----------------------------------------------------------------------------
39 39 # Module errors
40 40 #-----------------------------------------------------------------------------
41 41
42 42 class ProfileDirError(Exception):
43 43 pass
44 44
45 45
46 46 #-----------------------------------------------------------------------------
47 47 # Class for managing profile directories
48 48 #-----------------------------------------------------------------------------
49 49
50 50 class ProfileDir(LoggingConfigurable):
51 51 """An object to manage the profile directory and its resources.
52 52
53 53 The profile directory is used by all IPython applications, to manage
54 54 configuration, logging and security.
55 55
56 56 This object knows how to find, create and manage these directories. This
57 57 should be used by any code that wants to handle profiles.
58 58 """
59 59
60 60 security_dir_name = Unicode('security')
61 61 log_dir_name = Unicode('log')
62 startup_dir_name = Unicode('startup')
62 63 pid_dir_name = Unicode('pid')
63 64 security_dir = Unicode(u'')
64 65 log_dir = Unicode(u'')
66 startup_dir = Unicode(u'')
65 67 pid_dir = Unicode(u'')
66 68
67 69 location = Unicode(u'', config=True,
68 70 help="""Set the profile location directly. This overrides the logic used by the
69 71 `profile` option.""",
70 72 )
71 73
72 74 _location_isset = Bool(False) # flag for detecting multiply set location
73 75
74 76 def _location_changed(self, name, old, new):
75 77 if self._location_isset:
76 78 raise RuntimeError("Cannot set profile location more than once.")
77 79 self._location_isset = True
78 80 if not os.path.isdir(new):
79 81 os.makedirs(new)
80 82
81 83 # ensure config files exist:
82 84 self.security_dir = os.path.join(new, self.security_dir_name)
83 85 self.log_dir = os.path.join(new, self.log_dir_name)
86 self.startup_dir = os.path.join(new, self.startup_dir_name)
84 87 self.pid_dir = os.path.join(new, self.pid_dir_name)
85 88 self.check_dirs()
86 89
87 90 def _log_dir_changed(self, name, old, new):
88 91 self.check_log_dir()
89 92
90 93 def check_log_dir(self):
91 94 if not os.path.isdir(self.log_dir):
92 95 os.mkdir(self.log_dir)
93 96
97 def _startup_dir_changed(self, name, old, new):
98 self.check_startup_dir()
99
100 def check_startup_dir(self):
101 if not os.path.isdir(self.startup_dir):
102 os.mkdir(self.startup_dir)
103
94 104 def _security_dir_changed(self, name, old, new):
95 105 self.check_security_dir()
96 106
97 107 def check_security_dir(self):
98 108 if not os.path.isdir(self.security_dir):
99 109 os.mkdir(self.security_dir, 0700)
100 110 else:
101 111 try:
102 112 os.chmod(self.security_dir, 0700)
103 113 except OSError:
104 114 self.log.warn("Could not set security dir permissions to private.")
105 115
106 116 def _pid_dir_changed(self, name, old, new):
107 117 self.check_pid_dir()
108 118
109 119 def check_pid_dir(self):
110 120 if not os.path.isdir(self.pid_dir):
111 121 os.mkdir(self.pid_dir, 0700)
112 122 else:
113 123 try:
114 124 os.chmod(self.pid_dir, 0700)
115 125 except OSError:
116 126 self.log.warn("Could not set pid dir permissions to private.")
117 127
118 128 def check_dirs(self):
119 129 self.check_security_dir()
120 130 self.check_log_dir()
121 131 self.check_pid_dir()
122 132
123 133 def copy_config_file(self, config_file, path=None, overwrite=False):
124 134 """Copy a default config file into the active profile directory.
125 135
126 136 Default configuration files are kept in :mod:`IPython.config.default`.
127 137 This function moves these from that location to the working profile
128 138 directory.
129 139 """
130 140 dst = os.path.join(self.location, config_file)
131 141 if os.path.isfile(dst) and not overwrite:
132 142 return False
133 143 if path is None:
134 144 path = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
135 145 src = os.path.join(path, config_file)
136 146 shutil.copy(src, dst)
137 147 return True
138 148
139 149 @classmethod
140 150 def create_profile_dir(cls, profile_dir, config=None):
141 151 """Create a new profile directory given a full path.
142 152
143 153 Parameters
144 154 ----------
145 155 profile_dir : str
146 156 The full path to the profile directory. If it does exist, it will
147 157 be used. If not, it will be created.
148 158 """
149 159 return cls(location=profile_dir, config=config)
150 160
151 161 @classmethod
152 162 def create_profile_dir_by_name(cls, path, name=u'default', config=None):
153 163 """Create a profile dir by profile name and path.
154 164
155 165 Parameters
156 166 ----------
157 167 path : unicode
158 168 The path (directory) to put the profile directory in.
159 169 name : unicode
160 170 The name of the profile. The name of the profile directory will
161 171 be "profile_<profile>".
162 172 """
163 173 if not os.path.isdir(path):
164 174 raise ProfileDirError('Directory not found: %s' % path)
165 175 profile_dir = os.path.join(path, u'profile_' + name)
166 176 return cls(location=profile_dir, config=config)
167 177
168 178 @classmethod
169 179 def find_profile_dir_by_name(cls, ipython_dir, name=u'default', config=None):
170 180 """Find an existing profile dir by profile name, return its ProfileDir.
171 181
172 182 This searches through a sequence of paths for a profile dir. If it
173 183 is not found, a :class:`ProfileDirError` exception will be raised.
174 184
175 185 The search path algorithm is:
176 186 1. ``os.getcwdu()``
177 187 2. ``ipython_dir``
178 188
179 189 Parameters
180 190 ----------
181 191 ipython_dir : unicode or str
182 192 The IPython directory to use.
183 193 name : unicode or str
184 194 The name of the profile. The name of the profile directory
185 195 will be "profile_<profile>".
186 196 """
187 197 dirname = u'profile_' + name
188 198 paths = [os.getcwdu(), ipython_dir]
189 199 for p in paths:
190 200 profile_dir = os.path.join(p, dirname)
191 201 if os.path.isdir(profile_dir):
192 202 return cls(location=profile_dir, config=config)
193 203 else:
194 204 raise ProfileDirError('Profile directory not found in paths: %s' % dirname)
195 205
196 206 @classmethod
197 207 def find_profile_dir(cls, profile_dir, config=None):
198 208 """Find/create a profile dir and return its ProfileDir.
199 209
200 210 This will create the profile directory if it doesn't exist.
201 211
202 212 Parameters
203 213 ----------
204 214 profile_dir : unicode or str
205 215 The path of the profile directory. This is expanded using
206 216 :func:`IPython.utils.genutils.expand_path`.
207 217 """
208 218 profile_dir = expand_path(profile_dir)
209 219 if not os.path.isdir(profile_dir):
210 220 raise ProfileDirError('Profile directory not found: %s' % profile_dir)
211 221 return cls(location=profile_dir, config=config)
212 222
213 223
@@ -1,268 +1,286 b''
1 1 # encoding: utf-8
2 2 """
3 3 A mixin for :class:`~IPython.core.application.Application` classes that
4 4 launch InteractiveShell instances, load extensions, etc.
5 5
6 6 Authors
7 7 -------
8 8
9 9 * Min Ragan-Kelley
10 10 """
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Copyright (C) 2008-2011 The IPython Development Team
14 14 #
15 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 23 from __future__ import absolute_import
24 24
25 import glob
25 26 import os
26 27 import sys
27 28
28 29 from IPython.config.application import boolean_flag
29 30 from IPython.config.configurable import Configurable
30 31 from IPython.config.loader import Config
31 32 from IPython.utils import py3compat
32 33 from IPython.utils.path import filefind
33 34 from IPython.utils.traitlets import Unicode, Instance, List, Bool
34 35
35 36 #-----------------------------------------------------------------------------
36 37 # Aliases and Flags
37 38 #-----------------------------------------------------------------------------
38 39
39 40 shell_flags = {}
40 41
41 42 addflag = lambda *args: shell_flags.update(boolean_flag(*args))
42 43 addflag('autoindent', 'InteractiveShell.autoindent',
43 44 'Turn on autoindenting.', 'Turn off autoindenting.'
44 45 )
45 46 addflag('automagic', 'InteractiveShell.automagic',
46 47 """Turn on the auto calling of magic commands. Type %%magic at the
47 48 IPython prompt for more information.""",
48 49 'Turn off the auto calling of magic commands.'
49 50 )
50 51 addflag('pdb', 'InteractiveShell.pdb',
51 52 "Enable auto calling the pdb debugger after every exception.",
52 53 "Disable auto calling the pdb debugger after every exception."
53 54 )
54 55 # pydb flag doesn't do any config, as core.debugger switches on import,
55 56 # which is before parsing. This just allows the flag to be passed.
56 57 shell_flags.update(dict(
57 58 pydb = ({},
58 59 """"Use the third party 'pydb' package as debugger, instead of pdb.
59 60 Requires that pydb is installed."""
60 61 )
61 62 ))
62 63 addflag('pprint', 'PlainTextFormatter.pprint',
63 64 "Enable auto pretty printing of results.",
64 65 "Disable auto auto pretty printing of results."
65 66 )
66 67 addflag('color-info', 'InteractiveShell.color_info',
67 68 """IPython can display information about objects via a set of func-
68 69 tions, and optionally can use colors for this, syntax highlighting
69 70 source code and various other elements. However, because this
70 71 information is passed through a pager (like 'less') and many pagers get
71 72 confused with color codes, this option is off by default. You can test
72 73 it and turn it on permanently in your ipython_config.py file if it
73 74 works for you. Test it and turn it on permanently if it works with
74 75 your system. The magic function %%color_info allows you to toggle this
75 76 interactively for testing.""",
76 77 "Disable using colors for info related things."
77 78 )
78 79 addflag('deep-reload', 'InteractiveShell.deep_reload',
79 80 """Enable deep (recursive) reloading by default. IPython can use the
80 81 deep_reload module which reloads changes in modules recursively (it
81 82 replaces the reload() function, so you don't need to change anything to
82 83 use it). deep_reload() forces a full reload of modules whose code may
83 84 have changed, which the default reload() function does not. When
84 85 deep_reload is off, IPython will use the normal reload(), but
85 86 deep_reload will still be available as dreload(). This feature is off
86 87 by default [which means that you have both normal reload() and
87 88 dreload()].""",
88 89 "Disable deep (recursive) reloading by default."
89 90 )
90 91 nosep_config = Config()
91 92 nosep_config.InteractiveShell.separate_in = ''
92 93 nosep_config.InteractiveShell.separate_out = ''
93 94 nosep_config.InteractiveShell.separate_out2 = ''
94 95
95 96 shell_flags['nosep']=(nosep_config, "Eliminate all spacing between prompts.")
96 97
97 98
98 99 # it's possible we don't want short aliases for *all* of these:
99 100 shell_aliases = dict(
100 101 autocall='InteractiveShell.autocall',
101 102 colors='InteractiveShell.colors',
102 103 logfile='InteractiveShell.logfile',
103 104 logappend='InteractiveShell.logappend',
104 105 c='InteractiveShellApp.code_to_run',
105 106 ext='InteractiveShellApp.extra_extension',
106 107 )
107 108 shell_aliases['cache-size'] = 'InteractiveShell.cache_size'
108 109
109 110 #-----------------------------------------------------------------------------
110 111 # Main classes and functions
111 112 #-----------------------------------------------------------------------------
112 113
113 114 class InteractiveShellApp(Configurable):
114 115 """A Mixin for applications that start InteractiveShell instances.
115 116
116 117 Provides configurables for loading extensions and executing files
117 118 as part of configuring a Shell environment.
118 119
119 120 Provides init_extensions() and init_code() methods, to be called
120 121 after init_shell(), which must be implemented by subclasses.
121 122 """
122 123 extensions = List(Unicode, config=True,
123 124 help="A list of dotted module names of IPython extensions to load."
124 125 )
125 126 extra_extension = Unicode('', config=True,
126 127 help="dotted module name of an IPython extension to load."
127 128 )
128 129 def _extra_extension_changed(self, name, old, new):
129 130 if new:
130 131 # add to self.extensions
131 132 self.extensions.append(new)
132 133
133 134 exec_files = List(Unicode, config=True,
134 135 help="""List of files to run at IPython startup."""
135 136 )
136 137 file_to_run = Unicode('', config=True,
137 138 help="""A file to be run""")
138 139
139 140 exec_lines = List(Unicode, config=True,
140 141 help="""lines of code to run at IPython startup."""
141 142 )
142 143 code_to_run = Unicode('', config=True,
143 144 help="Execute the given command string."
144 145 )
145 146 pylab_import_all = Bool(True, config=True,
146 147 help="""If true, an 'import *' is done from numpy and pylab,
147 148 when using pylab"""
148 149 )
149 150 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
150 151
151 152 def init_shell(self):
152 153 raise NotImplementedError("Override in subclasses")
153 154
154 155 def init_extensions(self):
155 156 """Load all IPython extensions in IPythonApp.extensions.
156 157
157 158 This uses the :meth:`ExtensionManager.load_extensions` to load all
158 159 the extensions listed in ``self.extensions``.
159 160 """
160 161 if not self.extensions:
161 162 return
162 163 try:
163 164 self.log.debug("Loading IPython extensions...")
164 165 extensions = self.extensions
165 166 for ext in extensions:
166 167 try:
167 168 self.log.info("Loading IPython extension: %s" % ext)
168 169 self.shell.extension_manager.load_extension(ext)
169 170 except:
170 171 self.log.warn("Error in loading extension: %s" % ext)
171 172 self.shell.showtraceback()
172 173 except:
173 174 self.log.warn("Unknown error in loading extensions:")
174 175 self.shell.showtraceback()
175 176
176 177 def init_code(self):
177 178 """run the pre-flight code, specified via exec_lines"""
179 self._run_startup_files()
178 180 self._run_exec_lines()
179 181 self._run_exec_files()
180 182 self._run_cmd_line_code()
181 183
182 184 def _run_exec_lines(self):
183 185 """Run lines of code in IPythonApp.exec_lines in the user's namespace."""
184 186 if not self.exec_lines:
185 187 return
186 188 try:
187 189 self.log.debug("Running code from IPythonApp.exec_lines...")
188 190 for line in self.exec_lines:
189 191 try:
190 192 self.log.info("Running code in user namespace: %s" %
191 193 line)
192 194 self.shell.run_cell(line, store_history=False)
193 195 except:
194 196 self.log.warn("Error in executing line in user "
195 197 "namespace: %s" % line)
196 198 self.shell.showtraceback()
197 199 except:
198 200 self.log.warn("Unknown error in handling IPythonApp.exec_lines:")
199 201 self.shell.showtraceback()
200 202
201 203 def _exec_file(self, fname):
202 204 try:
203 205 full_filename = filefind(fname, [u'.', self.ipython_dir])
204 206 except IOError as e:
205 207 self.log.warn("File not found: %r"%fname)
206 208 return
207 209 # Make sure that the running script gets a proper sys.argv as if it
208 210 # were run from a system shell.
209 211 save_argv = sys.argv
210 212 sys.argv = [full_filename] + self.extra_args[1:]
211 213 # protect sys.argv from potential unicode strings on Python 2:
212 214 if not py3compat.PY3:
213 215 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
214 216 try:
215 217 if os.path.isfile(full_filename):
216 218 if full_filename.endswith('.ipy'):
217 219 self.log.info("Running file in user namespace: %s" %
218 220 full_filename)
219 221 self.shell.safe_execfile_ipy(full_filename)
220 222 else:
221 223 # default to python, even without extension
222 224 self.log.info("Running file in user namespace: %s" %
223 225 full_filename)
224 226 # Ensure that __file__ is always defined to match Python behavior
225 227 self.shell.user_ns['__file__'] = fname
226 228 try:
227 229 self.shell.safe_execfile(full_filename, self.shell.user_ns)
228 230 finally:
229 231 del self.shell.user_ns['__file__']
230 232 finally:
231 233 sys.argv = save_argv
232 234
235 def _run_startup_files(self):
236 """Run files from profile startup directory"""
237 startup_dir = self.profile_dir.startup_dir
238 startup_files = glob.glob(os.path.join(startup_dir, '*.py'))
239 startup_files += glob.glob(os.path.join(startup_dir, '*.ipy'))
240 if not startup_files:
241 return
242
243 self.log.debug("Running startup files from %s...", startup_dir)
244 try:
245 for fname in sorted(startup_files):
246 self._exec_file(fname)
247 except:
248 self.log.warn("Unknown error in handling startup files:")
249 self.shell.showtraceback()
250
233 251 def _run_exec_files(self):
234 252 """Run files from IPythonApp.exec_files"""
235 253 if not self.exec_files:
236 254 return
237 255
238 256 self.log.debug("Running files in IPythonApp.exec_files...")
239 257 try:
240 258 for fname in self.exec_files:
241 259 self._exec_file(fname)
242 260 except:
243 261 self.log.warn("Unknown error in handling IPythonApp.exec_files:")
244 262 self.shell.showtraceback()
245 263
246 264 def _run_cmd_line_code(self):
247 265 """Run code or file specified at the command-line"""
248 266 if self.code_to_run:
249 267 line = self.code_to_run
250 268 try:
251 269 self.log.info("Running code given at command line (c=): %s" %
252 270 line)
253 271 self.shell.run_cell(line, store_history=False)
254 272 except:
255 273 self.log.warn("Error in executing line in user namespace: %s" %
256 274 line)
257 275 self.shell.showtraceback()
258 276
259 277 # Like Python itself, ignore the second if the first of these is present
260 278 elif self.file_to_run:
261 279 fname = self.file_to_run
262 280 try:
263 281 self._exec_file(fname)
264 282 except:
265 283 self.log.warn("Error in executing file in user namespace: %s" %
266 284 fname)
267 285 self.shell.showtraceback()
268 286
General Comments 0
You need to be logged in to leave comments. Login now