##// END OF EJS Templates
Merge pull request #4469 from takluyver/py3-getcwdu...
Min RK -
r13456:5bf4949f merge
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,381 +1,382 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 An application for IPython.
3 An application for IPython.
4
4
5 All top-level applications should use the classes in this module for
5 All top-level applications should use the classes in this module for
6 handling configuration and creating configurables.
6 handling configuration and creating configurables.
7
7
8 The job of an :class:`Application` is to create the master configuration
8 The job of an :class:`Application` is to create the master configuration
9 object and then create the configurable objects, passing the config to them.
9 object and then create the configurable objects, passing the config to them.
10
10
11 Authors:
11 Authors:
12
12
13 * Brian Granger
13 * Brian Granger
14 * Fernando Perez
14 * Fernando Perez
15 * Min RK
15 * Min RK
16
16
17 """
17 """
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Copyright (C) 2008 The IPython Development Team
20 # Copyright (C) 2008 The IPython Development Team
21 #
21 #
22 # Distributed under the terms of the BSD License. The full license is in
22 # Distributed under the terms of the BSD License. The full license is in
23 # the file COPYING, distributed as part of this software.
23 # the file COPYING, distributed as part of this software.
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Imports
27 # Imports
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 import atexit
30 import atexit
31 import errno
31 import errno
32 import glob
32 import glob
33 import logging
33 import logging
34 import os
34 import os
35 import shutil
35 import shutil
36 import sys
36 import sys
37
37
38 from IPython.config.application import Application, catch_config_error
38 from IPython.config.application import Application, catch_config_error
39 from IPython.config.loader import ConfigFileNotFound
39 from IPython.config.loader import ConfigFileNotFound
40 from IPython.core import release, crashhandler
40 from IPython.core import release, crashhandler
41 from IPython.core.profiledir import ProfileDir, ProfileDirError
41 from IPython.core.profiledir import ProfileDir, ProfileDirError
42 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
42 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
43 from IPython.utils import py3compat
43 from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict, Set, Instance
44 from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict, Set, Instance
44
45
45 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
46 # Classes and functions
47 # Classes and functions
47 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
48
49
49
50
50 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
51 # Base Application Class
52 # Base Application Class
52 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
53
54
54 # aliases and flags
55 # aliases and flags
55
56
56 base_aliases = {
57 base_aliases = {
57 'profile-dir' : 'ProfileDir.location',
58 'profile-dir' : 'ProfileDir.location',
58 'profile' : 'BaseIPythonApplication.profile',
59 'profile' : 'BaseIPythonApplication.profile',
59 'ipython-dir' : 'BaseIPythonApplication.ipython_dir',
60 'ipython-dir' : 'BaseIPythonApplication.ipython_dir',
60 'log-level' : 'Application.log_level',
61 'log-level' : 'Application.log_level',
61 'config' : 'BaseIPythonApplication.extra_config_file',
62 'config' : 'BaseIPythonApplication.extra_config_file',
62 }
63 }
63
64
64 base_flags = dict(
65 base_flags = dict(
65 debug = ({'Application' : {'log_level' : logging.DEBUG}},
66 debug = ({'Application' : {'log_level' : logging.DEBUG}},
66 "set log level to logging.DEBUG (maximize logging output)"),
67 "set log level to logging.DEBUG (maximize logging output)"),
67 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
68 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
68 "set log level to logging.CRITICAL (minimize logging output)"),
69 "set log level to logging.CRITICAL (minimize logging output)"),
69 init = ({'BaseIPythonApplication' : {
70 init = ({'BaseIPythonApplication' : {
70 'copy_config_files' : True,
71 'copy_config_files' : True,
71 'auto_create' : True}
72 'auto_create' : True}
72 }, """Initialize profile with default config files. This is equivalent
73 }, """Initialize profile with default config files. This is equivalent
73 to running `ipython profile create <profile>` prior to startup.
74 to running `ipython profile create <profile>` prior to startup.
74 """)
75 """)
75 )
76 )
76
77
77
78
78 class BaseIPythonApplication(Application):
79 class BaseIPythonApplication(Application):
79
80
80 name = Unicode(u'ipython')
81 name = Unicode(u'ipython')
81 description = Unicode(u'IPython: an enhanced interactive Python shell.')
82 description = Unicode(u'IPython: an enhanced interactive Python shell.')
82 version = Unicode(release.version)
83 version = Unicode(release.version)
83
84
84 aliases = Dict(base_aliases)
85 aliases = Dict(base_aliases)
85 flags = Dict(base_flags)
86 flags = Dict(base_flags)
86 classes = List([ProfileDir])
87 classes = List([ProfileDir])
87
88
88 # Track whether the config_file has changed,
89 # Track whether the config_file has changed,
89 # because some logic happens only if we aren't using the default.
90 # because some logic happens only if we aren't using the default.
90 config_file_specified = Set()
91 config_file_specified = Set()
91
92
92 config_file_name = Unicode()
93 config_file_name = Unicode()
93 def _config_file_name_default(self):
94 def _config_file_name_default(self):
94 return self.name.replace('-','_') + u'_config.py'
95 return self.name.replace('-','_') + u'_config.py'
95 def _config_file_name_changed(self, name, old, new):
96 def _config_file_name_changed(self, name, old, new):
96 if new != old:
97 if new != old:
97 self.config_file_specified.add(new)
98 self.config_file_specified.add(new)
98
99
99 # The directory that contains IPython's builtin profiles.
100 # The directory that contains IPython's builtin profiles.
100 builtin_profile_dir = Unicode(
101 builtin_profile_dir = Unicode(
101 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
102 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
102 )
103 )
103
104
104 config_file_paths = List(Unicode)
105 config_file_paths = List(Unicode)
105 def _config_file_paths_default(self):
106 def _config_file_paths_default(self):
106 return [os.getcwdu()]
107 return [py3compat.getcwd()]
107
108
108 extra_config_file = Unicode(config=True,
109 extra_config_file = Unicode(config=True,
109 help="""Path to an extra config file to load.
110 help="""Path to an extra config file to load.
110
111
111 If specified, load this config file in addition to any other IPython config.
112 If specified, load this config file in addition to any other IPython config.
112 """)
113 """)
113 def _extra_config_file_changed(self, name, old, new):
114 def _extra_config_file_changed(self, name, old, new):
114 try:
115 try:
115 self.config_files.remove(old)
116 self.config_files.remove(old)
116 except ValueError:
117 except ValueError:
117 pass
118 pass
118 self.config_file_specified.add(new)
119 self.config_file_specified.add(new)
119 self.config_files.append(new)
120 self.config_files.append(new)
120
121
121 profile = Unicode(u'default', config=True,
122 profile = Unicode(u'default', config=True,
122 help="""The IPython profile to use."""
123 help="""The IPython profile to use."""
123 )
124 )
124
125
125 def _profile_changed(self, name, old, new):
126 def _profile_changed(self, name, old, new):
126 self.builtin_profile_dir = os.path.join(
127 self.builtin_profile_dir = os.path.join(
127 get_ipython_package_dir(), u'config', u'profile', new
128 get_ipython_package_dir(), u'config', u'profile', new
128 )
129 )
129
130
130 ipython_dir = Unicode(config=True,
131 ipython_dir = Unicode(config=True,
131 help="""
132 help="""
132 The name of the IPython directory. This directory is used for logging
133 The name of the IPython directory. This directory is used for logging
133 configuration (through profiles), history storage, etc. The default
134 configuration (through profiles), history storage, etc. The default
134 is usually $HOME/.ipython. This options can also be specified through
135 is usually $HOME/.ipython. This options can also be specified through
135 the environment variable IPYTHONDIR.
136 the environment variable IPYTHONDIR.
136 """
137 """
137 )
138 )
138 def _ipython_dir_default(self):
139 def _ipython_dir_default(self):
139 d = get_ipython_dir()
140 d = get_ipython_dir()
140 self._ipython_dir_changed('ipython_dir', d, d)
141 self._ipython_dir_changed('ipython_dir', d, d)
141 return d
142 return d
142
143
143 _in_init_profile_dir = False
144 _in_init_profile_dir = False
144 profile_dir = Instance(ProfileDir)
145 profile_dir = Instance(ProfileDir)
145 def _profile_dir_default(self):
146 def _profile_dir_default(self):
146 # avoid recursion
147 # avoid recursion
147 if self._in_init_profile_dir:
148 if self._in_init_profile_dir:
148 return
149 return
149 # profile_dir requested early, force initialization
150 # profile_dir requested early, force initialization
150 self.init_profile_dir()
151 self.init_profile_dir()
151 return self.profile_dir
152 return self.profile_dir
152
153
153 overwrite = Bool(False, config=True,
154 overwrite = Bool(False, config=True,
154 help="""Whether to overwrite existing config files when copying""")
155 help="""Whether to overwrite existing config files when copying""")
155 auto_create = Bool(False, config=True,
156 auto_create = Bool(False, config=True,
156 help="""Whether to create profile dir if it doesn't exist""")
157 help="""Whether to create profile dir if it doesn't exist""")
157
158
158 config_files = List(Unicode)
159 config_files = List(Unicode)
159 def _config_files_default(self):
160 def _config_files_default(self):
160 return [self.config_file_name]
161 return [self.config_file_name]
161
162
162 copy_config_files = Bool(False, config=True,
163 copy_config_files = Bool(False, config=True,
163 help="""Whether to install the default config files into the profile dir.
164 help="""Whether to install the default config files into the profile dir.
164 If a new profile is being created, and IPython contains config files for that
165 If a new profile is being created, and IPython contains config files for that
165 profile, then they will be staged into the new directory. Otherwise,
166 profile, then they will be staged into the new directory. Otherwise,
166 default config files will be automatically generated.
167 default config files will be automatically generated.
167 """)
168 """)
168
169
169 verbose_crash = Bool(False, config=True,
170 verbose_crash = Bool(False, config=True,
170 help="""Create a massive crash report when IPython encounters what may be an
171 help="""Create a massive crash report when IPython encounters what may be an
171 internal error. The default is to append a short message to the
172 internal error. The default is to append a short message to the
172 usual traceback""")
173 usual traceback""")
173
174
174 # The class to use as the crash handler.
175 # The class to use as the crash handler.
175 crash_handler_class = Type(crashhandler.CrashHandler)
176 crash_handler_class = Type(crashhandler.CrashHandler)
176
177
177 @catch_config_error
178 @catch_config_error
178 def __init__(self, **kwargs):
179 def __init__(self, **kwargs):
179 super(BaseIPythonApplication, self).__init__(**kwargs)
180 super(BaseIPythonApplication, self).__init__(**kwargs)
180 # ensure current working directory exists
181 # ensure current working directory exists
181 try:
182 try:
182 directory = os.getcwdu()
183 directory = py3compat.getcwd()
183 except:
184 except:
184 # raise exception
185 # raise exception
185 self.log.error("Current working directory doesn't exist.")
186 self.log.error("Current working directory doesn't exist.")
186 raise
187 raise
187
188
188 #-------------------------------------------------------------------------
189 #-------------------------------------------------------------------------
189 # Various stages of Application creation
190 # Various stages of Application creation
190 #-------------------------------------------------------------------------
191 #-------------------------------------------------------------------------
191
192
192 def init_crash_handler(self):
193 def init_crash_handler(self):
193 """Create a crash handler, typically setting sys.excepthook to it."""
194 """Create a crash handler, typically setting sys.excepthook to it."""
194 self.crash_handler = self.crash_handler_class(self)
195 self.crash_handler = self.crash_handler_class(self)
195 sys.excepthook = self.excepthook
196 sys.excepthook = self.excepthook
196 def unset_crashhandler():
197 def unset_crashhandler():
197 sys.excepthook = sys.__excepthook__
198 sys.excepthook = sys.__excepthook__
198 atexit.register(unset_crashhandler)
199 atexit.register(unset_crashhandler)
199
200
200 def excepthook(self, etype, evalue, tb):
201 def excepthook(self, etype, evalue, tb):
201 """this is sys.excepthook after init_crashhandler
202 """this is sys.excepthook after init_crashhandler
202
203
203 set self.verbose_crash=True to use our full crashhandler, instead of
204 set self.verbose_crash=True to use our full crashhandler, instead of
204 a regular traceback with a short message (crash_handler_lite)
205 a regular traceback with a short message (crash_handler_lite)
205 """
206 """
206
207
207 if self.verbose_crash:
208 if self.verbose_crash:
208 return self.crash_handler(etype, evalue, tb)
209 return self.crash_handler(etype, evalue, tb)
209 else:
210 else:
210 return crashhandler.crash_handler_lite(etype, evalue, tb)
211 return crashhandler.crash_handler_lite(etype, evalue, tb)
211
212
212 def _ipython_dir_changed(self, name, old, new):
213 def _ipython_dir_changed(self, name, old, new):
213 if old in sys.path:
214 if old in sys.path:
214 sys.path.remove(old)
215 sys.path.remove(old)
215 sys.path.append(os.path.abspath(new))
216 sys.path.append(os.path.abspath(new))
216 if not os.path.isdir(new):
217 if not os.path.isdir(new):
217 os.makedirs(new, mode=0o777)
218 os.makedirs(new, mode=0o777)
218 readme = os.path.join(new, 'README')
219 readme = os.path.join(new, 'README')
219 readme_src = os.path.join(get_ipython_package_dir(), u'config', u'profile', 'README')
220 readme_src = os.path.join(get_ipython_package_dir(), u'config', u'profile', 'README')
220 if not os.path.exists(readme) and os.path.exists(readme_src):
221 if not os.path.exists(readme) and os.path.exists(readme_src):
221 shutil.copy(readme_src, readme)
222 shutil.copy(readme_src, readme)
222 for d in ('extensions', 'nbextensions'):
223 for d in ('extensions', 'nbextensions'):
223 path = os.path.join(new, d)
224 path = os.path.join(new, d)
224 if not os.path.exists(path):
225 if not os.path.exists(path):
225 try:
226 try:
226 os.mkdir(path)
227 os.mkdir(path)
227 except OSError as e:
228 except OSError as e:
228 if e.errno != errno.EEXIST:
229 if e.errno != errno.EEXIST:
229 self.log.error("couldn't create path %s: %s", path, e)
230 self.log.error("couldn't create path %s: %s", path, e)
230 self.log.debug("IPYTHONDIR set to: %s" % new)
231 self.log.debug("IPYTHONDIR set to: %s" % new)
231
232
232 def load_config_file(self, suppress_errors=True):
233 def load_config_file(self, suppress_errors=True):
233 """Load the config file.
234 """Load the config file.
234
235
235 By default, errors in loading config are handled, and a warning
236 By default, errors in loading config are handled, and a warning
236 printed on screen. For testing, the suppress_errors option is set
237 printed on screen. For testing, the suppress_errors option is set
237 to False, so errors will make tests fail.
238 to False, so errors will make tests fail.
238 """
239 """
239 self.log.debug("Searching path %s for config files", self.config_file_paths)
240 self.log.debug("Searching path %s for config files", self.config_file_paths)
240 base_config = 'ipython_config.py'
241 base_config = 'ipython_config.py'
241 self.log.debug("Attempting to load config file: %s" %
242 self.log.debug("Attempting to load config file: %s" %
242 base_config)
243 base_config)
243 try:
244 try:
244 Application.load_config_file(
245 Application.load_config_file(
245 self,
246 self,
246 base_config,
247 base_config,
247 path=self.config_file_paths
248 path=self.config_file_paths
248 )
249 )
249 except ConfigFileNotFound:
250 except ConfigFileNotFound:
250 # ignore errors loading parent
251 # ignore errors loading parent
251 self.log.debug("Config file %s not found", base_config)
252 self.log.debug("Config file %s not found", base_config)
252 pass
253 pass
253
254
254 for config_file_name in self.config_files:
255 for config_file_name in self.config_files:
255 if not config_file_name or config_file_name == base_config:
256 if not config_file_name or config_file_name == base_config:
256 continue
257 continue
257 self.log.debug("Attempting to load config file: %s" %
258 self.log.debug("Attempting to load config file: %s" %
258 self.config_file_name)
259 self.config_file_name)
259 try:
260 try:
260 Application.load_config_file(
261 Application.load_config_file(
261 self,
262 self,
262 config_file_name,
263 config_file_name,
263 path=self.config_file_paths
264 path=self.config_file_paths
264 )
265 )
265 except ConfigFileNotFound:
266 except ConfigFileNotFound:
266 # Only warn if the default config file was NOT being used.
267 # Only warn if the default config file was NOT being used.
267 if config_file_name in self.config_file_specified:
268 if config_file_name in self.config_file_specified:
268 msg = self.log.warn
269 msg = self.log.warn
269 else:
270 else:
270 msg = self.log.debug
271 msg = self.log.debug
271 msg("Config file not found, skipping: %s", config_file_name)
272 msg("Config file not found, skipping: %s", config_file_name)
272 except:
273 except:
273 # For testing purposes.
274 # For testing purposes.
274 if not suppress_errors:
275 if not suppress_errors:
275 raise
276 raise
276 self.log.warn("Error loading config file: %s" %
277 self.log.warn("Error loading config file: %s" %
277 self.config_file_name, exc_info=True)
278 self.config_file_name, exc_info=True)
278
279
279 def init_profile_dir(self):
280 def init_profile_dir(self):
280 """initialize the profile dir"""
281 """initialize the profile dir"""
281 self._in_init_profile_dir = True
282 self._in_init_profile_dir = True
282 if self.profile_dir is not None:
283 if self.profile_dir is not None:
283 # already ran
284 # already ran
284 return
285 return
285 if 'ProfileDir.location' not in self.config:
286 if 'ProfileDir.location' not in self.config:
286 # location not specified, find by profile name
287 # location not specified, find by profile name
287 try:
288 try:
288 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
289 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
289 except ProfileDirError:
290 except ProfileDirError:
290 # not found, maybe create it (always create default profile)
291 # not found, maybe create it (always create default profile)
291 if self.auto_create or self.profile == 'default':
292 if self.auto_create or self.profile == 'default':
292 try:
293 try:
293 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
294 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
294 except ProfileDirError:
295 except ProfileDirError:
295 self.log.fatal("Could not create profile: %r"%self.profile)
296 self.log.fatal("Could not create profile: %r"%self.profile)
296 self.exit(1)
297 self.exit(1)
297 else:
298 else:
298 self.log.info("Created profile dir: %r"%p.location)
299 self.log.info("Created profile dir: %r"%p.location)
299 else:
300 else:
300 self.log.fatal("Profile %r not found."%self.profile)
301 self.log.fatal("Profile %r not found."%self.profile)
301 self.exit(1)
302 self.exit(1)
302 else:
303 else:
303 self.log.info("Using existing profile dir: %r"%p.location)
304 self.log.info("Using existing profile dir: %r"%p.location)
304 else:
305 else:
305 location = self.config.ProfileDir.location
306 location = self.config.ProfileDir.location
306 # location is fully specified
307 # location is fully specified
307 try:
308 try:
308 p = ProfileDir.find_profile_dir(location, self.config)
309 p = ProfileDir.find_profile_dir(location, self.config)
309 except ProfileDirError:
310 except ProfileDirError:
310 # not found, maybe create it
311 # not found, maybe create it
311 if self.auto_create:
312 if self.auto_create:
312 try:
313 try:
313 p = ProfileDir.create_profile_dir(location, self.config)
314 p = ProfileDir.create_profile_dir(location, self.config)
314 except ProfileDirError:
315 except ProfileDirError:
315 self.log.fatal("Could not create profile directory: %r"%location)
316 self.log.fatal("Could not create profile directory: %r"%location)
316 self.exit(1)
317 self.exit(1)
317 else:
318 else:
318 self.log.info("Creating new profile dir: %r"%location)
319 self.log.info("Creating new profile dir: %r"%location)
319 else:
320 else:
320 self.log.fatal("Profile directory %r not found."%location)
321 self.log.fatal("Profile directory %r not found."%location)
321 self.exit(1)
322 self.exit(1)
322 else:
323 else:
323 self.log.info("Using existing profile dir: %r"%location)
324 self.log.info("Using existing profile dir: %r"%location)
324
325
325 self.profile_dir = p
326 self.profile_dir = p
326 self.config_file_paths.append(p.location)
327 self.config_file_paths.append(p.location)
327 self._in_init_profile_dir = False
328 self._in_init_profile_dir = False
328
329
329 def init_config_files(self):
330 def init_config_files(self):
330 """[optionally] copy default config files into profile dir."""
331 """[optionally] copy default config files into profile dir."""
331 # copy config files
332 # copy config files
332 path = self.builtin_profile_dir
333 path = self.builtin_profile_dir
333 if self.copy_config_files:
334 if self.copy_config_files:
334 src = self.profile
335 src = self.profile
335
336
336 cfg = self.config_file_name
337 cfg = self.config_file_name
337 if path and os.path.exists(os.path.join(path, cfg)):
338 if path and os.path.exists(os.path.join(path, cfg)):
338 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
339 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
339 cfg, src, self.profile_dir.location, self.overwrite)
340 cfg, src, self.profile_dir.location, self.overwrite)
340 )
341 )
341 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
342 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
342 else:
343 else:
343 self.stage_default_config_file()
344 self.stage_default_config_file()
344 else:
345 else:
345 # Still stage *bundled* config files, but not generated ones
346 # Still stage *bundled* config files, but not generated ones
346 # This is necessary for `ipython profile=sympy` to load the profile
347 # This is necessary for `ipython profile=sympy` to load the profile
347 # on the first go
348 # on the first go
348 files = glob.glob(os.path.join(path, '*.py'))
349 files = glob.glob(os.path.join(path, '*.py'))
349 for fullpath in files:
350 for fullpath in files:
350 cfg = os.path.basename(fullpath)
351 cfg = os.path.basename(fullpath)
351 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
352 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
352 # file was copied
353 # file was copied
353 self.log.warn("Staging bundled %s from %s into %r"%(
354 self.log.warn("Staging bundled %s from %s into %r"%(
354 cfg, self.profile, self.profile_dir.location)
355 cfg, self.profile, self.profile_dir.location)
355 )
356 )
356
357
357
358
358 def stage_default_config_file(self):
359 def stage_default_config_file(self):
359 """auto generate default config file, and stage it into the profile."""
360 """auto generate default config file, and stage it into the profile."""
360 s = self.generate_config_file()
361 s = self.generate_config_file()
361 fname = os.path.join(self.profile_dir.location, self.config_file_name)
362 fname = os.path.join(self.profile_dir.location, self.config_file_name)
362 if self.overwrite or not os.path.exists(fname):
363 if self.overwrite or not os.path.exists(fname):
363 self.log.warn("Generating default config file: %r"%(fname))
364 self.log.warn("Generating default config file: %r"%(fname))
364 with open(fname, 'w') as f:
365 with open(fname, 'w') as f:
365 f.write(s)
366 f.write(s)
366
367
367 @catch_config_error
368 @catch_config_error
368 def initialize(self, argv=None):
369 def initialize(self, argv=None):
369 # don't hook up crash handler before parsing command-line
370 # don't hook up crash handler before parsing command-line
370 self.parse_command_line(argv)
371 self.parse_command_line(argv)
371 self.init_crash_handler()
372 self.init_crash_handler()
372 if self.subapp is not None:
373 if self.subapp is not None:
373 # stop here if subapp is taking over
374 # stop here if subapp is taking over
374 return
375 return
375 cl_config = self.config
376 cl_config = self.config
376 self.init_profile_dir()
377 self.init_profile_dir()
377 self.init_config_files()
378 self.init_config_files()
378 self.load_config_file()
379 self.load_config_file()
379 # enforce cl-opts override configfile opts:
380 # enforce cl-opts override configfile opts:
380 self.update_config(cl_config)
381 self.update_config(cl_config)
381
382
@@ -1,216 +1,216 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
3
3
4 Authors:
4 Authors:
5
5
6 * Fernando Perez
6 * Fernando Perez
7 * Brian E. Granger
7 * Brian E. Granger
8 """
8 """
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
11 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
12 # Copyright (C) 2008-2011 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 from __future__ import print_function
21 from __future__ import print_function
22
22
23 import os
23 import os
24 import sys
24 import sys
25 import traceback
25 import traceback
26 from pprint import pformat
26 from pprint import pformat
27
27
28 from IPython.core import ultratb
28 from IPython.core import ultratb
29 from IPython.core.release import author_email
29 from IPython.core.release import author_email
30 from IPython.utils.sysinfo import sys_info
30 from IPython.utils.sysinfo import sys_info
31 from IPython.utils.py3compat import input
31 from IPython.utils.py3compat import input, getcwd
32
32
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34 # Code
34 # Code
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36
36
37 # Template for the user message.
37 # Template for the user message.
38 _default_message_template = """\
38 _default_message_template = """\
39 Oops, {app_name} crashed. We do our best to make it stable, but...
39 Oops, {app_name} crashed. We do our best to make it stable, but...
40
40
41 A crash report was automatically generated with the following information:
41 A crash report was automatically generated with the following information:
42 - A verbatim copy of the crash traceback.
42 - A verbatim copy of the crash traceback.
43 - A copy of your input history during this session.
43 - A copy of your input history during this session.
44 - Data on your current {app_name} configuration.
44 - Data on your current {app_name} configuration.
45
45
46 It was left in the file named:
46 It was left in the file named:
47 \t'{crash_report_fname}'
47 \t'{crash_report_fname}'
48 If you can email this file to the developers, the information in it will help
48 If you can email this file to the developers, the information in it will help
49 them in understanding and correcting the problem.
49 them in understanding and correcting the problem.
50
50
51 You can mail it to: {contact_name} at {contact_email}
51 You can mail it to: {contact_name} at {contact_email}
52 with the subject '{app_name} Crash Report'.
52 with the subject '{app_name} Crash Report'.
53
53
54 If you want to do it now, the following command will work (under Unix):
54 If you want to do it now, the following command will work (under Unix):
55 mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
55 mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
56
56
57 To ensure accurate tracking of this issue, please file a report about it at:
57 To ensure accurate tracking of this issue, please file a report about it at:
58 {bug_tracker}
58 {bug_tracker}
59 """
59 """
60
60
61 _lite_message_template = """
61 _lite_message_template = """
62 If you suspect this is an IPython bug, please report it at:
62 If you suspect this is an IPython bug, please report it at:
63 https://github.com/ipython/ipython/issues
63 https://github.com/ipython/ipython/issues
64 or send an email to the mailing list at {email}
64 or send an email to the mailing list at {email}
65
65
66 You can print a more detailed traceback right now with "%tb", or use "%debug"
66 You can print a more detailed traceback right now with "%tb", or use "%debug"
67 to interactively debug it.
67 to interactively debug it.
68
68
69 Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
69 Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
70 {config}Application.verbose_crash=True
70 {config}Application.verbose_crash=True
71 """
71 """
72
72
73
73
74 class CrashHandler(object):
74 class CrashHandler(object):
75 """Customizable crash handlers for IPython applications.
75 """Customizable crash handlers for IPython applications.
76
76
77 Instances of this class provide a :meth:`__call__` method which can be
77 Instances of this class provide a :meth:`__call__` method which can be
78 used as a ``sys.excepthook``. The :meth:`__call__` signature is::
78 used as a ``sys.excepthook``. The :meth:`__call__` signature is::
79
79
80 def __call__(self, etype, evalue, etb)
80 def __call__(self, etype, evalue, etb)
81 """
81 """
82
82
83 message_template = _default_message_template
83 message_template = _default_message_template
84 section_sep = '\n\n'+'*'*75+'\n\n'
84 section_sep = '\n\n'+'*'*75+'\n\n'
85
85
86 def __init__(self, app, contact_name=None, contact_email=None,
86 def __init__(self, app, contact_name=None, contact_email=None,
87 bug_tracker=None, show_crash_traceback=True, call_pdb=False):
87 bug_tracker=None, show_crash_traceback=True, call_pdb=False):
88 """Create a new crash handler
88 """Create a new crash handler
89
89
90 Parameters
90 Parameters
91 ----------
91 ----------
92 app : Application
92 app : Application
93 A running :class:`Application` instance, which will be queried at
93 A running :class:`Application` instance, which will be queried at
94 crash time for internal information.
94 crash time for internal information.
95
95
96 contact_name : str
96 contact_name : str
97 A string with the name of the person to contact.
97 A string with the name of the person to contact.
98
98
99 contact_email : str
99 contact_email : str
100 A string with the email address of the contact.
100 A string with the email address of the contact.
101
101
102 bug_tracker : str
102 bug_tracker : str
103 A string with the URL for your project's bug tracker.
103 A string with the URL for your project's bug tracker.
104
104
105 show_crash_traceback : bool
105 show_crash_traceback : bool
106 If false, don't print the crash traceback on stderr, only generate
106 If false, don't print the crash traceback on stderr, only generate
107 the on-disk report
107 the on-disk report
108
108
109 Non-argument instance attributes:
109 Non-argument instance attributes:
110
110
111 These instances contain some non-argument attributes which allow for
111 These instances contain some non-argument attributes which allow for
112 further customization of the crash handler's behavior. Please see the
112 further customization of the crash handler's behavior. Please see the
113 source for further details.
113 source for further details.
114 """
114 """
115 self.crash_report_fname = "Crash_report_%s.txt" % app.name
115 self.crash_report_fname = "Crash_report_%s.txt" % app.name
116 self.app = app
116 self.app = app
117 self.call_pdb = call_pdb
117 self.call_pdb = call_pdb
118 #self.call_pdb = True # dbg
118 #self.call_pdb = True # dbg
119 self.show_crash_traceback = show_crash_traceback
119 self.show_crash_traceback = show_crash_traceback
120 self.info = dict(app_name = app.name,
120 self.info = dict(app_name = app.name,
121 contact_name = contact_name,
121 contact_name = contact_name,
122 contact_email = contact_email,
122 contact_email = contact_email,
123 bug_tracker = bug_tracker,
123 bug_tracker = bug_tracker,
124 crash_report_fname = self.crash_report_fname)
124 crash_report_fname = self.crash_report_fname)
125
125
126
126
127 def __call__(self, etype, evalue, etb):
127 def __call__(self, etype, evalue, etb):
128 """Handle an exception, call for compatible with sys.excepthook"""
128 """Handle an exception, call for compatible with sys.excepthook"""
129
129
130 # do not allow the crash handler to be called twice without reinstalling it
130 # do not allow the crash handler to be called twice without reinstalling it
131 # this prevents unlikely errors in the crash handling from entering an
131 # this prevents unlikely errors in the crash handling from entering an
132 # infinite loop.
132 # infinite loop.
133 sys.excepthook = sys.__excepthook__
133 sys.excepthook = sys.__excepthook__
134
134
135 # Report tracebacks shouldn't use color in general (safer for users)
135 # Report tracebacks shouldn't use color in general (safer for users)
136 color_scheme = 'NoColor'
136 color_scheme = 'NoColor'
137
137
138 # Use this ONLY for developer debugging (keep commented out for release)
138 # Use this ONLY for developer debugging (keep commented out for release)
139 #color_scheme = 'Linux' # dbg
139 #color_scheme = 'Linux' # dbg
140 try:
140 try:
141 rptdir = self.app.ipython_dir
141 rptdir = self.app.ipython_dir
142 except:
142 except:
143 rptdir = os.getcwdu()
143 rptdir = getcwd()
144 if rptdir is None or not os.path.isdir(rptdir):
144 if rptdir is None or not os.path.isdir(rptdir):
145 rptdir = os.getcwdu()
145 rptdir = getcwd()
146 report_name = os.path.join(rptdir,self.crash_report_fname)
146 report_name = os.path.join(rptdir,self.crash_report_fname)
147 # write the report filename into the instance dict so it can get
147 # write the report filename into the instance dict so it can get
148 # properly expanded out in the user message template
148 # properly expanded out in the user message template
149 self.crash_report_fname = report_name
149 self.crash_report_fname = report_name
150 self.info['crash_report_fname'] = report_name
150 self.info['crash_report_fname'] = report_name
151 TBhandler = ultratb.VerboseTB(
151 TBhandler = ultratb.VerboseTB(
152 color_scheme=color_scheme,
152 color_scheme=color_scheme,
153 long_header=1,
153 long_header=1,
154 call_pdb=self.call_pdb,
154 call_pdb=self.call_pdb,
155 )
155 )
156 if self.call_pdb:
156 if self.call_pdb:
157 TBhandler(etype,evalue,etb)
157 TBhandler(etype,evalue,etb)
158 return
158 return
159 else:
159 else:
160 traceback = TBhandler.text(etype,evalue,etb,context=31)
160 traceback = TBhandler.text(etype,evalue,etb,context=31)
161
161
162 # print traceback to screen
162 # print traceback to screen
163 if self.show_crash_traceback:
163 if self.show_crash_traceback:
164 print(traceback, file=sys.stderr)
164 print(traceback, file=sys.stderr)
165
165
166 # and generate a complete report on disk
166 # and generate a complete report on disk
167 try:
167 try:
168 report = open(report_name,'w')
168 report = open(report_name,'w')
169 except:
169 except:
170 print('Could not create crash report on disk.', file=sys.stderr)
170 print('Could not create crash report on disk.', file=sys.stderr)
171 return
171 return
172
172
173 # Inform user on stderr of what happened
173 # Inform user on stderr of what happened
174 print('\n'+'*'*70+'\n', file=sys.stderr)
174 print('\n'+'*'*70+'\n', file=sys.stderr)
175 print(self.message_template.format(**self.info), file=sys.stderr)
175 print(self.message_template.format(**self.info), file=sys.stderr)
176
176
177 # Construct report on disk
177 # Construct report on disk
178 report.write(self.make_report(traceback))
178 report.write(self.make_report(traceback))
179 report.close()
179 report.close()
180 input("Hit <Enter> to quit (your terminal may close):")
180 input("Hit <Enter> to quit (your terminal may close):")
181
181
182 def make_report(self,traceback):
182 def make_report(self,traceback):
183 """Return a string containing a crash report."""
183 """Return a string containing a crash report."""
184
184
185 sec_sep = self.section_sep
185 sec_sep = self.section_sep
186
186
187 report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
187 report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
188 rpt_add = report.append
188 rpt_add = report.append
189 rpt_add(sys_info())
189 rpt_add(sys_info())
190
190
191 try:
191 try:
192 config = pformat(self.app.config)
192 config = pformat(self.app.config)
193 rpt_add(sec_sep)
193 rpt_add(sec_sep)
194 rpt_add('Application name: %s\n\n' % self.app_name)
194 rpt_add('Application name: %s\n\n' % self.app_name)
195 rpt_add('Current user configuration structure:\n\n')
195 rpt_add('Current user configuration structure:\n\n')
196 rpt_add(config)
196 rpt_add(config)
197 except:
197 except:
198 pass
198 pass
199 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
199 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
200
200
201 return ''.join(report)
201 return ''.join(report)
202
202
203
203
204 def crash_handler_lite(etype, evalue, tb):
204 def crash_handler_lite(etype, evalue, tb):
205 """a light excepthook, adding a small message to the usual traceback"""
205 """a light excepthook, adding a small message to the usual traceback"""
206 traceback.print_exception(etype, evalue, tb)
206 traceback.print_exception(etype, evalue, tb)
207
207
208 from IPython.core.interactiveshell import InteractiveShell
208 from IPython.core.interactiveshell import InteractiveShell
209 if InteractiveShell.initialized():
209 if InteractiveShell.initialized():
210 # we are in a Shell environment, give %magic example
210 # we are in a Shell environment, give %magic example
211 config = "%config "
211 config = "%config "
212 else:
212 else:
213 # we are not in a shell, show generic config
213 # we are not in a shell, show generic config
214 config = "c."
214 config = "c."
215 print(_lite_message_template.format(email=author_email, config=config), file=sys.stderr)
215 print(_lite_message_template.format(email=author_email, config=config), file=sys.stderr)
216
216
@@ -1,807 +1,808 b''
1 """ History related magics and functionality """
1 """ History related magics and functionality """
2 #-----------------------------------------------------------------------------
2 #-----------------------------------------------------------------------------
3 # Copyright (C) 2010-2011 The IPython Development Team.
3 # Copyright (C) 2010-2011 The IPython Development Team.
4 #
4 #
5 # Distributed under the terms of the BSD License.
5 # Distributed under the terms of the BSD License.
6 #
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 from __future__ import print_function
13 from __future__ import print_function
14
14
15 # Stdlib imports
15 # Stdlib imports
16 import atexit
16 import atexit
17 import datetime
17 import datetime
18 import os
18 import os
19 import re
19 import re
20 try:
20 try:
21 import sqlite3
21 import sqlite3
22 except ImportError:
22 except ImportError:
23 try:
23 try:
24 from pysqlite2 import dbapi2 as sqlite3
24 from pysqlite2 import dbapi2 as sqlite3
25 except ImportError:
25 except ImportError:
26 sqlite3 = None
26 sqlite3 = None
27 import threading
27 import threading
28
28
29 # Our own packages
29 # Our own packages
30 from IPython.config.configurable import Configurable
30 from IPython.config.configurable import Configurable
31 from IPython.external.decorator import decorator
31 from IPython.external.decorator import decorator
32 from IPython.utils.path import locate_profile
32 from IPython.utils.path import locate_profile
33 from IPython.utils import py3compat
33 from IPython.utils.traitlets import (
34 from IPython.utils.traitlets import (
34 Any, Bool, Dict, Instance, Integer, List, Unicode, TraitError,
35 Any, Bool, Dict, Instance, Integer, List, Unicode, TraitError,
35 )
36 )
36 from IPython.utils.warn import warn
37 from IPython.utils.warn import warn
37
38
38 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
39 # Classes and functions
40 # Classes and functions
40 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
41
42
42 class DummyDB(object):
43 class DummyDB(object):
43 """Dummy DB that will act as a black hole for history.
44 """Dummy DB that will act as a black hole for history.
44
45
45 Only used in the absence of sqlite"""
46 Only used in the absence of sqlite"""
46 def execute(*args, **kwargs):
47 def execute(*args, **kwargs):
47 return []
48 return []
48
49
49 def commit(self, *args, **kwargs):
50 def commit(self, *args, **kwargs):
50 pass
51 pass
51
52
52 def __enter__(self, *args, **kwargs):
53 def __enter__(self, *args, **kwargs):
53 pass
54 pass
54
55
55 def __exit__(self, *args, **kwargs):
56 def __exit__(self, *args, **kwargs):
56 pass
57 pass
57
58
58
59
59 @decorator
60 @decorator
60 def needs_sqlite(f, self, *a, **kw):
61 def needs_sqlite(f, self, *a, **kw):
61 """return an empty list in the absence of sqlite"""
62 """return an empty list in the absence of sqlite"""
62 if sqlite3 is None or not self.enabled:
63 if sqlite3 is None or not self.enabled:
63 return []
64 return []
64 else:
65 else:
65 return f(self, *a, **kw)
66 return f(self, *a, **kw)
66
67
67
68
68 if sqlite3 is not None:
69 if sqlite3 is not None:
69 DatabaseError = sqlite3.DatabaseError
70 DatabaseError = sqlite3.DatabaseError
70 else:
71 else:
71 class DatabaseError(Exception):
72 class DatabaseError(Exception):
72 "Dummy exception when sqlite could not be imported. Should never occur."
73 "Dummy exception when sqlite could not be imported. Should never occur."
73
74
74 @decorator
75 @decorator
75 def catch_corrupt_db(f, self, *a, **kw):
76 def catch_corrupt_db(f, self, *a, **kw):
76 """A decorator which wraps HistoryAccessor method calls to catch errors from
77 """A decorator which wraps HistoryAccessor method calls to catch errors from
77 a corrupt SQLite database, move the old database out of the way, and create
78 a corrupt SQLite database, move the old database out of the way, and create
78 a new one.
79 a new one.
79 """
80 """
80 try:
81 try:
81 return f(self, *a, **kw)
82 return f(self, *a, **kw)
82 except DatabaseError:
83 except DatabaseError:
83 if os.path.isfile(self.hist_file):
84 if os.path.isfile(self.hist_file):
84 # Try to move the file out of the way
85 # Try to move the file out of the way
85 base,ext = os.path.splitext(self.hist_file)
86 base,ext = os.path.splitext(self.hist_file)
86 newpath = base + '-corrupt' + ext
87 newpath = base + '-corrupt' + ext
87 os.rename(self.hist_file, newpath)
88 os.rename(self.hist_file, newpath)
88 self.init_db()
89 self.init_db()
89 print("ERROR! History file wasn't a valid SQLite database.",
90 print("ERROR! History file wasn't a valid SQLite database.",
90 "It was moved to %s" % newpath, "and a new file created.")
91 "It was moved to %s" % newpath, "and a new file created.")
91 return []
92 return []
92
93
93 else:
94 else:
94 # The hist_file is probably :memory: or something else.
95 # The hist_file is probably :memory: or something else.
95 raise
96 raise
96
97
97
98
98
99
99 class HistoryAccessor(Configurable):
100 class HistoryAccessor(Configurable):
100 """Access the history database without adding to it.
101 """Access the history database without adding to it.
101
102
102 This is intended for use by standalone history tools. IPython shells use
103 This is intended for use by standalone history tools. IPython shells use
103 HistoryManager, below, which is a subclass of this."""
104 HistoryManager, below, which is a subclass of this."""
104
105
105 # String holding the path to the history file
106 # String holding the path to the history file
106 hist_file = Unicode(config=True,
107 hist_file = Unicode(config=True,
107 help="""Path to file to use for SQLite history database.
108 help="""Path to file to use for SQLite history database.
108
109
109 By default, IPython will put the history database in the IPython
110 By default, IPython will put the history database in the IPython
110 profile directory. If you would rather share one history among
111 profile directory. If you would rather share one history among
111 profiles, you can set this value in each, so that they are consistent.
112 profiles, you can set this value in each, so that they are consistent.
112
113
113 Due to an issue with fcntl, SQLite is known to misbehave on some NFS
114 Due to an issue with fcntl, SQLite is known to misbehave on some NFS
114 mounts. If you see IPython hanging, try setting this to something on a
115 mounts. If you see IPython hanging, try setting this to something on a
115 local disk, e.g::
116 local disk, e.g::
116
117
117 ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite
118 ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite
118
119
119 """)
120 """)
120
121
121 enabled = Bool(True, config=True,
122 enabled = Bool(True, config=True,
122 help="""enable the SQLite history
123 help="""enable the SQLite history
123
124
124 set enabled=False to disable the SQLite history,
125 set enabled=False to disable the SQLite history,
125 in which case there will be no stored history, no SQLite connection,
126 in which case there will be no stored history, no SQLite connection,
126 and no background saving thread. This may be necessary in some
127 and no background saving thread. This may be necessary in some
127 threaded environments where IPython is embedded.
128 threaded environments where IPython is embedded.
128 """
129 """
129 )
130 )
130
131
131 connection_options = Dict(config=True,
132 connection_options = Dict(config=True,
132 help="""Options for configuring the SQLite connection
133 help="""Options for configuring the SQLite connection
133
134
134 These options are passed as keyword args to sqlite3.connect
135 These options are passed as keyword args to sqlite3.connect
135 when establishing database conenctions.
136 when establishing database conenctions.
136 """
137 """
137 )
138 )
138
139
139 # The SQLite database
140 # The SQLite database
140 db = Any()
141 db = Any()
141 def _db_changed(self, name, old, new):
142 def _db_changed(self, name, old, new):
142 """validate the db, since it can be an Instance of two different types"""
143 """validate the db, since it can be an Instance of two different types"""
143 connection_types = (DummyDB,)
144 connection_types = (DummyDB,)
144 if sqlite3 is not None:
145 if sqlite3 is not None:
145 connection_types = (DummyDB, sqlite3.Connection)
146 connection_types = (DummyDB, sqlite3.Connection)
146 if not isinstance(new, connection_types):
147 if not isinstance(new, connection_types):
147 msg = "%s.db must be sqlite3 Connection or DummyDB, not %r" % \
148 msg = "%s.db must be sqlite3 Connection or DummyDB, not %r" % \
148 (self.__class__.__name__, new)
149 (self.__class__.__name__, new)
149 raise TraitError(msg)
150 raise TraitError(msg)
150
151
151 def __init__(self, profile='default', hist_file=u'', **traits):
152 def __init__(self, profile='default', hist_file=u'', **traits):
152 """Create a new history accessor.
153 """Create a new history accessor.
153
154
154 Parameters
155 Parameters
155 ----------
156 ----------
156 profile : str
157 profile : str
157 The name of the profile from which to open history.
158 The name of the profile from which to open history.
158 hist_file : str
159 hist_file : str
159 Path to an SQLite history database stored by IPython. If specified,
160 Path to an SQLite history database stored by IPython. If specified,
160 hist_file overrides profile.
161 hist_file overrides profile.
161 config :
162 config :
162 Config object. hist_file can also be set through this.
163 Config object. hist_file can also be set through this.
163 """
164 """
164 # We need a pointer back to the shell for various tasks.
165 # We need a pointer back to the shell for various tasks.
165 super(HistoryAccessor, self).__init__(**traits)
166 super(HistoryAccessor, self).__init__(**traits)
166 # defer setting hist_file from kwarg until after init,
167 # defer setting hist_file from kwarg until after init,
167 # otherwise the default kwarg value would clobber any value
168 # otherwise the default kwarg value would clobber any value
168 # set by config
169 # set by config
169 if hist_file:
170 if hist_file:
170 self.hist_file = hist_file
171 self.hist_file = hist_file
171
172
172 if self.hist_file == u'':
173 if self.hist_file == u'':
173 # No one has set the hist_file, yet.
174 # No one has set the hist_file, yet.
174 self.hist_file = self._get_hist_file_name(profile)
175 self.hist_file = self._get_hist_file_name(profile)
175
176
176 if sqlite3 is None and self.enabled:
177 if sqlite3 is None and self.enabled:
177 warn("IPython History requires SQLite, your history will not be saved")
178 warn("IPython History requires SQLite, your history will not be saved")
178 self.enabled = False
179 self.enabled = False
179
180
180 self.init_db()
181 self.init_db()
181
182
182 def _get_hist_file_name(self, profile='default'):
183 def _get_hist_file_name(self, profile='default'):
183 """Find the history file for the given profile name.
184 """Find the history file for the given profile name.
184
185
185 This is overridden by the HistoryManager subclass, to use the shell's
186 This is overridden by the HistoryManager subclass, to use the shell's
186 active profile.
187 active profile.
187
188
188 Parameters
189 Parameters
189 ----------
190 ----------
190 profile : str
191 profile : str
191 The name of a profile which has a history file.
192 The name of a profile which has a history file.
192 """
193 """
193 return os.path.join(locate_profile(profile), 'history.sqlite')
194 return os.path.join(locate_profile(profile), 'history.sqlite')
194
195
195 @catch_corrupt_db
196 @catch_corrupt_db
196 def init_db(self):
197 def init_db(self):
197 """Connect to the database, and create tables if necessary."""
198 """Connect to the database, and create tables if necessary."""
198 if not self.enabled:
199 if not self.enabled:
199 self.db = DummyDB()
200 self.db = DummyDB()
200 return
201 return
201
202
202 # use detect_types so that timestamps return datetime objects
203 # use detect_types so that timestamps return datetime objects
203 kwargs = dict(detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
204 kwargs = dict(detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
204 kwargs.update(self.connection_options)
205 kwargs.update(self.connection_options)
205 self.db = sqlite3.connect(self.hist_file, **kwargs)
206 self.db = sqlite3.connect(self.hist_file, **kwargs)
206 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
207 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
207 primary key autoincrement, start timestamp,
208 primary key autoincrement, start timestamp,
208 end timestamp, num_cmds integer, remark text)""")
209 end timestamp, num_cmds integer, remark text)""")
209 self.db.execute("""CREATE TABLE IF NOT EXISTS history
210 self.db.execute("""CREATE TABLE IF NOT EXISTS history
210 (session integer, line integer, source text, source_raw text,
211 (session integer, line integer, source text, source_raw text,
211 PRIMARY KEY (session, line))""")
212 PRIMARY KEY (session, line))""")
212 # Output history is optional, but ensure the table's there so it can be
213 # Output history is optional, but ensure the table's there so it can be
213 # enabled later.
214 # enabled later.
214 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
215 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
215 (session integer, line integer, output text,
216 (session integer, line integer, output text,
216 PRIMARY KEY (session, line))""")
217 PRIMARY KEY (session, line))""")
217 self.db.commit()
218 self.db.commit()
218
219
219 def writeout_cache(self):
220 def writeout_cache(self):
220 """Overridden by HistoryManager to dump the cache before certain
221 """Overridden by HistoryManager to dump the cache before certain
221 database lookups."""
222 database lookups."""
222 pass
223 pass
223
224
224 ## -------------------------------
225 ## -------------------------------
225 ## Methods for retrieving history:
226 ## Methods for retrieving history:
226 ## -------------------------------
227 ## -------------------------------
227 def _run_sql(self, sql, params, raw=True, output=False):
228 def _run_sql(self, sql, params, raw=True, output=False):
228 """Prepares and runs an SQL query for the history database.
229 """Prepares and runs an SQL query for the history database.
229
230
230 Parameters
231 Parameters
231 ----------
232 ----------
232 sql : str
233 sql : str
233 Any filtering expressions to go after SELECT ... FROM ...
234 Any filtering expressions to go after SELECT ... FROM ...
234 params : tuple
235 params : tuple
235 Parameters passed to the SQL query (to replace "?")
236 Parameters passed to the SQL query (to replace "?")
236 raw, output : bool
237 raw, output : bool
237 See :meth:`get_range`
238 See :meth:`get_range`
238
239
239 Returns
240 Returns
240 -------
241 -------
241 Tuples as :meth:`get_range`
242 Tuples as :meth:`get_range`
242 """
243 """
243 toget = 'source_raw' if raw else 'source'
244 toget = 'source_raw' if raw else 'source'
244 sqlfrom = "history"
245 sqlfrom = "history"
245 if output:
246 if output:
246 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
247 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
247 toget = "history.%s, output_history.output" % toget
248 toget = "history.%s, output_history.output" % toget
248 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
249 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
249 (toget, sqlfrom) + sql, params)
250 (toget, sqlfrom) + sql, params)
250 if output: # Regroup into 3-tuples, and parse JSON
251 if output: # Regroup into 3-tuples, and parse JSON
251 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
252 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
252 return cur
253 return cur
253
254
254 @needs_sqlite
255 @needs_sqlite
255 @catch_corrupt_db
256 @catch_corrupt_db
256 def get_session_info(self, session=0):
257 def get_session_info(self, session=0):
257 """get info about a session
258 """get info about a session
258
259
259 Parameters
260 Parameters
260 ----------
261 ----------
261
262
262 session : int
263 session : int
263 Session number to retrieve. The current session is 0, and negative
264 Session number to retrieve. The current session is 0, and negative
264 numbers count back from current session, so -1 is previous session.
265 numbers count back from current session, so -1 is previous session.
265
266
266 Returns
267 Returns
267 -------
268 -------
268
269
269 (session_id [int], start [datetime], end [datetime], num_cmds [int],
270 (session_id [int], start [datetime], end [datetime], num_cmds [int],
270 remark [unicode])
271 remark [unicode])
271
272
272 Sessions that are running or did not exit cleanly will have `end=None`
273 Sessions that are running or did not exit cleanly will have `end=None`
273 and `num_cmds=None`.
274 and `num_cmds=None`.
274
275
275 """
276 """
276
277
277 if session <= 0:
278 if session <= 0:
278 session += self.session_number
279 session += self.session_number
279
280
280 query = "SELECT * from sessions where session == ?"
281 query = "SELECT * from sessions where session == ?"
281 return self.db.execute(query, (session,)).fetchone()
282 return self.db.execute(query, (session,)).fetchone()
282
283
283 @catch_corrupt_db
284 @catch_corrupt_db
284 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
285 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
285 """Get the last n lines from the history database.
286 """Get the last n lines from the history database.
286
287
287 Parameters
288 Parameters
288 ----------
289 ----------
289 n : int
290 n : int
290 The number of lines to get
291 The number of lines to get
291 raw, output : bool
292 raw, output : bool
292 See :meth:`get_range`
293 See :meth:`get_range`
293 include_latest : bool
294 include_latest : bool
294 If False (default), n+1 lines are fetched, and the latest one
295 If False (default), n+1 lines are fetched, and the latest one
295 is discarded. This is intended to be used where the function
296 is discarded. This is intended to be used where the function
296 is called by a user command, which it should not return.
297 is called by a user command, which it should not return.
297
298
298 Returns
299 Returns
299 -------
300 -------
300 Tuples as :meth:`get_range`
301 Tuples as :meth:`get_range`
301 """
302 """
302 self.writeout_cache()
303 self.writeout_cache()
303 if not include_latest:
304 if not include_latest:
304 n += 1
305 n += 1
305 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
306 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
306 (n,), raw=raw, output=output)
307 (n,), raw=raw, output=output)
307 if not include_latest:
308 if not include_latest:
308 return reversed(list(cur)[1:])
309 return reversed(list(cur)[1:])
309 return reversed(list(cur))
310 return reversed(list(cur))
310
311
311 @catch_corrupt_db
312 @catch_corrupt_db
312 def search(self, pattern="*", raw=True, search_raw=True,
313 def search(self, pattern="*", raw=True, search_raw=True,
313 output=False, n=None, unique=False):
314 output=False, n=None, unique=False):
314 """Search the database using unix glob-style matching (wildcards
315 """Search the database using unix glob-style matching (wildcards
315 * and ?).
316 * and ?).
316
317
317 Parameters
318 Parameters
318 ----------
319 ----------
319 pattern : str
320 pattern : str
320 The wildcarded pattern to match when searching
321 The wildcarded pattern to match when searching
321 search_raw : bool
322 search_raw : bool
322 If True, search the raw input, otherwise, the parsed input
323 If True, search the raw input, otherwise, the parsed input
323 raw, output : bool
324 raw, output : bool
324 See :meth:`get_range`
325 See :meth:`get_range`
325 n : None or int
326 n : None or int
326 If an integer is given, it defines the limit of
327 If an integer is given, it defines the limit of
327 returned entries.
328 returned entries.
328 unique : bool
329 unique : bool
329 When it is true, return only unique entries.
330 When it is true, return only unique entries.
330
331
331 Returns
332 Returns
332 -------
333 -------
333 Tuples as :meth:`get_range`
334 Tuples as :meth:`get_range`
334 """
335 """
335 tosearch = "source_raw" if search_raw else "source"
336 tosearch = "source_raw" if search_raw else "source"
336 if output:
337 if output:
337 tosearch = "history." + tosearch
338 tosearch = "history." + tosearch
338 self.writeout_cache()
339 self.writeout_cache()
339 sqlform = "WHERE %s GLOB ?" % tosearch
340 sqlform = "WHERE %s GLOB ?" % tosearch
340 params = (pattern,)
341 params = (pattern,)
341 if unique:
342 if unique:
342 sqlform += ' GROUP BY {0}'.format(tosearch)
343 sqlform += ' GROUP BY {0}'.format(tosearch)
343 if n is not None:
344 if n is not None:
344 sqlform += " ORDER BY session DESC, line DESC LIMIT ?"
345 sqlform += " ORDER BY session DESC, line DESC LIMIT ?"
345 params += (n,)
346 params += (n,)
346 elif unique:
347 elif unique:
347 sqlform += " ORDER BY session, line"
348 sqlform += " ORDER BY session, line"
348 cur = self._run_sql(sqlform, params, raw=raw, output=output)
349 cur = self._run_sql(sqlform, params, raw=raw, output=output)
349 if n is not None:
350 if n is not None:
350 return reversed(list(cur))
351 return reversed(list(cur))
351 return cur
352 return cur
352
353
353 @catch_corrupt_db
354 @catch_corrupt_db
354 def get_range(self, session, start=1, stop=None, raw=True,output=False):
355 def get_range(self, session, start=1, stop=None, raw=True,output=False):
355 """Retrieve input by session.
356 """Retrieve input by session.
356
357
357 Parameters
358 Parameters
358 ----------
359 ----------
359 session : int
360 session : int
360 Session number to retrieve.
361 Session number to retrieve.
361 start : int
362 start : int
362 First line to retrieve.
363 First line to retrieve.
363 stop : int
364 stop : int
364 End of line range (excluded from output itself). If None, retrieve
365 End of line range (excluded from output itself). If None, retrieve
365 to the end of the session.
366 to the end of the session.
366 raw : bool
367 raw : bool
367 If True, return untranslated input
368 If True, return untranslated input
368 output : bool
369 output : bool
369 If True, attempt to include output. This will be 'real' Python
370 If True, attempt to include output. This will be 'real' Python
370 objects for the current session, or text reprs from previous
371 objects for the current session, or text reprs from previous
371 sessions if db_log_output was enabled at the time. Where no output
372 sessions if db_log_output was enabled at the time. Where no output
372 is found, None is used.
373 is found, None is used.
373
374
374 Returns
375 Returns
375 -------
376 -------
376 An iterator over the desired lines. Each line is a 3-tuple, either
377 An iterator over the desired lines. Each line is a 3-tuple, either
377 (session, line, input) if output is False, or
378 (session, line, input) if output is False, or
378 (session, line, (input, output)) if output is True.
379 (session, line, (input, output)) if output is True.
379 """
380 """
380 if stop:
381 if stop:
381 lineclause = "line >= ? AND line < ?"
382 lineclause = "line >= ? AND line < ?"
382 params = (session, start, stop)
383 params = (session, start, stop)
383 else:
384 else:
384 lineclause = "line>=?"
385 lineclause = "line>=?"
385 params = (session, start)
386 params = (session, start)
386
387
387 return self._run_sql("WHERE session==? AND %s" % lineclause,
388 return self._run_sql("WHERE session==? AND %s" % lineclause,
388 params, raw=raw, output=output)
389 params, raw=raw, output=output)
389
390
390 def get_range_by_str(self, rangestr, raw=True, output=False):
391 def get_range_by_str(self, rangestr, raw=True, output=False):
391 """Get lines of history from a string of ranges, as used by magic
392 """Get lines of history from a string of ranges, as used by magic
392 commands %hist, %save, %macro, etc.
393 commands %hist, %save, %macro, etc.
393
394
394 Parameters
395 Parameters
395 ----------
396 ----------
396 rangestr : str
397 rangestr : str
397 A string specifying ranges, e.g. "5 ~2/1-4". See
398 A string specifying ranges, e.g. "5 ~2/1-4". See
398 :func:`magic_history` for full details.
399 :func:`magic_history` for full details.
399 raw, output : bool
400 raw, output : bool
400 As :meth:`get_range`
401 As :meth:`get_range`
401
402
402 Returns
403 Returns
403 -------
404 -------
404 Tuples as :meth:`get_range`
405 Tuples as :meth:`get_range`
405 """
406 """
406 for sess, s, e in extract_hist_ranges(rangestr):
407 for sess, s, e in extract_hist_ranges(rangestr):
407 for line in self.get_range(sess, s, e, raw=raw, output=output):
408 for line in self.get_range(sess, s, e, raw=raw, output=output):
408 yield line
409 yield line
409
410
410
411
411 class HistoryManager(HistoryAccessor):
412 class HistoryManager(HistoryAccessor):
412 """A class to organize all history-related functionality in one place.
413 """A class to organize all history-related functionality in one place.
413 """
414 """
414 # Public interface
415 # Public interface
415
416
416 # An instance of the IPython shell we are attached to
417 # An instance of the IPython shell we are attached to
417 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
418 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
418 # Lists to hold processed and raw history. These start with a blank entry
419 # Lists to hold processed and raw history. These start with a blank entry
419 # so that we can index them starting from 1
420 # so that we can index them starting from 1
420 input_hist_parsed = List([""])
421 input_hist_parsed = List([""])
421 input_hist_raw = List([""])
422 input_hist_raw = List([""])
422 # A list of directories visited during session
423 # A list of directories visited during session
423 dir_hist = List()
424 dir_hist = List()
424 def _dir_hist_default(self):
425 def _dir_hist_default(self):
425 try:
426 try:
426 return [os.getcwdu()]
427 return [py3compat.getcwd()]
427 except OSError:
428 except OSError:
428 return []
429 return []
429
430
430 # A dict of output history, keyed with ints from the shell's
431 # A dict of output history, keyed with ints from the shell's
431 # execution count.
432 # execution count.
432 output_hist = Dict()
433 output_hist = Dict()
433 # The text/plain repr of outputs.
434 # The text/plain repr of outputs.
434 output_hist_reprs = Dict()
435 output_hist_reprs = Dict()
435
436
436 # The number of the current session in the history database
437 # The number of the current session in the history database
437 session_number = Integer()
438 session_number = Integer()
438 # Should we log output to the database? (default no)
439 # Should we log output to the database? (default no)
439 db_log_output = Bool(False, config=True)
440 db_log_output = Bool(False, config=True)
440 # Write to database every x commands (higher values save disk access & power)
441 # Write to database every x commands (higher values save disk access & power)
441 # Values of 1 or less effectively disable caching.
442 # Values of 1 or less effectively disable caching.
442 db_cache_size = Integer(0, config=True)
443 db_cache_size = Integer(0, config=True)
443 # The input and output caches
444 # The input and output caches
444 db_input_cache = List()
445 db_input_cache = List()
445 db_output_cache = List()
446 db_output_cache = List()
446
447
447 # History saving in separate thread
448 # History saving in separate thread
448 save_thread = Instance('IPython.core.history.HistorySavingThread')
449 save_thread = Instance('IPython.core.history.HistorySavingThread')
449 try: # Event is a function returning an instance of _Event...
450 try: # Event is a function returning an instance of _Event...
450 save_flag = Instance(threading._Event)
451 save_flag = Instance(threading._Event)
451 except AttributeError: # ...until Python 3.3, when it's a class.
452 except AttributeError: # ...until Python 3.3, when it's a class.
452 save_flag = Instance(threading.Event)
453 save_flag = Instance(threading.Event)
453
454
454 # Private interface
455 # Private interface
455 # Variables used to store the three last inputs from the user. On each new
456 # Variables used to store the three last inputs from the user. On each new
456 # history update, we populate the user's namespace with these, shifted as
457 # history update, we populate the user's namespace with these, shifted as
457 # necessary.
458 # necessary.
458 _i00 = Unicode(u'')
459 _i00 = Unicode(u'')
459 _i = Unicode(u'')
460 _i = Unicode(u'')
460 _ii = Unicode(u'')
461 _ii = Unicode(u'')
461 _iii = Unicode(u'')
462 _iii = Unicode(u'')
462
463
463 # A regex matching all forms of the exit command, so that we don't store
464 # A regex matching all forms of the exit command, so that we don't store
464 # them in the history (it's annoying to rewind the first entry and land on
465 # them in the history (it's annoying to rewind the first entry and land on
465 # an exit call).
466 # an exit call).
466 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
467 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
467
468
468 def __init__(self, shell=None, config=None, **traits):
469 def __init__(self, shell=None, config=None, **traits):
469 """Create a new history manager associated with a shell instance.
470 """Create a new history manager associated with a shell instance.
470 """
471 """
471 # We need a pointer back to the shell for various tasks.
472 # We need a pointer back to the shell for various tasks.
472 super(HistoryManager, self).__init__(shell=shell, config=config,
473 super(HistoryManager, self).__init__(shell=shell, config=config,
473 **traits)
474 **traits)
474 self.save_flag = threading.Event()
475 self.save_flag = threading.Event()
475 self.db_input_cache_lock = threading.Lock()
476 self.db_input_cache_lock = threading.Lock()
476 self.db_output_cache_lock = threading.Lock()
477 self.db_output_cache_lock = threading.Lock()
477 if self.enabled and self.hist_file != ':memory:':
478 if self.enabled and self.hist_file != ':memory:':
478 self.save_thread = HistorySavingThread(self)
479 self.save_thread = HistorySavingThread(self)
479 self.save_thread.start()
480 self.save_thread.start()
480
481
481 self.new_session()
482 self.new_session()
482
483
483 def _get_hist_file_name(self, profile=None):
484 def _get_hist_file_name(self, profile=None):
484 """Get default history file name based on the Shell's profile.
485 """Get default history file name based on the Shell's profile.
485
486
486 The profile parameter is ignored, but must exist for compatibility with
487 The profile parameter is ignored, but must exist for compatibility with
487 the parent class."""
488 the parent class."""
488 profile_dir = self.shell.profile_dir.location
489 profile_dir = self.shell.profile_dir.location
489 return os.path.join(profile_dir, 'history.sqlite')
490 return os.path.join(profile_dir, 'history.sqlite')
490
491
491 @needs_sqlite
492 @needs_sqlite
492 def new_session(self, conn=None):
493 def new_session(self, conn=None):
493 """Get a new session number."""
494 """Get a new session number."""
494 if conn is None:
495 if conn is None:
495 conn = self.db
496 conn = self.db
496
497
497 with conn:
498 with conn:
498 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
499 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
499 NULL, "") """, (datetime.datetime.now(),))
500 NULL, "") """, (datetime.datetime.now(),))
500 self.session_number = cur.lastrowid
501 self.session_number = cur.lastrowid
501
502
502 def end_session(self):
503 def end_session(self):
503 """Close the database session, filling in the end time and line count."""
504 """Close the database session, filling in the end time and line count."""
504 self.writeout_cache()
505 self.writeout_cache()
505 with self.db:
506 with self.db:
506 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
507 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
507 session==?""", (datetime.datetime.now(),
508 session==?""", (datetime.datetime.now(),
508 len(self.input_hist_parsed)-1, self.session_number))
509 len(self.input_hist_parsed)-1, self.session_number))
509 self.session_number = 0
510 self.session_number = 0
510
511
511 def name_session(self, name):
512 def name_session(self, name):
512 """Give the current session a name in the history database."""
513 """Give the current session a name in the history database."""
513 with self.db:
514 with self.db:
514 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
515 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
515 (name, self.session_number))
516 (name, self.session_number))
516
517
517 def reset(self, new_session=True):
518 def reset(self, new_session=True):
518 """Clear the session history, releasing all object references, and
519 """Clear the session history, releasing all object references, and
519 optionally open a new session."""
520 optionally open a new session."""
520 self.output_hist.clear()
521 self.output_hist.clear()
521 # The directory history can't be completely empty
522 # The directory history can't be completely empty
522 self.dir_hist[:] = [os.getcwdu()]
523 self.dir_hist[:] = [py3compat.getcwd()]
523
524
524 if new_session:
525 if new_session:
525 if self.session_number:
526 if self.session_number:
526 self.end_session()
527 self.end_session()
527 self.input_hist_parsed[:] = [""]
528 self.input_hist_parsed[:] = [""]
528 self.input_hist_raw[:] = [""]
529 self.input_hist_raw[:] = [""]
529 self.new_session()
530 self.new_session()
530
531
531 # ------------------------------
532 # ------------------------------
532 # Methods for retrieving history
533 # Methods for retrieving history
533 # ------------------------------
534 # ------------------------------
534 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
535 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
535 """Get input and output history from the current session. Called by
536 """Get input and output history from the current session. Called by
536 get_range, and takes similar parameters."""
537 get_range, and takes similar parameters."""
537 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
538 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
538
539
539 n = len(input_hist)
540 n = len(input_hist)
540 if start < 0:
541 if start < 0:
541 start += n
542 start += n
542 if not stop or (stop > n):
543 if not stop or (stop > n):
543 stop = n
544 stop = n
544 elif stop < 0:
545 elif stop < 0:
545 stop += n
546 stop += n
546
547
547 for i in range(start, stop):
548 for i in range(start, stop):
548 if output:
549 if output:
549 line = (input_hist[i], self.output_hist_reprs.get(i))
550 line = (input_hist[i], self.output_hist_reprs.get(i))
550 else:
551 else:
551 line = input_hist[i]
552 line = input_hist[i]
552 yield (0, i, line)
553 yield (0, i, line)
553
554
554 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
555 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
555 """Retrieve input by session.
556 """Retrieve input by session.
556
557
557 Parameters
558 Parameters
558 ----------
559 ----------
559 session : int
560 session : int
560 Session number to retrieve. The current session is 0, and negative
561 Session number to retrieve. The current session is 0, and negative
561 numbers count back from current session, so -1 is previous session.
562 numbers count back from current session, so -1 is previous session.
562 start : int
563 start : int
563 First line to retrieve.
564 First line to retrieve.
564 stop : int
565 stop : int
565 End of line range (excluded from output itself). If None, retrieve
566 End of line range (excluded from output itself). If None, retrieve
566 to the end of the session.
567 to the end of the session.
567 raw : bool
568 raw : bool
568 If True, return untranslated input
569 If True, return untranslated input
569 output : bool
570 output : bool
570 If True, attempt to include output. This will be 'real' Python
571 If True, attempt to include output. This will be 'real' Python
571 objects for the current session, or text reprs from previous
572 objects for the current session, or text reprs from previous
572 sessions if db_log_output was enabled at the time. Where no output
573 sessions if db_log_output was enabled at the time. Where no output
573 is found, None is used.
574 is found, None is used.
574
575
575 Returns
576 Returns
576 -------
577 -------
577 An iterator over the desired lines. Each line is a 3-tuple, either
578 An iterator over the desired lines. Each line is a 3-tuple, either
578 (session, line, input) if output is False, or
579 (session, line, input) if output is False, or
579 (session, line, (input, output)) if output is True.
580 (session, line, (input, output)) if output is True.
580 """
581 """
581 if session <= 0:
582 if session <= 0:
582 session += self.session_number
583 session += self.session_number
583 if session==self.session_number: # Current session
584 if session==self.session_number: # Current session
584 return self._get_range_session(start, stop, raw, output)
585 return self._get_range_session(start, stop, raw, output)
585 return super(HistoryManager, self).get_range(session, start, stop, raw,
586 return super(HistoryManager, self).get_range(session, start, stop, raw,
586 output)
587 output)
587
588
588 ## ----------------------------
589 ## ----------------------------
589 ## Methods for storing history:
590 ## Methods for storing history:
590 ## ----------------------------
591 ## ----------------------------
591 def store_inputs(self, line_num, source, source_raw=None):
592 def store_inputs(self, line_num, source, source_raw=None):
592 """Store source and raw input in history and create input cache
593 """Store source and raw input in history and create input cache
593 variables _i*.
594 variables _i*.
594
595
595 Parameters
596 Parameters
596 ----------
597 ----------
597 line_num : int
598 line_num : int
598 The prompt number of this input.
599 The prompt number of this input.
599
600
600 source : str
601 source : str
601 Python input.
602 Python input.
602
603
603 source_raw : str, optional
604 source_raw : str, optional
604 If given, this is the raw input without any IPython transformations
605 If given, this is the raw input without any IPython transformations
605 applied to it. If not given, ``source`` is used.
606 applied to it. If not given, ``source`` is used.
606 """
607 """
607 if source_raw is None:
608 if source_raw is None:
608 source_raw = source
609 source_raw = source
609 source = source.rstrip('\n')
610 source = source.rstrip('\n')
610 source_raw = source_raw.rstrip('\n')
611 source_raw = source_raw.rstrip('\n')
611
612
612 # do not store exit/quit commands
613 # do not store exit/quit commands
613 if self._exit_re.match(source_raw.strip()):
614 if self._exit_re.match(source_raw.strip()):
614 return
615 return
615
616
616 self.input_hist_parsed.append(source)
617 self.input_hist_parsed.append(source)
617 self.input_hist_raw.append(source_raw)
618 self.input_hist_raw.append(source_raw)
618
619
619 with self.db_input_cache_lock:
620 with self.db_input_cache_lock:
620 self.db_input_cache.append((line_num, source, source_raw))
621 self.db_input_cache.append((line_num, source, source_raw))
621 # Trigger to flush cache and write to DB.
622 # Trigger to flush cache and write to DB.
622 if len(self.db_input_cache) >= self.db_cache_size:
623 if len(self.db_input_cache) >= self.db_cache_size:
623 self.save_flag.set()
624 self.save_flag.set()
624
625
625 # update the auto _i variables
626 # update the auto _i variables
626 self._iii = self._ii
627 self._iii = self._ii
627 self._ii = self._i
628 self._ii = self._i
628 self._i = self._i00
629 self._i = self._i00
629 self._i00 = source_raw
630 self._i00 = source_raw
630
631
631 # hackish access to user namespace to create _i1,_i2... dynamically
632 # hackish access to user namespace to create _i1,_i2... dynamically
632 new_i = '_i%s' % line_num
633 new_i = '_i%s' % line_num
633 to_main = {'_i': self._i,
634 to_main = {'_i': self._i,
634 '_ii': self._ii,
635 '_ii': self._ii,
635 '_iii': self._iii,
636 '_iii': self._iii,
636 new_i : self._i00 }
637 new_i : self._i00 }
637
638
638 if self.shell is not None:
639 if self.shell is not None:
639 self.shell.push(to_main, interactive=False)
640 self.shell.push(to_main, interactive=False)
640
641
641 def store_output(self, line_num):
642 def store_output(self, line_num):
642 """If database output logging is enabled, this saves all the
643 """If database output logging is enabled, this saves all the
643 outputs from the indicated prompt number to the database. It's
644 outputs from the indicated prompt number to the database. It's
644 called by run_cell after code has been executed.
645 called by run_cell after code has been executed.
645
646
646 Parameters
647 Parameters
647 ----------
648 ----------
648 line_num : int
649 line_num : int
649 The line number from which to save outputs
650 The line number from which to save outputs
650 """
651 """
651 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
652 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
652 return
653 return
653 output = self.output_hist_reprs[line_num]
654 output = self.output_hist_reprs[line_num]
654
655
655 with self.db_output_cache_lock:
656 with self.db_output_cache_lock:
656 self.db_output_cache.append((line_num, output))
657 self.db_output_cache.append((line_num, output))
657 if self.db_cache_size <= 1:
658 if self.db_cache_size <= 1:
658 self.save_flag.set()
659 self.save_flag.set()
659
660
660 def _writeout_input_cache(self, conn):
661 def _writeout_input_cache(self, conn):
661 with conn:
662 with conn:
662 for line in self.db_input_cache:
663 for line in self.db_input_cache:
663 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
664 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
664 (self.session_number,)+line)
665 (self.session_number,)+line)
665
666
666 def _writeout_output_cache(self, conn):
667 def _writeout_output_cache(self, conn):
667 with conn:
668 with conn:
668 for line in self.db_output_cache:
669 for line in self.db_output_cache:
669 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
670 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
670 (self.session_number,)+line)
671 (self.session_number,)+line)
671
672
672 @needs_sqlite
673 @needs_sqlite
673 def writeout_cache(self, conn=None):
674 def writeout_cache(self, conn=None):
674 """Write any entries in the cache to the database."""
675 """Write any entries in the cache to the database."""
675 if conn is None:
676 if conn is None:
676 conn = self.db
677 conn = self.db
677
678
678 with self.db_input_cache_lock:
679 with self.db_input_cache_lock:
679 try:
680 try:
680 self._writeout_input_cache(conn)
681 self._writeout_input_cache(conn)
681 except sqlite3.IntegrityError:
682 except sqlite3.IntegrityError:
682 self.new_session(conn)
683 self.new_session(conn)
683 print("ERROR! Session/line number was not unique in",
684 print("ERROR! Session/line number was not unique in",
684 "database. History logging moved to new session",
685 "database. History logging moved to new session",
685 self.session_number)
686 self.session_number)
686 try:
687 try:
687 # Try writing to the new session. If this fails, don't
688 # Try writing to the new session. If this fails, don't
688 # recurse
689 # recurse
689 self._writeout_input_cache(conn)
690 self._writeout_input_cache(conn)
690 except sqlite3.IntegrityError:
691 except sqlite3.IntegrityError:
691 pass
692 pass
692 finally:
693 finally:
693 self.db_input_cache = []
694 self.db_input_cache = []
694
695
695 with self.db_output_cache_lock:
696 with self.db_output_cache_lock:
696 try:
697 try:
697 self._writeout_output_cache(conn)
698 self._writeout_output_cache(conn)
698 except sqlite3.IntegrityError:
699 except sqlite3.IntegrityError:
699 print("!! Session/line number for output was not unique",
700 print("!! Session/line number for output was not unique",
700 "in database. Output will not be stored.")
701 "in database. Output will not be stored.")
701 finally:
702 finally:
702 self.db_output_cache = []
703 self.db_output_cache = []
703
704
704
705
705 class HistorySavingThread(threading.Thread):
706 class HistorySavingThread(threading.Thread):
706 """This thread takes care of writing history to the database, so that
707 """This thread takes care of writing history to the database, so that
707 the UI isn't held up while that happens.
708 the UI isn't held up while that happens.
708
709
709 It waits for the HistoryManager's save_flag to be set, then writes out
710 It waits for the HistoryManager's save_flag to be set, then writes out
710 the history cache. The main thread is responsible for setting the flag when
711 the history cache. The main thread is responsible for setting the flag when
711 the cache size reaches a defined threshold."""
712 the cache size reaches a defined threshold."""
712 daemon = True
713 daemon = True
713 stop_now = False
714 stop_now = False
714 enabled = True
715 enabled = True
715 def __init__(self, history_manager):
716 def __init__(self, history_manager):
716 super(HistorySavingThread, self).__init__(name="IPythonHistorySavingThread")
717 super(HistorySavingThread, self).__init__(name="IPythonHistorySavingThread")
717 self.history_manager = history_manager
718 self.history_manager = history_manager
718 self.enabled = history_manager.enabled
719 self.enabled = history_manager.enabled
719 atexit.register(self.stop)
720 atexit.register(self.stop)
720
721
721 @needs_sqlite
722 @needs_sqlite
722 def run(self):
723 def run(self):
723 # We need a separate db connection per thread:
724 # We need a separate db connection per thread:
724 try:
725 try:
725 self.db = sqlite3.connect(self.history_manager.hist_file,
726 self.db = sqlite3.connect(self.history_manager.hist_file,
726 **self.history_manager.connection_options
727 **self.history_manager.connection_options
727 )
728 )
728 while True:
729 while True:
729 self.history_manager.save_flag.wait()
730 self.history_manager.save_flag.wait()
730 if self.stop_now:
731 if self.stop_now:
731 return
732 return
732 self.history_manager.save_flag.clear()
733 self.history_manager.save_flag.clear()
733 self.history_manager.writeout_cache(self.db)
734 self.history_manager.writeout_cache(self.db)
734 except Exception as e:
735 except Exception as e:
735 print(("The history saving thread hit an unexpected error (%s)."
736 print(("The history saving thread hit an unexpected error (%s)."
736 "History will not be written to the database.") % repr(e))
737 "History will not be written to the database.") % repr(e))
737
738
738 def stop(self):
739 def stop(self):
739 """This can be called from the main thread to safely stop this thread.
740 """This can be called from the main thread to safely stop this thread.
740
741
741 Note that it does not attempt to write out remaining history before
742 Note that it does not attempt to write out remaining history before
742 exiting. That should be done by calling the HistoryManager's
743 exiting. That should be done by calling the HistoryManager's
743 end_session method."""
744 end_session method."""
744 self.stop_now = True
745 self.stop_now = True
745 self.history_manager.save_flag.set()
746 self.history_manager.save_flag.set()
746 self.join()
747 self.join()
747
748
748
749
749 # To match, e.g. ~5/8-~2/3
750 # To match, e.g. ~5/8-~2/3
750 range_re = re.compile(r"""
751 range_re = re.compile(r"""
751 ((?P<startsess>~?\d+)/)?
752 ((?P<startsess>~?\d+)/)?
752 (?P<start>\d+)?
753 (?P<start>\d+)?
753 ((?P<sep>[\-:])
754 ((?P<sep>[\-:])
754 ((?P<endsess>~?\d+)/)?
755 ((?P<endsess>~?\d+)/)?
755 (?P<end>\d+))?
756 (?P<end>\d+))?
756 $""", re.VERBOSE)
757 $""", re.VERBOSE)
757
758
758
759
759 def extract_hist_ranges(ranges_str):
760 def extract_hist_ranges(ranges_str):
760 """Turn a string of history ranges into 3-tuples of (session, start, stop).
761 """Turn a string of history ranges into 3-tuples of (session, start, stop).
761
762
762 Examples
763 Examples
763 --------
764 --------
764 list(extract_input_ranges("~8/5-~7/4 2"))
765 list(extract_input_ranges("~8/5-~7/4 2"))
765 [(-8, 5, None), (-7, 1, 4), (0, 2, 3)]
766 [(-8, 5, None), (-7, 1, 4), (0, 2, 3)]
766 """
767 """
767 for range_str in ranges_str.split():
768 for range_str in ranges_str.split():
768 rmatch = range_re.match(range_str)
769 rmatch = range_re.match(range_str)
769 if not rmatch:
770 if not rmatch:
770 continue
771 continue
771 start = rmatch.group("start")
772 start = rmatch.group("start")
772 if start:
773 if start:
773 start = int(start)
774 start = int(start)
774 end = rmatch.group("end")
775 end = rmatch.group("end")
775 # If no end specified, get (a, a + 1)
776 # If no end specified, get (a, a + 1)
776 end = int(end) if end else start + 1
777 end = int(end) if end else start + 1
777 else: # start not specified
778 else: # start not specified
778 if not rmatch.group('startsess'): # no startsess
779 if not rmatch.group('startsess'): # no startsess
779 continue
780 continue
780 start = 1
781 start = 1
781 end = None # provide the entire session hist
782 end = None # provide the entire session hist
782
783
783 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
784 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
784 end += 1
785 end += 1
785 startsess = rmatch.group("startsess") or "0"
786 startsess = rmatch.group("startsess") or "0"
786 endsess = rmatch.group("endsess") or startsess
787 endsess = rmatch.group("endsess") or startsess
787 startsess = int(startsess.replace("~","-"))
788 startsess = int(startsess.replace("~","-"))
788 endsess = int(endsess.replace("~","-"))
789 endsess = int(endsess.replace("~","-"))
789 assert endsess >= startsess, "start session must be earlier than end session"
790 assert endsess >= startsess, "start session must be earlier than end session"
790
791
791 if endsess == startsess:
792 if endsess == startsess:
792 yield (startsess, start, end)
793 yield (startsess, start, end)
793 continue
794 continue
794 # Multiple sessions in one range:
795 # Multiple sessions in one range:
795 yield (startsess, start, None)
796 yield (startsess, start, None)
796 for sess in range(startsess+1, endsess):
797 for sess in range(startsess+1, endsess):
797 yield (sess, 1, None)
798 yield (sess, 1, None)
798 yield (endsess, 1, end)
799 yield (endsess, 1, end)
799
800
800
801
801 def _format_lineno(session, line):
802 def _format_lineno(session, line):
802 """Helper function to format line numbers properly."""
803 """Helper function to format line numbers properly."""
803 if session == 0:
804 if session == 0:
804 return str(line)
805 return str(line)
805 return "%s#%s" % (session, line)
806 return "%s#%s" % (session, line)
806
807
807
808
@@ -1,3164 +1,3164 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Main IPython class."""
2 """Main IPython class."""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from __future__ import absolute_import
17 from __future__ import absolute_import
18 from __future__ import print_function
18 from __future__ import print_function
19
19
20 import __future__
20 import __future__
21 import abc
21 import abc
22 import ast
22 import ast
23 import atexit
23 import atexit
24 import functools
24 import functools
25 import os
25 import os
26 import re
26 import re
27 import runpy
27 import runpy
28 import sys
28 import sys
29 import tempfile
29 import tempfile
30 import types
30 import types
31 import subprocess
31 import subprocess
32 from io import open as io_open
32 from io import open as io_open
33
33
34 from IPython.config.configurable import SingletonConfigurable
34 from IPython.config.configurable import SingletonConfigurable
35 from IPython.core import debugger, oinspect
35 from IPython.core import debugger, oinspect
36 from IPython.core import magic
36 from IPython.core import magic
37 from IPython.core import page
37 from IPython.core import page
38 from IPython.core import prefilter
38 from IPython.core import prefilter
39 from IPython.core import shadowns
39 from IPython.core import shadowns
40 from IPython.core import ultratb
40 from IPython.core import ultratb
41 from IPython.core.alias import AliasManager, AliasError
41 from IPython.core.alias import AliasManager, AliasError
42 from IPython.core.autocall import ExitAutocall
42 from IPython.core.autocall import ExitAutocall
43 from IPython.core.builtin_trap import BuiltinTrap
43 from IPython.core.builtin_trap import BuiltinTrap
44 from IPython.core.compilerop import CachingCompiler, check_linecache_ipython
44 from IPython.core.compilerop import CachingCompiler, check_linecache_ipython
45 from IPython.core.display_trap import DisplayTrap
45 from IPython.core.display_trap import DisplayTrap
46 from IPython.core.displayhook import DisplayHook
46 from IPython.core.displayhook import DisplayHook
47 from IPython.core.displaypub import DisplayPublisher
47 from IPython.core.displaypub import DisplayPublisher
48 from IPython.core.error import UsageError
48 from IPython.core.error import UsageError
49 from IPython.core.extensions import ExtensionManager
49 from IPython.core.extensions import ExtensionManager
50 from IPython.core.formatters import DisplayFormatter
50 from IPython.core.formatters import DisplayFormatter
51 from IPython.core.history import HistoryManager
51 from IPython.core.history import HistoryManager
52 from IPython.core.inputsplitter import IPythonInputSplitter, ESC_MAGIC, ESC_MAGIC2
52 from IPython.core.inputsplitter import IPythonInputSplitter, ESC_MAGIC, ESC_MAGIC2
53 from IPython.core.logger import Logger
53 from IPython.core.logger import Logger
54 from IPython.core.macro import Macro
54 from IPython.core.macro import Macro
55 from IPython.core.payload import PayloadManager
55 from IPython.core.payload import PayloadManager
56 from IPython.core.prefilter import PrefilterManager
56 from IPython.core.prefilter import PrefilterManager
57 from IPython.core.profiledir import ProfileDir
57 from IPython.core.profiledir import ProfileDir
58 from IPython.core.prompts import PromptManager
58 from IPython.core.prompts import PromptManager
59 from IPython.lib.latextools import LaTeXTool
59 from IPython.lib.latextools import LaTeXTool
60 from IPython.testing.skipdoctest import skip_doctest
60 from IPython.testing.skipdoctest import skip_doctest
61 from IPython.utils import PyColorize
61 from IPython.utils import PyColorize
62 from IPython.utils import io
62 from IPython.utils import io
63 from IPython.utils import py3compat
63 from IPython.utils import py3compat
64 from IPython.utils import openpy
64 from IPython.utils import openpy
65 from IPython.utils.decorators import undoc
65 from IPython.utils.decorators import undoc
66 from IPython.utils.io import ask_yes_no
66 from IPython.utils.io import ask_yes_no
67 from IPython.utils.ipstruct import Struct
67 from IPython.utils.ipstruct import Struct
68 from IPython.utils.path import get_home_dir, get_ipython_dir, get_py_filename, unquote_filename
68 from IPython.utils.path import get_home_dir, get_ipython_dir, get_py_filename, unquote_filename
69 from IPython.utils.pickleshare import PickleShareDB
69 from IPython.utils.pickleshare import PickleShareDB
70 from IPython.utils.process import system, getoutput
70 from IPython.utils.process import system, getoutput
71 from IPython.utils.py3compat import (builtin_mod, unicode_type, string_types,
71 from IPython.utils.py3compat import (builtin_mod, unicode_type, string_types,
72 with_metaclass, iteritems)
72 with_metaclass, iteritems)
73 from IPython.utils.strdispatch import StrDispatch
73 from IPython.utils.strdispatch import StrDispatch
74 from IPython.utils.syspathcontext import prepended_to_syspath
74 from IPython.utils.syspathcontext import prepended_to_syspath
75 from IPython.utils.text import (format_screen, LSString, SList,
75 from IPython.utils.text import (format_screen, LSString, SList,
76 DollarFormatter)
76 DollarFormatter)
77 from IPython.utils.traitlets import (Integer, CBool, CaselessStrEnum, Enum,
77 from IPython.utils.traitlets import (Integer, CBool, CaselessStrEnum, Enum,
78 List, Unicode, Instance, Type)
78 List, Unicode, Instance, Type)
79 from IPython.utils.warn import warn, error
79 from IPython.utils.warn import warn, error
80 import IPython.core.hooks
80 import IPython.core.hooks
81
81
82 #-----------------------------------------------------------------------------
82 #-----------------------------------------------------------------------------
83 # Globals
83 # Globals
84 #-----------------------------------------------------------------------------
84 #-----------------------------------------------------------------------------
85
85
86 # compiled regexps for autoindent management
86 # compiled regexps for autoindent management
87 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
87 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
88
88
89 #-----------------------------------------------------------------------------
89 #-----------------------------------------------------------------------------
90 # Utilities
90 # Utilities
91 #-----------------------------------------------------------------------------
91 #-----------------------------------------------------------------------------
92
92
93 @undoc
93 @undoc
94 def softspace(file, newvalue):
94 def softspace(file, newvalue):
95 """Copied from code.py, to remove the dependency"""
95 """Copied from code.py, to remove the dependency"""
96
96
97 oldvalue = 0
97 oldvalue = 0
98 try:
98 try:
99 oldvalue = file.softspace
99 oldvalue = file.softspace
100 except AttributeError:
100 except AttributeError:
101 pass
101 pass
102 try:
102 try:
103 file.softspace = newvalue
103 file.softspace = newvalue
104 except (AttributeError, TypeError):
104 except (AttributeError, TypeError):
105 # "attribute-less object" or "read-only attributes"
105 # "attribute-less object" or "read-only attributes"
106 pass
106 pass
107 return oldvalue
107 return oldvalue
108
108
109 @undoc
109 @undoc
110 def no_op(*a, **kw): pass
110 def no_op(*a, **kw): pass
111
111
112 @undoc
112 @undoc
113 class NoOpContext(object):
113 class NoOpContext(object):
114 def __enter__(self): pass
114 def __enter__(self): pass
115 def __exit__(self, type, value, traceback): pass
115 def __exit__(self, type, value, traceback): pass
116 no_op_context = NoOpContext()
116 no_op_context = NoOpContext()
117
117
118 class SpaceInInput(Exception): pass
118 class SpaceInInput(Exception): pass
119
119
120 @undoc
120 @undoc
121 class Bunch: pass
121 class Bunch: pass
122
122
123
123
124 def get_default_colors():
124 def get_default_colors():
125 if sys.platform=='darwin':
125 if sys.platform=='darwin':
126 return "LightBG"
126 return "LightBG"
127 elif os.name=='nt':
127 elif os.name=='nt':
128 return 'Linux'
128 return 'Linux'
129 else:
129 else:
130 return 'Linux'
130 return 'Linux'
131
131
132
132
133 class SeparateUnicode(Unicode):
133 class SeparateUnicode(Unicode):
134 """A Unicode subclass to validate separate_in, separate_out, etc.
134 """A Unicode subclass to validate separate_in, separate_out, etc.
135
135
136 This is a Unicode based trait that converts '0'->'' and '\\n'->'\n'.
136 This is a Unicode based trait that converts '0'->'' and '\\n'->'\n'.
137 """
137 """
138
138
139 def validate(self, obj, value):
139 def validate(self, obj, value):
140 if value == '0': value = ''
140 if value == '0': value = ''
141 value = value.replace('\\n','\n')
141 value = value.replace('\\n','\n')
142 return super(SeparateUnicode, self).validate(obj, value)
142 return super(SeparateUnicode, self).validate(obj, value)
143
143
144
144
145 class ReadlineNoRecord(object):
145 class ReadlineNoRecord(object):
146 """Context manager to execute some code, then reload readline history
146 """Context manager to execute some code, then reload readline history
147 so that interactive input to the code doesn't appear when pressing up."""
147 so that interactive input to the code doesn't appear when pressing up."""
148 def __init__(self, shell):
148 def __init__(self, shell):
149 self.shell = shell
149 self.shell = shell
150 self._nested_level = 0
150 self._nested_level = 0
151
151
152 def __enter__(self):
152 def __enter__(self):
153 if self._nested_level == 0:
153 if self._nested_level == 0:
154 try:
154 try:
155 self.orig_length = self.current_length()
155 self.orig_length = self.current_length()
156 self.readline_tail = self.get_readline_tail()
156 self.readline_tail = self.get_readline_tail()
157 except (AttributeError, IndexError): # Can fail with pyreadline
157 except (AttributeError, IndexError): # Can fail with pyreadline
158 self.orig_length, self.readline_tail = 999999, []
158 self.orig_length, self.readline_tail = 999999, []
159 self._nested_level += 1
159 self._nested_level += 1
160
160
161 def __exit__(self, type, value, traceback):
161 def __exit__(self, type, value, traceback):
162 self._nested_level -= 1
162 self._nested_level -= 1
163 if self._nested_level == 0:
163 if self._nested_level == 0:
164 # Try clipping the end if it's got longer
164 # Try clipping the end if it's got longer
165 try:
165 try:
166 e = self.current_length() - self.orig_length
166 e = self.current_length() - self.orig_length
167 if e > 0:
167 if e > 0:
168 for _ in range(e):
168 for _ in range(e):
169 self.shell.readline.remove_history_item(self.orig_length)
169 self.shell.readline.remove_history_item(self.orig_length)
170
170
171 # If it still doesn't match, just reload readline history.
171 # If it still doesn't match, just reload readline history.
172 if self.current_length() != self.orig_length \
172 if self.current_length() != self.orig_length \
173 or self.get_readline_tail() != self.readline_tail:
173 or self.get_readline_tail() != self.readline_tail:
174 self.shell.refill_readline_hist()
174 self.shell.refill_readline_hist()
175 except (AttributeError, IndexError):
175 except (AttributeError, IndexError):
176 pass
176 pass
177 # Returning False will cause exceptions to propagate
177 # Returning False will cause exceptions to propagate
178 return False
178 return False
179
179
180 def current_length(self):
180 def current_length(self):
181 return self.shell.readline.get_current_history_length()
181 return self.shell.readline.get_current_history_length()
182
182
183 def get_readline_tail(self, n=10):
183 def get_readline_tail(self, n=10):
184 """Get the last n items in readline history."""
184 """Get the last n items in readline history."""
185 end = self.shell.readline.get_current_history_length() + 1
185 end = self.shell.readline.get_current_history_length() + 1
186 start = max(end-n, 1)
186 start = max(end-n, 1)
187 ghi = self.shell.readline.get_history_item
187 ghi = self.shell.readline.get_history_item
188 return [ghi(x) for x in range(start, end)]
188 return [ghi(x) for x in range(start, end)]
189
189
190
190
191 @undoc
191 @undoc
192 class DummyMod(object):
192 class DummyMod(object):
193 """A dummy module used for IPython's interactive module when
193 """A dummy module used for IPython's interactive module when
194 a namespace must be assigned to the module's __dict__."""
194 a namespace must be assigned to the module's __dict__."""
195 pass
195 pass
196
196
197 #-----------------------------------------------------------------------------
197 #-----------------------------------------------------------------------------
198 # Main IPython class
198 # Main IPython class
199 #-----------------------------------------------------------------------------
199 #-----------------------------------------------------------------------------
200
200
201 class InteractiveShell(SingletonConfigurable):
201 class InteractiveShell(SingletonConfigurable):
202 """An enhanced, interactive shell for Python."""
202 """An enhanced, interactive shell for Python."""
203
203
204 _instance = None
204 _instance = None
205
205
206 ast_transformers = List([], config=True, help=
206 ast_transformers = List([], config=True, help=
207 """
207 """
208 A list of ast.NodeTransformer subclass instances, which will be applied
208 A list of ast.NodeTransformer subclass instances, which will be applied
209 to user input before code is run.
209 to user input before code is run.
210 """
210 """
211 )
211 )
212
212
213 autocall = Enum((0,1,2), default_value=0, config=True, help=
213 autocall = Enum((0,1,2), default_value=0, config=True, help=
214 """
214 """
215 Make IPython automatically call any callable object even if you didn't
215 Make IPython automatically call any callable object even if you didn't
216 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
216 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
217 automatically. The value can be '0' to disable the feature, '1' for
217 automatically. The value can be '0' to disable the feature, '1' for
218 'smart' autocall, where it is not applied if there are no more
218 'smart' autocall, where it is not applied if there are no more
219 arguments on the line, and '2' for 'full' autocall, where all callable
219 arguments on the line, and '2' for 'full' autocall, where all callable
220 objects are automatically called (even if no arguments are present).
220 objects are automatically called (even if no arguments are present).
221 """
221 """
222 )
222 )
223 # TODO: remove all autoindent logic and put into frontends.
223 # TODO: remove all autoindent logic and put into frontends.
224 # We can't do this yet because even runlines uses the autoindent.
224 # We can't do this yet because even runlines uses the autoindent.
225 autoindent = CBool(True, config=True, help=
225 autoindent = CBool(True, config=True, help=
226 """
226 """
227 Autoindent IPython code entered interactively.
227 Autoindent IPython code entered interactively.
228 """
228 """
229 )
229 )
230 automagic = CBool(True, config=True, help=
230 automagic = CBool(True, config=True, help=
231 """
231 """
232 Enable magic commands to be called without the leading %.
232 Enable magic commands to be called without the leading %.
233 """
233 """
234 )
234 )
235 cache_size = Integer(1000, config=True, help=
235 cache_size = Integer(1000, config=True, help=
236 """
236 """
237 Set the size of the output cache. The default is 1000, you can
237 Set the size of the output cache. The default is 1000, you can
238 change it permanently in your config file. Setting it to 0 completely
238 change it permanently in your config file. Setting it to 0 completely
239 disables the caching system, and the minimum value accepted is 20 (if
239 disables the caching system, and the minimum value accepted is 20 (if
240 you provide a value less than 20, it is reset to 0 and a warning is
240 you provide a value less than 20, it is reset to 0 and a warning is
241 issued). This limit is defined because otherwise you'll spend more
241 issued). This limit is defined because otherwise you'll spend more
242 time re-flushing a too small cache than working
242 time re-flushing a too small cache than working
243 """
243 """
244 )
244 )
245 color_info = CBool(True, config=True, help=
245 color_info = CBool(True, config=True, help=
246 """
246 """
247 Use colors for displaying information about objects. Because this
247 Use colors for displaying information about objects. Because this
248 information is passed through a pager (like 'less'), and some pagers
248 information is passed through a pager (like 'less'), and some pagers
249 get confused with color codes, this capability can be turned off.
249 get confused with color codes, this capability can be turned off.
250 """
250 """
251 )
251 )
252 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
252 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
253 default_value=get_default_colors(), config=True,
253 default_value=get_default_colors(), config=True,
254 help="Set the color scheme (NoColor, Linux, or LightBG)."
254 help="Set the color scheme (NoColor, Linux, or LightBG)."
255 )
255 )
256 colors_force = CBool(False, help=
256 colors_force = CBool(False, help=
257 """
257 """
258 Force use of ANSI color codes, regardless of OS and readline
258 Force use of ANSI color codes, regardless of OS and readline
259 availability.
259 availability.
260 """
260 """
261 # FIXME: This is essentially a hack to allow ZMQShell to show colors
261 # FIXME: This is essentially a hack to allow ZMQShell to show colors
262 # without readline on Win32. When the ZMQ formatting system is
262 # without readline on Win32. When the ZMQ formatting system is
263 # refactored, this should be removed.
263 # refactored, this should be removed.
264 )
264 )
265 debug = CBool(False, config=True)
265 debug = CBool(False, config=True)
266 deep_reload = CBool(False, config=True, help=
266 deep_reload = CBool(False, config=True, help=
267 """
267 """
268 Enable deep (recursive) reloading by default. IPython can use the
268 Enable deep (recursive) reloading by default. IPython can use the
269 deep_reload module which reloads changes in modules recursively (it
269 deep_reload module which reloads changes in modules recursively (it
270 replaces the reload() function, so you don't need to change anything to
270 replaces the reload() function, so you don't need to change anything to
271 use it). deep_reload() forces a full reload of modules whose code may
271 use it). deep_reload() forces a full reload of modules whose code may
272 have changed, which the default reload() function does not. When
272 have changed, which the default reload() function does not. When
273 deep_reload is off, IPython will use the normal reload(), but
273 deep_reload is off, IPython will use the normal reload(), but
274 deep_reload will still be available as dreload().
274 deep_reload will still be available as dreload().
275 """
275 """
276 )
276 )
277 disable_failing_post_execute = CBool(False, config=True,
277 disable_failing_post_execute = CBool(False, config=True,
278 help="Don't call post-execute functions that have failed in the past."
278 help="Don't call post-execute functions that have failed in the past."
279 )
279 )
280 display_formatter = Instance(DisplayFormatter)
280 display_formatter = Instance(DisplayFormatter)
281 displayhook_class = Type(DisplayHook)
281 displayhook_class = Type(DisplayHook)
282 display_pub_class = Type(DisplayPublisher)
282 display_pub_class = Type(DisplayPublisher)
283 data_pub_class = None
283 data_pub_class = None
284
284
285 exit_now = CBool(False)
285 exit_now = CBool(False)
286 exiter = Instance(ExitAutocall)
286 exiter = Instance(ExitAutocall)
287 def _exiter_default(self):
287 def _exiter_default(self):
288 return ExitAutocall(self)
288 return ExitAutocall(self)
289 # Monotonically increasing execution counter
289 # Monotonically increasing execution counter
290 execution_count = Integer(1)
290 execution_count = Integer(1)
291 filename = Unicode("<ipython console>")
291 filename = Unicode("<ipython console>")
292 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
292 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
293
293
294 # Input splitter, to transform input line by line and detect when a block
294 # Input splitter, to transform input line by line and detect when a block
295 # is ready to be executed.
295 # is ready to be executed.
296 input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
296 input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
297 (), {'line_input_checker': True})
297 (), {'line_input_checker': True})
298
298
299 # This InputSplitter instance is used to transform completed cells before
299 # This InputSplitter instance is used to transform completed cells before
300 # running them. It allows cell magics to contain blank lines.
300 # running them. It allows cell magics to contain blank lines.
301 input_transformer_manager = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
301 input_transformer_manager = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
302 (), {'line_input_checker': False})
302 (), {'line_input_checker': False})
303
303
304 logstart = CBool(False, config=True, help=
304 logstart = CBool(False, config=True, help=
305 """
305 """
306 Start logging to the default log file.
306 Start logging to the default log file.
307 """
307 """
308 )
308 )
309 logfile = Unicode('', config=True, help=
309 logfile = Unicode('', config=True, help=
310 """
310 """
311 The name of the logfile to use.
311 The name of the logfile to use.
312 """
312 """
313 )
313 )
314 logappend = Unicode('', config=True, help=
314 logappend = Unicode('', config=True, help=
315 """
315 """
316 Start logging to the given file in append mode.
316 Start logging to the given file in append mode.
317 """
317 """
318 )
318 )
319 object_info_string_level = Enum((0,1,2), default_value=0,
319 object_info_string_level = Enum((0,1,2), default_value=0,
320 config=True)
320 config=True)
321 pdb = CBool(False, config=True, help=
321 pdb = CBool(False, config=True, help=
322 """
322 """
323 Automatically call the pdb debugger after every exception.
323 Automatically call the pdb debugger after every exception.
324 """
324 """
325 )
325 )
326 multiline_history = CBool(sys.platform != 'win32', config=True,
326 multiline_history = CBool(sys.platform != 'win32', config=True,
327 help="Save multi-line entries as one entry in readline history"
327 help="Save multi-line entries as one entry in readline history"
328 )
328 )
329
329
330 # deprecated prompt traits:
330 # deprecated prompt traits:
331
331
332 prompt_in1 = Unicode('In [\\#]: ', config=True,
332 prompt_in1 = Unicode('In [\\#]: ', config=True,
333 help="Deprecated, use PromptManager.in_template")
333 help="Deprecated, use PromptManager.in_template")
334 prompt_in2 = Unicode(' .\\D.: ', config=True,
334 prompt_in2 = Unicode(' .\\D.: ', config=True,
335 help="Deprecated, use PromptManager.in2_template")
335 help="Deprecated, use PromptManager.in2_template")
336 prompt_out = Unicode('Out[\\#]: ', config=True,
336 prompt_out = Unicode('Out[\\#]: ', config=True,
337 help="Deprecated, use PromptManager.out_template")
337 help="Deprecated, use PromptManager.out_template")
338 prompts_pad_left = CBool(True, config=True,
338 prompts_pad_left = CBool(True, config=True,
339 help="Deprecated, use PromptManager.justify")
339 help="Deprecated, use PromptManager.justify")
340
340
341 def _prompt_trait_changed(self, name, old, new):
341 def _prompt_trait_changed(self, name, old, new):
342 table = {
342 table = {
343 'prompt_in1' : 'in_template',
343 'prompt_in1' : 'in_template',
344 'prompt_in2' : 'in2_template',
344 'prompt_in2' : 'in2_template',
345 'prompt_out' : 'out_template',
345 'prompt_out' : 'out_template',
346 'prompts_pad_left' : 'justify',
346 'prompts_pad_left' : 'justify',
347 }
347 }
348 warn("InteractiveShell.{name} is deprecated, use PromptManager.{newname}".format(
348 warn("InteractiveShell.{name} is deprecated, use PromptManager.{newname}".format(
349 name=name, newname=table[name])
349 name=name, newname=table[name])
350 )
350 )
351 # protect against weird cases where self.config may not exist:
351 # protect against weird cases where self.config may not exist:
352 if self.config is not None:
352 if self.config is not None:
353 # propagate to corresponding PromptManager trait
353 # propagate to corresponding PromptManager trait
354 setattr(self.config.PromptManager, table[name], new)
354 setattr(self.config.PromptManager, table[name], new)
355
355
356 _prompt_in1_changed = _prompt_trait_changed
356 _prompt_in1_changed = _prompt_trait_changed
357 _prompt_in2_changed = _prompt_trait_changed
357 _prompt_in2_changed = _prompt_trait_changed
358 _prompt_out_changed = _prompt_trait_changed
358 _prompt_out_changed = _prompt_trait_changed
359 _prompt_pad_left_changed = _prompt_trait_changed
359 _prompt_pad_left_changed = _prompt_trait_changed
360
360
361 show_rewritten_input = CBool(True, config=True,
361 show_rewritten_input = CBool(True, config=True,
362 help="Show rewritten input, e.g. for autocall."
362 help="Show rewritten input, e.g. for autocall."
363 )
363 )
364
364
365 quiet = CBool(False, config=True)
365 quiet = CBool(False, config=True)
366
366
367 history_length = Integer(10000, config=True)
367 history_length = Integer(10000, config=True)
368
368
369 # The readline stuff will eventually be moved to the terminal subclass
369 # The readline stuff will eventually be moved to the terminal subclass
370 # but for now, we can't do that as readline is welded in everywhere.
370 # but for now, we can't do that as readline is welded in everywhere.
371 readline_use = CBool(True, config=True)
371 readline_use = CBool(True, config=True)
372 readline_remove_delims = Unicode('-/~', config=True)
372 readline_remove_delims = Unicode('-/~', config=True)
373 readline_delims = Unicode() # set by init_readline()
373 readline_delims = Unicode() # set by init_readline()
374 # don't use \M- bindings by default, because they
374 # don't use \M- bindings by default, because they
375 # conflict with 8-bit encodings. See gh-58,gh-88
375 # conflict with 8-bit encodings. See gh-58,gh-88
376 readline_parse_and_bind = List([
376 readline_parse_and_bind = List([
377 'tab: complete',
377 'tab: complete',
378 '"\C-l": clear-screen',
378 '"\C-l": clear-screen',
379 'set show-all-if-ambiguous on',
379 'set show-all-if-ambiguous on',
380 '"\C-o": tab-insert',
380 '"\C-o": tab-insert',
381 '"\C-r": reverse-search-history',
381 '"\C-r": reverse-search-history',
382 '"\C-s": forward-search-history',
382 '"\C-s": forward-search-history',
383 '"\C-p": history-search-backward',
383 '"\C-p": history-search-backward',
384 '"\C-n": history-search-forward',
384 '"\C-n": history-search-forward',
385 '"\e[A": history-search-backward',
385 '"\e[A": history-search-backward',
386 '"\e[B": history-search-forward',
386 '"\e[B": history-search-forward',
387 '"\C-k": kill-line',
387 '"\C-k": kill-line',
388 '"\C-u": unix-line-discard',
388 '"\C-u": unix-line-discard',
389 ], allow_none=False, config=True)
389 ], allow_none=False, config=True)
390
390
391 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none'],
391 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none'],
392 default_value='last_expr', config=True,
392 default_value='last_expr', config=True,
393 help="""
393 help="""
394 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
394 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
395 run interactively (displaying output from expressions).""")
395 run interactively (displaying output from expressions).""")
396
396
397 # TODO: this part of prompt management should be moved to the frontends.
397 # TODO: this part of prompt management should be moved to the frontends.
398 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
398 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
399 separate_in = SeparateUnicode('\n', config=True)
399 separate_in = SeparateUnicode('\n', config=True)
400 separate_out = SeparateUnicode('', config=True)
400 separate_out = SeparateUnicode('', config=True)
401 separate_out2 = SeparateUnicode('', config=True)
401 separate_out2 = SeparateUnicode('', config=True)
402 wildcards_case_sensitive = CBool(True, config=True)
402 wildcards_case_sensitive = CBool(True, config=True)
403 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
403 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
404 default_value='Context', config=True)
404 default_value='Context', config=True)
405
405
406 # Subcomponents of InteractiveShell
406 # Subcomponents of InteractiveShell
407 alias_manager = Instance('IPython.core.alias.AliasManager')
407 alias_manager = Instance('IPython.core.alias.AliasManager')
408 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
408 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
409 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap')
409 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap')
410 display_trap = Instance('IPython.core.display_trap.DisplayTrap')
410 display_trap = Instance('IPython.core.display_trap.DisplayTrap')
411 extension_manager = Instance('IPython.core.extensions.ExtensionManager')
411 extension_manager = Instance('IPython.core.extensions.ExtensionManager')
412 payload_manager = Instance('IPython.core.payload.PayloadManager')
412 payload_manager = Instance('IPython.core.payload.PayloadManager')
413 history_manager = Instance('IPython.core.history.HistoryManager')
413 history_manager = Instance('IPython.core.history.HistoryManager')
414 magics_manager = Instance('IPython.core.magic.MagicsManager')
414 magics_manager = Instance('IPython.core.magic.MagicsManager')
415
415
416 profile_dir = Instance('IPython.core.application.ProfileDir')
416 profile_dir = Instance('IPython.core.application.ProfileDir')
417 @property
417 @property
418 def profile(self):
418 def profile(self):
419 if self.profile_dir is not None:
419 if self.profile_dir is not None:
420 name = os.path.basename(self.profile_dir.location)
420 name = os.path.basename(self.profile_dir.location)
421 return name.replace('profile_','')
421 return name.replace('profile_','')
422
422
423
423
424 # Private interface
424 # Private interface
425 _post_execute = Instance(dict)
425 _post_execute = Instance(dict)
426
426
427 # Tracks any GUI loop loaded for pylab
427 # Tracks any GUI loop loaded for pylab
428 pylab_gui_select = None
428 pylab_gui_select = None
429
429
430 def __init__(self, ipython_dir=None, profile_dir=None,
430 def __init__(self, ipython_dir=None, profile_dir=None,
431 user_module=None, user_ns=None,
431 user_module=None, user_ns=None,
432 custom_exceptions=((), None), **kwargs):
432 custom_exceptions=((), None), **kwargs):
433
433
434 # This is where traits with a config_key argument are updated
434 # This is where traits with a config_key argument are updated
435 # from the values on config.
435 # from the values on config.
436 super(InteractiveShell, self).__init__(**kwargs)
436 super(InteractiveShell, self).__init__(**kwargs)
437 self.configurables = [self]
437 self.configurables = [self]
438
438
439 # These are relatively independent and stateless
439 # These are relatively independent and stateless
440 self.init_ipython_dir(ipython_dir)
440 self.init_ipython_dir(ipython_dir)
441 self.init_profile_dir(profile_dir)
441 self.init_profile_dir(profile_dir)
442 self.init_instance_attrs()
442 self.init_instance_attrs()
443 self.init_environment()
443 self.init_environment()
444
444
445 # Check if we're in a virtualenv, and set up sys.path.
445 # Check if we're in a virtualenv, and set up sys.path.
446 self.init_virtualenv()
446 self.init_virtualenv()
447
447
448 # Create namespaces (user_ns, user_global_ns, etc.)
448 # Create namespaces (user_ns, user_global_ns, etc.)
449 self.init_create_namespaces(user_module, user_ns)
449 self.init_create_namespaces(user_module, user_ns)
450 # This has to be done after init_create_namespaces because it uses
450 # This has to be done after init_create_namespaces because it uses
451 # something in self.user_ns, but before init_sys_modules, which
451 # something in self.user_ns, but before init_sys_modules, which
452 # is the first thing to modify sys.
452 # is the first thing to modify sys.
453 # TODO: When we override sys.stdout and sys.stderr before this class
453 # TODO: When we override sys.stdout and sys.stderr before this class
454 # is created, we are saving the overridden ones here. Not sure if this
454 # is created, we are saving the overridden ones here. Not sure if this
455 # is what we want to do.
455 # is what we want to do.
456 self.save_sys_module_state()
456 self.save_sys_module_state()
457 self.init_sys_modules()
457 self.init_sys_modules()
458
458
459 # While we're trying to have each part of the code directly access what
459 # While we're trying to have each part of the code directly access what
460 # it needs without keeping redundant references to objects, we have too
460 # it needs without keeping redundant references to objects, we have too
461 # much legacy code that expects ip.db to exist.
461 # much legacy code that expects ip.db to exist.
462 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
462 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
463
463
464 self.init_history()
464 self.init_history()
465 self.init_encoding()
465 self.init_encoding()
466 self.init_prefilter()
466 self.init_prefilter()
467
467
468 self.init_syntax_highlighting()
468 self.init_syntax_highlighting()
469 self.init_hooks()
469 self.init_hooks()
470 self.init_pushd_popd_magic()
470 self.init_pushd_popd_magic()
471 # self.init_traceback_handlers use to be here, but we moved it below
471 # self.init_traceback_handlers use to be here, but we moved it below
472 # because it and init_io have to come after init_readline.
472 # because it and init_io have to come after init_readline.
473 self.init_user_ns()
473 self.init_user_ns()
474 self.init_logger()
474 self.init_logger()
475 self.init_builtins()
475 self.init_builtins()
476
476
477 # The following was in post_config_initialization
477 # The following was in post_config_initialization
478 self.init_inspector()
478 self.init_inspector()
479 # init_readline() must come before init_io(), because init_io uses
479 # init_readline() must come before init_io(), because init_io uses
480 # readline related things.
480 # readline related things.
481 self.init_readline()
481 self.init_readline()
482 # We save this here in case user code replaces raw_input, but it needs
482 # We save this here in case user code replaces raw_input, but it needs
483 # to be after init_readline(), because PyPy's readline works by replacing
483 # to be after init_readline(), because PyPy's readline works by replacing
484 # raw_input.
484 # raw_input.
485 if py3compat.PY3:
485 if py3compat.PY3:
486 self.raw_input_original = input
486 self.raw_input_original = input
487 else:
487 else:
488 self.raw_input_original = raw_input
488 self.raw_input_original = raw_input
489 # init_completer must come after init_readline, because it needs to
489 # init_completer must come after init_readline, because it needs to
490 # know whether readline is present or not system-wide to configure the
490 # know whether readline is present or not system-wide to configure the
491 # completers, since the completion machinery can now operate
491 # completers, since the completion machinery can now operate
492 # independently of readline (e.g. over the network)
492 # independently of readline (e.g. over the network)
493 self.init_completer()
493 self.init_completer()
494 # TODO: init_io() needs to happen before init_traceback handlers
494 # TODO: init_io() needs to happen before init_traceback handlers
495 # because the traceback handlers hardcode the stdout/stderr streams.
495 # because the traceback handlers hardcode the stdout/stderr streams.
496 # This logic in in debugger.Pdb and should eventually be changed.
496 # This logic in in debugger.Pdb and should eventually be changed.
497 self.init_io()
497 self.init_io()
498 self.init_traceback_handlers(custom_exceptions)
498 self.init_traceback_handlers(custom_exceptions)
499 self.init_prompts()
499 self.init_prompts()
500 self.init_display_formatter()
500 self.init_display_formatter()
501 self.init_display_pub()
501 self.init_display_pub()
502 self.init_data_pub()
502 self.init_data_pub()
503 self.init_displayhook()
503 self.init_displayhook()
504 self.init_latextool()
504 self.init_latextool()
505 self.init_magics()
505 self.init_magics()
506 self.init_alias()
506 self.init_alias()
507 self.init_logstart()
507 self.init_logstart()
508 self.init_pdb()
508 self.init_pdb()
509 self.init_extension_manager()
509 self.init_extension_manager()
510 self.init_payload()
510 self.init_payload()
511 self.init_comms()
511 self.init_comms()
512 self.hooks.late_startup_hook()
512 self.hooks.late_startup_hook()
513 atexit.register(self.atexit_operations)
513 atexit.register(self.atexit_operations)
514
514
515 def get_ipython(self):
515 def get_ipython(self):
516 """Return the currently running IPython instance."""
516 """Return the currently running IPython instance."""
517 return self
517 return self
518
518
519 #-------------------------------------------------------------------------
519 #-------------------------------------------------------------------------
520 # Trait changed handlers
520 # Trait changed handlers
521 #-------------------------------------------------------------------------
521 #-------------------------------------------------------------------------
522
522
523 def _ipython_dir_changed(self, name, new):
523 def _ipython_dir_changed(self, name, new):
524 if not os.path.isdir(new):
524 if not os.path.isdir(new):
525 os.makedirs(new, mode = 0o777)
525 os.makedirs(new, mode = 0o777)
526
526
527 def set_autoindent(self,value=None):
527 def set_autoindent(self,value=None):
528 """Set the autoindent flag, checking for readline support.
528 """Set the autoindent flag, checking for readline support.
529
529
530 If called with no arguments, it acts as a toggle."""
530 If called with no arguments, it acts as a toggle."""
531
531
532 if value != 0 and not self.has_readline:
532 if value != 0 and not self.has_readline:
533 if os.name == 'posix':
533 if os.name == 'posix':
534 warn("The auto-indent feature requires the readline library")
534 warn("The auto-indent feature requires the readline library")
535 self.autoindent = 0
535 self.autoindent = 0
536 return
536 return
537 if value is None:
537 if value is None:
538 self.autoindent = not self.autoindent
538 self.autoindent = not self.autoindent
539 else:
539 else:
540 self.autoindent = value
540 self.autoindent = value
541
541
542 #-------------------------------------------------------------------------
542 #-------------------------------------------------------------------------
543 # init_* methods called by __init__
543 # init_* methods called by __init__
544 #-------------------------------------------------------------------------
544 #-------------------------------------------------------------------------
545
545
546 def init_ipython_dir(self, ipython_dir):
546 def init_ipython_dir(self, ipython_dir):
547 if ipython_dir is not None:
547 if ipython_dir is not None:
548 self.ipython_dir = ipython_dir
548 self.ipython_dir = ipython_dir
549 return
549 return
550
550
551 self.ipython_dir = get_ipython_dir()
551 self.ipython_dir = get_ipython_dir()
552
552
553 def init_profile_dir(self, profile_dir):
553 def init_profile_dir(self, profile_dir):
554 if profile_dir is not None:
554 if profile_dir is not None:
555 self.profile_dir = profile_dir
555 self.profile_dir = profile_dir
556 return
556 return
557 self.profile_dir =\
557 self.profile_dir =\
558 ProfileDir.create_profile_dir_by_name(self.ipython_dir, 'default')
558 ProfileDir.create_profile_dir_by_name(self.ipython_dir, 'default')
559
559
560 def init_instance_attrs(self):
560 def init_instance_attrs(self):
561 self.more = False
561 self.more = False
562
562
563 # command compiler
563 # command compiler
564 self.compile = CachingCompiler()
564 self.compile = CachingCompiler()
565
565
566 # Make an empty namespace, which extension writers can rely on both
566 # Make an empty namespace, which extension writers can rely on both
567 # existing and NEVER being used by ipython itself. This gives them a
567 # existing and NEVER being used by ipython itself. This gives them a
568 # convenient location for storing additional information and state
568 # convenient location for storing additional information and state
569 # their extensions may require, without fear of collisions with other
569 # their extensions may require, without fear of collisions with other
570 # ipython names that may develop later.
570 # ipython names that may develop later.
571 self.meta = Struct()
571 self.meta = Struct()
572
572
573 # Temporary files used for various purposes. Deleted at exit.
573 # Temporary files used for various purposes. Deleted at exit.
574 self.tempfiles = []
574 self.tempfiles = []
575
575
576 # Keep track of readline usage (later set by init_readline)
576 # Keep track of readline usage (later set by init_readline)
577 self.has_readline = False
577 self.has_readline = False
578
578
579 # keep track of where we started running (mainly for crash post-mortem)
579 # keep track of where we started running (mainly for crash post-mortem)
580 # This is not being used anywhere currently.
580 # This is not being used anywhere currently.
581 self.starting_dir = os.getcwdu()
581 self.starting_dir = py3compat.getcwd()
582
582
583 # Indentation management
583 # Indentation management
584 self.indent_current_nsp = 0
584 self.indent_current_nsp = 0
585
585
586 # Dict to track post-execution functions that have been registered
586 # Dict to track post-execution functions that have been registered
587 self._post_execute = {}
587 self._post_execute = {}
588
588
589 def init_environment(self):
589 def init_environment(self):
590 """Any changes we need to make to the user's environment."""
590 """Any changes we need to make to the user's environment."""
591 pass
591 pass
592
592
593 def init_encoding(self):
593 def init_encoding(self):
594 # Get system encoding at startup time. Certain terminals (like Emacs
594 # Get system encoding at startup time. Certain terminals (like Emacs
595 # under Win32 have it set to None, and we need to have a known valid
595 # under Win32 have it set to None, and we need to have a known valid
596 # encoding to use in the raw_input() method
596 # encoding to use in the raw_input() method
597 try:
597 try:
598 self.stdin_encoding = sys.stdin.encoding or 'ascii'
598 self.stdin_encoding = sys.stdin.encoding or 'ascii'
599 except AttributeError:
599 except AttributeError:
600 self.stdin_encoding = 'ascii'
600 self.stdin_encoding = 'ascii'
601
601
602 def init_syntax_highlighting(self):
602 def init_syntax_highlighting(self):
603 # Python source parser/formatter for syntax highlighting
603 # Python source parser/formatter for syntax highlighting
604 pyformat = PyColorize.Parser().format
604 pyformat = PyColorize.Parser().format
605 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
605 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
606
606
607 def init_pushd_popd_magic(self):
607 def init_pushd_popd_magic(self):
608 # for pushd/popd management
608 # for pushd/popd management
609 self.home_dir = get_home_dir()
609 self.home_dir = get_home_dir()
610
610
611 self.dir_stack = []
611 self.dir_stack = []
612
612
613 def init_logger(self):
613 def init_logger(self):
614 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
614 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
615 logmode='rotate')
615 logmode='rotate')
616
616
617 def init_logstart(self):
617 def init_logstart(self):
618 """Initialize logging in case it was requested at the command line.
618 """Initialize logging in case it was requested at the command line.
619 """
619 """
620 if self.logappend:
620 if self.logappend:
621 self.magic('logstart %s append' % self.logappend)
621 self.magic('logstart %s append' % self.logappend)
622 elif self.logfile:
622 elif self.logfile:
623 self.magic('logstart %s' % self.logfile)
623 self.magic('logstart %s' % self.logfile)
624 elif self.logstart:
624 elif self.logstart:
625 self.magic('logstart')
625 self.magic('logstart')
626
626
627 def init_builtins(self):
627 def init_builtins(self):
628 # A single, static flag that we set to True. Its presence indicates
628 # A single, static flag that we set to True. Its presence indicates
629 # that an IPython shell has been created, and we make no attempts at
629 # that an IPython shell has been created, and we make no attempts at
630 # removing on exit or representing the existence of more than one
630 # removing on exit or representing the existence of more than one
631 # IPython at a time.
631 # IPython at a time.
632 builtin_mod.__dict__['__IPYTHON__'] = True
632 builtin_mod.__dict__['__IPYTHON__'] = True
633
633
634 # In 0.11 we introduced '__IPYTHON__active' as an integer we'd try to
634 # In 0.11 we introduced '__IPYTHON__active' as an integer we'd try to
635 # manage on enter/exit, but with all our shells it's virtually
635 # manage on enter/exit, but with all our shells it's virtually
636 # impossible to get all the cases right. We're leaving the name in for
636 # impossible to get all the cases right. We're leaving the name in for
637 # those who adapted their codes to check for this flag, but will
637 # those who adapted their codes to check for this flag, but will
638 # eventually remove it after a few more releases.
638 # eventually remove it after a few more releases.
639 builtin_mod.__dict__['__IPYTHON__active'] = \
639 builtin_mod.__dict__['__IPYTHON__active'] = \
640 'Deprecated, check for __IPYTHON__'
640 'Deprecated, check for __IPYTHON__'
641
641
642 self.builtin_trap = BuiltinTrap(shell=self)
642 self.builtin_trap = BuiltinTrap(shell=self)
643
643
644 def init_inspector(self):
644 def init_inspector(self):
645 # Object inspector
645 # Object inspector
646 self.inspector = oinspect.Inspector(oinspect.InspectColors,
646 self.inspector = oinspect.Inspector(oinspect.InspectColors,
647 PyColorize.ANSICodeColors,
647 PyColorize.ANSICodeColors,
648 'NoColor',
648 'NoColor',
649 self.object_info_string_level)
649 self.object_info_string_level)
650
650
651 def init_io(self):
651 def init_io(self):
652 # This will just use sys.stdout and sys.stderr. If you want to
652 # This will just use sys.stdout and sys.stderr. If you want to
653 # override sys.stdout and sys.stderr themselves, you need to do that
653 # override sys.stdout and sys.stderr themselves, you need to do that
654 # *before* instantiating this class, because io holds onto
654 # *before* instantiating this class, because io holds onto
655 # references to the underlying streams.
655 # references to the underlying streams.
656 if (sys.platform == 'win32' or sys.platform == 'cli') and self.has_readline:
656 if (sys.platform == 'win32' or sys.platform == 'cli') and self.has_readline:
657 io.stdout = io.stderr = io.IOStream(self.readline._outputfile)
657 io.stdout = io.stderr = io.IOStream(self.readline._outputfile)
658 else:
658 else:
659 io.stdout = io.IOStream(sys.stdout)
659 io.stdout = io.IOStream(sys.stdout)
660 io.stderr = io.IOStream(sys.stderr)
660 io.stderr = io.IOStream(sys.stderr)
661
661
662 def init_prompts(self):
662 def init_prompts(self):
663 self.prompt_manager = PromptManager(shell=self, parent=self)
663 self.prompt_manager = PromptManager(shell=self, parent=self)
664 self.configurables.append(self.prompt_manager)
664 self.configurables.append(self.prompt_manager)
665 # Set system prompts, so that scripts can decide if they are running
665 # Set system prompts, so that scripts can decide if they are running
666 # interactively.
666 # interactively.
667 sys.ps1 = 'In : '
667 sys.ps1 = 'In : '
668 sys.ps2 = '...: '
668 sys.ps2 = '...: '
669 sys.ps3 = 'Out: '
669 sys.ps3 = 'Out: '
670
670
671 def init_display_formatter(self):
671 def init_display_formatter(self):
672 self.display_formatter = DisplayFormatter(parent=self)
672 self.display_formatter = DisplayFormatter(parent=self)
673 self.configurables.append(self.display_formatter)
673 self.configurables.append(self.display_formatter)
674
674
675 def init_display_pub(self):
675 def init_display_pub(self):
676 self.display_pub = self.display_pub_class(parent=self)
676 self.display_pub = self.display_pub_class(parent=self)
677 self.configurables.append(self.display_pub)
677 self.configurables.append(self.display_pub)
678
678
679 def init_data_pub(self):
679 def init_data_pub(self):
680 if not self.data_pub_class:
680 if not self.data_pub_class:
681 self.data_pub = None
681 self.data_pub = None
682 return
682 return
683 self.data_pub = self.data_pub_class(parent=self)
683 self.data_pub = self.data_pub_class(parent=self)
684 self.configurables.append(self.data_pub)
684 self.configurables.append(self.data_pub)
685
685
686 def init_displayhook(self):
686 def init_displayhook(self):
687 # Initialize displayhook, set in/out prompts and printing system
687 # Initialize displayhook, set in/out prompts and printing system
688 self.displayhook = self.displayhook_class(
688 self.displayhook = self.displayhook_class(
689 parent=self,
689 parent=self,
690 shell=self,
690 shell=self,
691 cache_size=self.cache_size,
691 cache_size=self.cache_size,
692 )
692 )
693 self.configurables.append(self.displayhook)
693 self.configurables.append(self.displayhook)
694 # This is a context manager that installs/revmoes the displayhook at
694 # This is a context manager that installs/revmoes the displayhook at
695 # the appropriate time.
695 # the appropriate time.
696 self.display_trap = DisplayTrap(hook=self.displayhook)
696 self.display_trap = DisplayTrap(hook=self.displayhook)
697
697
698 def init_latextool(self):
698 def init_latextool(self):
699 """Configure LaTeXTool."""
699 """Configure LaTeXTool."""
700 cfg = LaTeXTool.instance(parent=self)
700 cfg = LaTeXTool.instance(parent=self)
701 if cfg not in self.configurables:
701 if cfg not in self.configurables:
702 self.configurables.append(cfg)
702 self.configurables.append(cfg)
703
703
704 def init_virtualenv(self):
704 def init_virtualenv(self):
705 """Add a virtualenv to sys.path so the user can import modules from it.
705 """Add a virtualenv to sys.path so the user can import modules from it.
706 This isn't perfect: it doesn't use the Python interpreter with which the
706 This isn't perfect: it doesn't use the Python interpreter with which the
707 virtualenv was built, and it ignores the --no-site-packages option. A
707 virtualenv was built, and it ignores the --no-site-packages option. A
708 warning will appear suggesting the user installs IPython in the
708 warning will appear suggesting the user installs IPython in the
709 virtualenv, but for many cases, it probably works well enough.
709 virtualenv, but for many cases, it probably works well enough.
710
710
711 Adapted from code snippets online.
711 Adapted from code snippets online.
712
712
713 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
713 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
714 """
714 """
715 if 'VIRTUAL_ENV' not in os.environ:
715 if 'VIRTUAL_ENV' not in os.environ:
716 # Not in a virtualenv
716 # Not in a virtualenv
717 return
717 return
718
718
719 if sys.executable.startswith(os.environ['VIRTUAL_ENV']):
719 if sys.executable.startswith(os.environ['VIRTUAL_ENV']):
720 # Running properly in the virtualenv, don't need to do anything
720 # Running properly in the virtualenv, don't need to do anything
721 return
721 return
722
722
723 warn("Attempting to work in a virtualenv. If you encounter problems, please "
723 warn("Attempting to work in a virtualenv. If you encounter problems, please "
724 "install IPython inside the virtualenv.")
724 "install IPython inside the virtualenv.")
725 if sys.platform == "win32":
725 if sys.platform == "win32":
726 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'Lib', 'site-packages')
726 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'Lib', 'site-packages')
727 else:
727 else:
728 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'lib',
728 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'lib',
729 'python%d.%d' % sys.version_info[:2], 'site-packages')
729 'python%d.%d' % sys.version_info[:2], 'site-packages')
730
730
731 import site
731 import site
732 sys.path.insert(0, virtual_env)
732 sys.path.insert(0, virtual_env)
733 site.addsitedir(virtual_env)
733 site.addsitedir(virtual_env)
734
734
735 #-------------------------------------------------------------------------
735 #-------------------------------------------------------------------------
736 # Things related to injections into the sys module
736 # Things related to injections into the sys module
737 #-------------------------------------------------------------------------
737 #-------------------------------------------------------------------------
738
738
739 def save_sys_module_state(self):
739 def save_sys_module_state(self):
740 """Save the state of hooks in the sys module.
740 """Save the state of hooks in the sys module.
741
741
742 This has to be called after self.user_module is created.
742 This has to be called after self.user_module is created.
743 """
743 """
744 self._orig_sys_module_state = {}
744 self._orig_sys_module_state = {}
745 self._orig_sys_module_state['stdin'] = sys.stdin
745 self._orig_sys_module_state['stdin'] = sys.stdin
746 self._orig_sys_module_state['stdout'] = sys.stdout
746 self._orig_sys_module_state['stdout'] = sys.stdout
747 self._orig_sys_module_state['stderr'] = sys.stderr
747 self._orig_sys_module_state['stderr'] = sys.stderr
748 self._orig_sys_module_state['excepthook'] = sys.excepthook
748 self._orig_sys_module_state['excepthook'] = sys.excepthook
749 self._orig_sys_modules_main_name = self.user_module.__name__
749 self._orig_sys_modules_main_name = self.user_module.__name__
750 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
750 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
751
751
752 def restore_sys_module_state(self):
752 def restore_sys_module_state(self):
753 """Restore the state of the sys module."""
753 """Restore the state of the sys module."""
754 try:
754 try:
755 for k, v in iteritems(self._orig_sys_module_state):
755 for k, v in iteritems(self._orig_sys_module_state):
756 setattr(sys, k, v)
756 setattr(sys, k, v)
757 except AttributeError:
757 except AttributeError:
758 pass
758 pass
759 # Reset what what done in self.init_sys_modules
759 # Reset what what done in self.init_sys_modules
760 if self._orig_sys_modules_main_mod is not None:
760 if self._orig_sys_modules_main_mod is not None:
761 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
761 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
762
762
763 #-------------------------------------------------------------------------
763 #-------------------------------------------------------------------------
764 # Things related to hooks
764 # Things related to hooks
765 #-------------------------------------------------------------------------
765 #-------------------------------------------------------------------------
766
766
767 def init_hooks(self):
767 def init_hooks(self):
768 # hooks holds pointers used for user-side customizations
768 # hooks holds pointers used for user-side customizations
769 self.hooks = Struct()
769 self.hooks = Struct()
770
770
771 self.strdispatchers = {}
771 self.strdispatchers = {}
772
772
773 # Set all default hooks, defined in the IPython.hooks module.
773 # Set all default hooks, defined in the IPython.hooks module.
774 hooks = IPython.core.hooks
774 hooks = IPython.core.hooks
775 for hook_name in hooks.__all__:
775 for hook_name in hooks.__all__:
776 # default hooks have priority 100, i.e. low; user hooks should have
776 # default hooks have priority 100, i.e. low; user hooks should have
777 # 0-100 priority
777 # 0-100 priority
778 self.set_hook(hook_name,getattr(hooks,hook_name), 100)
778 self.set_hook(hook_name,getattr(hooks,hook_name), 100)
779
779
780 def set_hook(self,name,hook, priority = 50, str_key = None, re_key = None):
780 def set_hook(self,name,hook, priority = 50, str_key = None, re_key = None):
781 """set_hook(name,hook) -> sets an internal IPython hook.
781 """set_hook(name,hook) -> sets an internal IPython hook.
782
782
783 IPython exposes some of its internal API as user-modifiable hooks. By
783 IPython exposes some of its internal API as user-modifiable hooks. By
784 adding your function to one of these hooks, you can modify IPython's
784 adding your function to one of these hooks, you can modify IPython's
785 behavior to call at runtime your own routines."""
785 behavior to call at runtime your own routines."""
786
786
787 # At some point in the future, this should validate the hook before it
787 # At some point in the future, this should validate the hook before it
788 # accepts it. Probably at least check that the hook takes the number
788 # accepts it. Probably at least check that the hook takes the number
789 # of args it's supposed to.
789 # of args it's supposed to.
790
790
791 f = types.MethodType(hook,self)
791 f = types.MethodType(hook,self)
792
792
793 # check if the hook is for strdispatcher first
793 # check if the hook is for strdispatcher first
794 if str_key is not None:
794 if str_key is not None:
795 sdp = self.strdispatchers.get(name, StrDispatch())
795 sdp = self.strdispatchers.get(name, StrDispatch())
796 sdp.add_s(str_key, f, priority )
796 sdp.add_s(str_key, f, priority )
797 self.strdispatchers[name] = sdp
797 self.strdispatchers[name] = sdp
798 return
798 return
799 if re_key is not None:
799 if re_key is not None:
800 sdp = self.strdispatchers.get(name, StrDispatch())
800 sdp = self.strdispatchers.get(name, StrDispatch())
801 sdp.add_re(re.compile(re_key), f, priority )
801 sdp.add_re(re.compile(re_key), f, priority )
802 self.strdispatchers[name] = sdp
802 self.strdispatchers[name] = sdp
803 return
803 return
804
804
805 dp = getattr(self.hooks, name, None)
805 dp = getattr(self.hooks, name, None)
806 if name not in IPython.core.hooks.__all__:
806 if name not in IPython.core.hooks.__all__:
807 print("Warning! Hook '%s' is not one of %s" % \
807 print("Warning! Hook '%s' is not one of %s" % \
808 (name, IPython.core.hooks.__all__ ))
808 (name, IPython.core.hooks.__all__ ))
809 if not dp:
809 if not dp:
810 dp = IPython.core.hooks.CommandChainDispatcher()
810 dp = IPython.core.hooks.CommandChainDispatcher()
811
811
812 try:
812 try:
813 dp.add(f,priority)
813 dp.add(f,priority)
814 except AttributeError:
814 except AttributeError:
815 # it was not commandchain, plain old func - replace
815 # it was not commandchain, plain old func - replace
816 dp = f
816 dp = f
817
817
818 setattr(self.hooks,name, dp)
818 setattr(self.hooks,name, dp)
819
819
820 def register_post_execute(self, func):
820 def register_post_execute(self, func):
821 """Register a function for calling after code execution.
821 """Register a function for calling after code execution.
822 """
822 """
823 if not callable(func):
823 if not callable(func):
824 raise ValueError('argument %s must be callable' % func)
824 raise ValueError('argument %s must be callable' % func)
825 self._post_execute[func] = True
825 self._post_execute[func] = True
826
826
827 #-------------------------------------------------------------------------
827 #-------------------------------------------------------------------------
828 # Things related to the "main" module
828 # Things related to the "main" module
829 #-------------------------------------------------------------------------
829 #-------------------------------------------------------------------------
830
830
831 def new_main_mod(self, filename, modname):
831 def new_main_mod(self, filename, modname):
832 """Return a new 'main' module object for user code execution.
832 """Return a new 'main' module object for user code execution.
833
833
834 ``filename`` should be the path of the script which will be run in the
834 ``filename`` should be the path of the script which will be run in the
835 module. Requests with the same filename will get the same module, with
835 module. Requests with the same filename will get the same module, with
836 its namespace cleared.
836 its namespace cleared.
837
837
838 ``modname`` should be the module name - normally either '__main__' or
838 ``modname`` should be the module name - normally either '__main__' or
839 the basename of the file without the extension.
839 the basename of the file without the extension.
840
840
841 When scripts are executed via %run, we must keep a reference to their
841 When scripts are executed via %run, we must keep a reference to their
842 __main__ module around so that Python doesn't
842 __main__ module around so that Python doesn't
843 clear it, rendering references to module globals useless.
843 clear it, rendering references to module globals useless.
844
844
845 This method keeps said reference in a private dict, keyed by the
845 This method keeps said reference in a private dict, keyed by the
846 absolute path of the script. This way, for multiple executions of the
846 absolute path of the script. This way, for multiple executions of the
847 same script we only keep one copy of the namespace (the last one),
847 same script we only keep one copy of the namespace (the last one),
848 thus preventing memory leaks from old references while allowing the
848 thus preventing memory leaks from old references while allowing the
849 objects from the last execution to be accessible.
849 objects from the last execution to be accessible.
850 """
850 """
851 filename = os.path.abspath(filename)
851 filename = os.path.abspath(filename)
852 try:
852 try:
853 main_mod = self._main_mod_cache[filename]
853 main_mod = self._main_mod_cache[filename]
854 except KeyError:
854 except KeyError:
855 main_mod = self._main_mod_cache[filename] = types.ModuleType(modname,
855 main_mod = self._main_mod_cache[filename] = types.ModuleType(modname,
856 doc="Module created for script run in IPython")
856 doc="Module created for script run in IPython")
857 else:
857 else:
858 main_mod.__dict__.clear()
858 main_mod.__dict__.clear()
859 main_mod.__name__ = modname
859 main_mod.__name__ = modname
860
860
861 main_mod.__file__ = filename
861 main_mod.__file__ = filename
862 # It seems pydoc (and perhaps others) needs any module instance to
862 # It seems pydoc (and perhaps others) needs any module instance to
863 # implement a __nonzero__ method
863 # implement a __nonzero__ method
864 main_mod.__nonzero__ = lambda : True
864 main_mod.__nonzero__ = lambda : True
865
865
866 return main_mod
866 return main_mod
867
867
868 def clear_main_mod_cache(self):
868 def clear_main_mod_cache(self):
869 """Clear the cache of main modules.
869 """Clear the cache of main modules.
870
870
871 Mainly for use by utilities like %reset.
871 Mainly for use by utilities like %reset.
872
872
873 Examples
873 Examples
874 --------
874 --------
875
875
876 In [15]: import IPython
876 In [15]: import IPython
877
877
878 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
878 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
879
879
880 In [17]: len(_ip._main_mod_cache) > 0
880 In [17]: len(_ip._main_mod_cache) > 0
881 Out[17]: True
881 Out[17]: True
882
882
883 In [18]: _ip.clear_main_mod_cache()
883 In [18]: _ip.clear_main_mod_cache()
884
884
885 In [19]: len(_ip._main_mod_cache) == 0
885 In [19]: len(_ip._main_mod_cache) == 0
886 Out[19]: True
886 Out[19]: True
887 """
887 """
888 self._main_mod_cache.clear()
888 self._main_mod_cache.clear()
889
889
890 #-------------------------------------------------------------------------
890 #-------------------------------------------------------------------------
891 # Things related to debugging
891 # Things related to debugging
892 #-------------------------------------------------------------------------
892 #-------------------------------------------------------------------------
893
893
894 def init_pdb(self):
894 def init_pdb(self):
895 # Set calling of pdb on exceptions
895 # Set calling of pdb on exceptions
896 # self.call_pdb is a property
896 # self.call_pdb is a property
897 self.call_pdb = self.pdb
897 self.call_pdb = self.pdb
898
898
899 def _get_call_pdb(self):
899 def _get_call_pdb(self):
900 return self._call_pdb
900 return self._call_pdb
901
901
902 def _set_call_pdb(self,val):
902 def _set_call_pdb(self,val):
903
903
904 if val not in (0,1,False,True):
904 if val not in (0,1,False,True):
905 raise ValueError('new call_pdb value must be boolean')
905 raise ValueError('new call_pdb value must be boolean')
906
906
907 # store value in instance
907 # store value in instance
908 self._call_pdb = val
908 self._call_pdb = val
909
909
910 # notify the actual exception handlers
910 # notify the actual exception handlers
911 self.InteractiveTB.call_pdb = val
911 self.InteractiveTB.call_pdb = val
912
912
913 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
913 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
914 'Control auto-activation of pdb at exceptions')
914 'Control auto-activation of pdb at exceptions')
915
915
916 def debugger(self,force=False):
916 def debugger(self,force=False):
917 """Call the pydb/pdb debugger.
917 """Call the pydb/pdb debugger.
918
918
919 Keywords:
919 Keywords:
920
920
921 - force(False): by default, this routine checks the instance call_pdb
921 - force(False): by default, this routine checks the instance call_pdb
922 flag and does not actually invoke the debugger if the flag is false.
922 flag and does not actually invoke the debugger if the flag is false.
923 The 'force' option forces the debugger to activate even if the flag
923 The 'force' option forces the debugger to activate even if the flag
924 is false.
924 is false.
925 """
925 """
926
926
927 if not (force or self.call_pdb):
927 if not (force or self.call_pdb):
928 return
928 return
929
929
930 if not hasattr(sys,'last_traceback'):
930 if not hasattr(sys,'last_traceback'):
931 error('No traceback has been produced, nothing to debug.')
931 error('No traceback has been produced, nothing to debug.')
932 return
932 return
933
933
934 # use pydb if available
934 # use pydb if available
935 if debugger.has_pydb:
935 if debugger.has_pydb:
936 from pydb import pm
936 from pydb import pm
937 else:
937 else:
938 # fallback to our internal debugger
938 # fallback to our internal debugger
939 pm = lambda : self.InteractiveTB.debugger(force=True)
939 pm = lambda : self.InteractiveTB.debugger(force=True)
940
940
941 with self.readline_no_record:
941 with self.readline_no_record:
942 pm()
942 pm()
943
943
944 #-------------------------------------------------------------------------
944 #-------------------------------------------------------------------------
945 # Things related to IPython's various namespaces
945 # Things related to IPython's various namespaces
946 #-------------------------------------------------------------------------
946 #-------------------------------------------------------------------------
947 default_user_namespaces = True
947 default_user_namespaces = True
948
948
949 def init_create_namespaces(self, user_module=None, user_ns=None):
949 def init_create_namespaces(self, user_module=None, user_ns=None):
950 # Create the namespace where the user will operate. user_ns is
950 # Create the namespace where the user will operate. user_ns is
951 # normally the only one used, and it is passed to the exec calls as
951 # normally the only one used, and it is passed to the exec calls as
952 # the locals argument. But we do carry a user_global_ns namespace
952 # the locals argument. But we do carry a user_global_ns namespace
953 # given as the exec 'globals' argument, This is useful in embedding
953 # given as the exec 'globals' argument, This is useful in embedding
954 # situations where the ipython shell opens in a context where the
954 # situations where the ipython shell opens in a context where the
955 # distinction between locals and globals is meaningful. For
955 # distinction between locals and globals is meaningful. For
956 # non-embedded contexts, it is just the same object as the user_ns dict.
956 # non-embedded contexts, it is just the same object as the user_ns dict.
957
957
958 # FIXME. For some strange reason, __builtins__ is showing up at user
958 # FIXME. For some strange reason, __builtins__ is showing up at user
959 # level as a dict instead of a module. This is a manual fix, but I
959 # level as a dict instead of a module. This is a manual fix, but I
960 # should really track down where the problem is coming from. Alex
960 # should really track down where the problem is coming from. Alex
961 # Schmolck reported this problem first.
961 # Schmolck reported this problem first.
962
962
963 # A useful post by Alex Martelli on this topic:
963 # A useful post by Alex Martelli on this topic:
964 # Re: inconsistent value from __builtins__
964 # Re: inconsistent value from __builtins__
965 # Von: Alex Martelli <aleaxit@yahoo.com>
965 # Von: Alex Martelli <aleaxit@yahoo.com>
966 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
966 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
967 # Gruppen: comp.lang.python
967 # Gruppen: comp.lang.python
968
968
969 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
969 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
970 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
970 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
971 # > <type 'dict'>
971 # > <type 'dict'>
972 # > >>> print type(__builtins__)
972 # > >>> print type(__builtins__)
973 # > <type 'module'>
973 # > <type 'module'>
974 # > Is this difference in return value intentional?
974 # > Is this difference in return value intentional?
975
975
976 # Well, it's documented that '__builtins__' can be either a dictionary
976 # Well, it's documented that '__builtins__' can be either a dictionary
977 # or a module, and it's been that way for a long time. Whether it's
977 # or a module, and it's been that way for a long time. Whether it's
978 # intentional (or sensible), I don't know. In any case, the idea is
978 # intentional (or sensible), I don't know. In any case, the idea is
979 # that if you need to access the built-in namespace directly, you
979 # that if you need to access the built-in namespace directly, you
980 # should start with "import __builtin__" (note, no 's') which will
980 # should start with "import __builtin__" (note, no 's') which will
981 # definitely give you a module. Yeah, it's somewhat confusing:-(.
981 # definitely give you a module. Yeah, it's somewhat confusing:-(.
982
982
983 # These routines return a properly built module and dict as needed by
983 # These routines return a properly built module and dict as needed by
984 # the rest of the code, and can also be used by extension writers to
984 # the rest of the code, and can also be used by extension writers to
985 # generate properly initialized namespaces.
985 # generate properly initialized namespaces.
986 if (user_ns is not None) or (user_module is not None):
986 if (user_ns is not None) or (user_module is not None):
987 self.default_user_namespaces = False
987 self.default_user_namespaces = False
988 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
988 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
989
989
990 # A record of hidden variables we have added to the user namespace, so
990 # A record of hidden variables we have added to the user namespace, so
991 # we can list later only variables defined in actual interactive use.
991 # we can list later only variables defined in actual interactive use.
992 self.user_ns_hidden = {}
992 self.user_ns_hidden = {}
993
993
994 # Now that FakeModule produces a real module, we've run into a nasty
994 # Now that FakeModule produces a real module, we've run into a nasty
995 # problem: after script execution (via %run), the module where the user
995 # problem: after script execution (via %run), the module where the user
996 # code ran is deleted. Now that this object is a true module (needed
996 # code ran is deleted. Now that this object is a true module (needed
997 # so docetst and other tools work correctly), the Python module
997 # so docetst and other tools work correctly), the Python module
998 # teardown mechanism runs over it, and sets to None every variable
998 # teardown mechanism runs over it, and sets to None every variable
999 # present in that module. Top-level references to objects from the
999 # present in that module. Top-level references to objects from the
1000 # script survive, because the user_ns is updated with them. However,
1000 # script survive, because the user_ns is updated with them. However,
1001 # calling functions defined in the script that use other things from
1001 # calling functions defined in the script that use other things from
1002 # the script will fail, because the function's closure had references
1002 # the script will fail, because the function's closure had references
1003 # to the original objects, which are now all None. So we must protect
1003 # to the original objects, which are now all None. So we must protect
1004 # these modules from deletion by keeping a cache.
1004 # these modules from deletion by keeping a cache.
1005 #
1005 #
1006 # To avoid keeping stale modules around (we only need the one from the
1006 # To avoid keeping stale modules around (we only need the one from the
1007 # last run), we use a dict keyed with the full path to the script, so
1007 # last run), we use a dict keyed with the full path to the script, so
1008 # only the last version of the module is held in the cache. Note,
1008 # only the last version of the module is held in the cache. Note,
1009 # however, that we must cache the module *namespace contents* (their
1009 # however, that we must cache the module *namespace contents* (their
1010 # __dict__). Because if we try to cache the actual modules, old ones
1010 # __dict__). Because if we try to cache the actual modules, old ones
1011 # (uncached) could be destroyed while still holding references (such as
1011 # (uncached) could be destroyed while still holding references (such as
1012 # those held by GUI objects that tend to be long-lived)>
1012 # those held by GUI objects that tend to be long-lived)>
1013 #
1013 #
1014 # The %reset command will flush this cache. See the cache_main_mod()
1014 # The %reset command will flush this cache. See the cache_main_mod()
1015 # and clear_main_mod_cache() methods for details on use.
1015 # and clear_main_mod_cache() methods for details on use.
1016
1016
1017 # This is the cache used for 'main' namespaces
1017 # This is the cache used for 'main' namespaces
1018 self._main_mod_cache = {}
1018 self._main_mod_cache = {}
1019
1019
1020 # A table holding all the namespaces IPython deals with, so that
1020 # A table holding all the namespaces IPython deals with, so that
1021 # introspection facilities can search easily.
1021 # introspection facilities can search easily.
1022 self.ns_table = {'user_global':self.user_module.__dict__,
1022 self.ns_table = {'user_global':self.user_module.__dict__,
1023 'user_local':self.user_ns,
1023 'user_local':self.user_ns,
1024 'builtin':builtin_mod.__dict__
1024 'builtin':builtin_mod.__dict__
1025 }
1025 }
1026
1026
1027 @property
1027 @property
1028 def user_global_ns(self):
1028 def user_global_ns(self):
1029 return self.user_module.__dict__
1029 return self.user_module.__dict__
1030
1030
1031 def prepare_user_module(self, user_module=None, user_ns=None):
1031 def prepare_user_module(self, user_module=None, user_ns=None):
1032 """Prepare the module and namespace in which user code will be run.
1032 """Prepare the module and namespace in which user code will be run.
1033
1033
1034 When IPython is started normally, both parameters are None: a new module
1034 When IPython is started normally, both parameters are None: a new module
1035 is created automatically, and its __dict__ used as the namespace.
1035 is created automatically, and its __dict__ used as the namespace.
1036
1036
1037 If only user_module is provided, its __dict__ is used as the namespace.
1037 If only user_module is provided, its __dict__ is used as the namespace.
1038 If only user_ns is provided, a dummy module is created, and user_ns
1038 If only user_ns is provided, a dummy module is created, and user_ns
1039 becomes the global namespace. If both are provided (as they may be
1039 becomes the global namespace. If both are provided (as they may be
1040 when embedding), user_ns is the local namespace, and user_module
1040 when embedding), user_ns is the local namespace, and user_module
1041 provides the global namespace.
1041 provides the global namespace.
1042
1042
1043 Parameters
1043 Parameters
1044 ----------
1044 ----------
1045 user_module : module, optional
1045 user_module : module, optional
1046 The current user module in which IPython is being run. If None,
1046 The current user module in which IPython is being run. If None,
1047 a clean module will be created.
1047 a clean module will be created.
1048 user_ns : dict, optional
1048 user_ns : dict, optional
1049 A namespace in which to run interactive commands.
1049 A namespace in which to run interactive commands.
1050
1050
1051 Returns
1051 Returns
1052 -------
1052 -------
1053 A tuple of user_module and user_ns, each properly initialised.
1053 A tuple of user_module and user_ns, each properly initialised.
1054 """
1054 """
1055 if user_module is None and user_ns is not None:
1055 if user_module is None and user_ns is not None:
1056 user_ns.setdefault("__name__", "__main__")
1056 user_ns.setdefault("__name__", "__main__")
1057 user_module = DummyMod()
1057 user_module = DummyMod()
1058 user_module.__dict__ = user_ns
1058 user_module.__dict__ = user_ns
1059
1059
1060 if user_module is None:
1060 if user_module is None:
1061 user_module = types.ModuleType("__main__",
1061 user_module = types.ModuleType("__main__",
1062 doc="Automatically created module for IPython interactive environment")
1062 doc="Automatically created module for IPython interactive environment")
1063
1063
1064 # We must ensure that __builtin__ (without the final 's') is always
1064 # We must ensure that __builtin__ (without the final 's') is always
1065 # available and pointing to the __builtin__ *module*. For more details:
1065 # available and pointing to the __builtin__ *module*. For more details:
1066 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1066 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1067 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1067 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1068 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1068 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1069
1069
1070 if user_ns is None:
1070 if user_ns is None:
1071 user_ns = user_module.__dict__
1071 user_ns = user_module.__dict__
1072
1072
1073 return user_module, user_ns
1073 return user_module, user_ns
1074
1074
1075 def init_sys_modules(self):
1075 def init_sys_modules(self):
1076 # We need to insert into sys.modules something that looks like a
1076 # We need to insert into sys.modules something that looks like a
1077 # module but which accesses the IPython namespace, for shelve and
1077 # module but which accesses the IPython namespace, for shelve and
1078 # pickle to work interactively. Normally they rely on getting
1078 # pickle to work interactively. Normally they rely on getting
1079 # everything out of __main__, but for embedding purposes each IPython
1079 # everything out of __main__, but for embedding purposes each IPython
1080 # instance has its own private namespace, so we can't go shoving
1080 # instance has its own private namespace, so we can't go shoving
1081 # everything into __main__.
1081 # everything into __main__.
1082
1082
1083 # note, however, that we should only do this for non-embedded
1083 # note, however, that we should only do this for non-embedded
1084 # ipythons, which really mimic the __main__.__dict__ with their own
1084 # ipythons, which really mimic the __main__.__dict__ with their own
1085 # namespace. Embedded instances, on the other hand, should not do
1085 # namespace. Embedded instances, on the other hand, should not do
1086 # this because they need to manage the user local/global namespaces
1086 # this because they need to manage the user local/global namespaces
1087 # only, but they live within a 'normal' __main__ (meaning, they
1087 # only, but they live within a 'normal' __main__ (meaning, they
1088 # shouldn't overtake the execution environment of the script they're
1088 # shouldn't overtake the execution environment of the script they're
1089 # embedded in).
1089 # embedded in).
1090
1090
1091 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1091 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1092 main_name = self.user_module.__name__
1092 main_name = self.user_module.__name__
1093 sys.modules[main_name] = self.user_module
1093 sys.modules[main_name] = self.user_module
1094
1094
1095 def init_user_ns(self):
1095 def init_user_ns(self):
1096 """Initialize all user-visible namespaces to their minimum defaults.
1096 """Initialize all user-visible namespaces to their minimum defaults.
1097
1097
1098 Certain history lists are also initialized here, as they effectively
1098 Certain history lists are also initialized here, as they effectively
1099 act as user namespaces.
1099 act as user namespaces.
1100
1100
1101 Notes
1101 Notes
1102 -----
1102 -----
1103 All data structures here are only filled in, they are NOT reset by this
1103 All data structures here are only filled in, they are NOT reset by this
1104 method. If they were not empty before, data will simply be added to
1104 method. If they were not empty before, data will simply be added to
1105 therm.
1105 therm.
1106 """
1106 """
1107 # This function works in two parts: first we put a few things in
1107 # This function works in two parts: first we put a few things in
1108 # user_ns, and we sync that contents into user_ns_hidden so that these
1108 # user_ns, and we sync that contents into user_ns_hidden so that these
1109 # initial variables aren't shown by %who. After the sync, we add the
1109 # initial variables aren't shown by %who. After the sync, we add the
1110 # rest of what we *do* want the user to see with %who even on a new
1110 # rest of what we *do* want the user to see with %who even on a new
1111 # session (probably nothing, so theye really only see their own stuff)
1111 # session (probably nothing, so theye really only see their own stuff)
1112
1112
1113 # The user dict must *always* have a __builtin__ reference to the
1113 # The user dict must *always* have a __builtin__ reference to the
1114 # Python standard __builtin__ namespace, which must be imported.
1114 # Python standard __builtin__ namespace, which must be imported.
1115 # This is so that certain operations in prompt evaluation can be
1115 # This is so that certain operations in prompt evaluation can be
1116 # reliably executed with builtins. Note that we can NOT use
1116 # reliably executed with builtins. Note that we can NOT use
1117 # __builtins__ (note the 's'), because that can either be a dict or a
1117 # __builtins__ (note the 's'), because that can either be a dict or a
1118 # module, and can even mutate at runtime, depending on the context
1118 # module, and can even mutate at runtime, depending on the context
1119 # (Python makes no guarantees on it). In contrast, __builtin__ is
1119 # (Python makes no guarantees on it). In contrast, __builtin__ is
1120 # always a module object, though it must be explicitly imported.
1120 # always a module object, though it must be explicitly imported.
1121
1121
1122 # For more details:
1122 # For more details:
1123 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1123 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1124 ns = dict()
1124 ns = dict()
1125
1125
1126 # Put 'help' in the user namespace
1126 # Put 'help' in the user namespace
1127 try:
1127 try:
1128 from site import _Helper
1128 from site import _Helper
1129 ns['help'] = _Helper()
1129 ns['help'] = _Helper()
1130 except ImportError:
1130 except ImportError:
1131 warn('help() not available - check site.py')
1131 warn('help() not available - check site.py')
1132
1132
1133 # make global variables for user access to the histories
1133 # make global variables for user access to the histories
1134 ns['_ih'] = self.history_manager.input_hist_parsed
1134 ns['_ih'] = self.history_manager.input_hist_parsed
1135 ns['_oh'] = self.history_manager.output_hist
1135 ns['_oh'] = self.history_manager.output_hist
1136 ns['_dh'] = self.history_manager.dir_hist
1136 ns['_dh'] = self.history_manager.dir_hist
1137
1137
1138 ns['_sh'] = shadowns
1138 ns['_sh'] = shadowns
1139
1139
1140 # user aliases to input and output histories. These shouldn't show up
1140 # user aliases to input and output histories. These shouldn't show up
1141 # in %who, as they can have very large reprs.
1141 # in %who, as they can have very large reprs.
1142 ns['In'] = self.history_manager.input_hist_parsed
1142 ns['In'] = self.history_manager.input_hist_parsed
1143 ns['Out'] = self.history_manager.output_hist
1143 ns['Out'] = self.history_manager.output_hist
1144
1144
1145 # Store myself as the public api!!!
1145 # Store myself as the public api!!!
1146 ns['get_ipython'] = self.get_ipython
1146 ns['get_ipython'] = self.get_ipython
1147
1147
1148 ns['exit'] = self.exiter
1148 ns['exit'] = self.exiter
1149 ns['quit'] = self.exiter
1149 ns['quit'] = self.exiter
1150
1150
1151 # Sync what we've added so far to user_ns_hidden so these aren't seen
1151 # Sync what we've added so far to user_ns_hidden so these aren't seen
1152 # by %who
1152 # by %who
1153 self.user_ns_hidden.update(ns)
1153 self.user_ns_hidden.update(ns)
1154
1154
1155 # Anything put into ns now would show up in %who. Think twice before
1155 # Anything put into ns now would show up in %who. Think twice before
1156 # putting anything here, as we really want %who to show the user their
1156 # putting anything here, as we really want %who to show the user their
1157 # stuff, not our variables.
1157 # stuff, not our variables.
1158
1158
1159 # Finally, update the real user's namespace
1159 # Finally, update the real user's namespace
1160 self.user_ns.update(ns)
1160 self.user_ns.update(ns)
1161
1161
1162 @property
1162 @property
1163 def all_ns_refs(self):
1163 def all_ns_refs(self):
1164 """Get a list of references to all the namespace dictionaries in which
1164 """Get a list of references to all the namespace dictionaries in which
1165 IPython might store a user-created object.
1165 IPython might store a user-created object.
1166
1166
1167 Note that this does not include the displayhook, which also caches
1167 Note that this does not include the displayhook, which also caches
1168 objects from the output."""
1168 objects from the output."""
1169 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1169 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1170 [m.__dict__ for m in self._main_mod_cache.values()]
1170 [m.__dict__ for m in self._main_mod_cache.values()]
1171
1171
1172 def reset(self, new_session=True):
1172 def reset(self, new_session=True):
1173 """Clear all internal namespaces, and attempt to release references to
1173 """Clear all internal namespaces, and attempt to release references to
1174 user objects.
1174 user objects.
1175
1175
1176 If new_session is True, a new history session will be opened.
1176 If new_session is True, a new history session will be opened.
1177 """
1177 """
1178 # Clear histories
1178 # Clear histories
1179 self.history_manager.reset(new_session)
1179 self.history_manager.reset(new_session)
1180 # Reset counter used to index all histories
1180 # Reset counter used to index all histories
1181 if new_session:
1181 if new_session:
1182 self.execution_count = 1
1182 self.execution_count = 1
1183
1183
1184 # Flush cached output items
1184 # Flush cached output items
1185 if self.displayhook.do_full_cache:
1185 if self.displayhook.do_full_cache:
1186 self.displayhook.flush()
1186 self.displayhook.flush()
1187
1187
1188 # The main execution namespaces must be cleared very carefully,
1188 # The main execution namespaces must be cleared very carefully,
1189 # skipping the deletion of the builtin-related keys, because doing so
1189 # skipping the deletion of the builtin-related keys, because doing so
1190 # would cause errors in many object's __del__ methods.
1190 # would cause errors in many object's __del__ methods.
1191 if self.user_ns is not self.user_global_ns:
1191 if self.user_ns is not self.user_global_ns:
1192 self.user_ns.clear()
1192 self.user_ns.clear()
1193 ns = self.user_global_ns
1193 ns = self.user_global_ns
1194 drop_keys = set(ns.keys())
1194 drop_keys = set(ns.keys())
1195 drop_keys.discard('__builtin__')
1195 drop_keys.discard('__builtin__')
1196 drop_keys.discard('__builtins__')
1196 drop_keys.discard('__builtins__')
1197 drop_keys.discard('__name__')
1197 drop_keys.discard('__name__')
1198 for k in drop_keys:
1198 for k in drop_keys:
1199 del ns[k]
1199 del ns[k]
1200
1200
1201 self.user_ns_hidden.clear()
1201 self.user_ns_hidden.clear()
1202
1202
1203 # Restore the user namespaces to minimal usability
1203 # Restore the user namespaces to minimal usability
1204 self.init_user_ns()
1204 self.init_user_ns()
1205
1205
1206 # Restore the default and user aliases
1206 # Restore the default and user aliases
1207 self.alias_manager.clear_aliases()
1207 self.alias_manager.clear_aliases()
1208 self.alias_manager.init_aliases()
1208 self.alias_manager.init_aliases()
1209
1209
1210 # Flush the private list of module references kept for script
1210 # Flush the private list of module references kept for script
1211 # execution protection
1211 # execution protection
1212 self.clear_main_mod_cache()
1212 self.clear_main_mod_cache()
1213
1213
1214 def del_var(self, varname, by_name=False):
1214 def del_var(self, varname, by_name=False):
1215 """Delete a variable from the various namespaces, so that, as
1215 """Delete a variable from the various namespaces, so that, as
1216 far as possible, we're not keeping any hidden references to it.
1216 far as possible, we're not keeping any hidden references to it.
1217
1217
1218 Parameters
1218 Parameters
1219 ----------
1219 ----------
1220 varname : str
1220 varname : str
1221 The name of the variable to delete.
1221 The name of the variable to delete.
1222 by_name : bool
1222 by_name : bool
1223 If True, delete variables with the given name in each
1223 If True, delete variables with the given name in each
1224 namespace. If False (default), find the variable in the user
1224 namespace. If False (default), find the variable in the user
1225 namespace, and delete references to it.
1225 namespace, and delete references to it.
1226 """
1226 """
1227 if varname in ('__builtin__', '__builtins__'):
1227 if varname in ('__builtin__', '__builtins__'):
1228 raise ValueError("Refusing to delete %s" % varname)
1228 raise ValueError("Refusing to delete %s" % varname)
1229
1229
1230 ns_refs = self.all_ns_refs
1230 ns_refs = self.all_ns_refs
1231
1231
1232 if by_name: # Delete by name
1232 if by_name: # Delete by name
1233 for ns in ns_refs:
1233 for ns in ns_refs:
1234 try:
1234 try:
1235 del ns[varname]
1235 del ns[varname]
1236 except KeyError:
1236 except KeyError:
1237 pass
1237 pass
1238 else: # Delete by object
1238 else: # Delete by object
1239 try:
1239 try:
1240 obj = self.user_ns[varname]
1240 obj = self.user_ns[varname]
1241 except KeyError:
1241 except KeyError:
1242 raise NameError("name '%s' is not defined" % varname)
1242 raise NameError("name '%s' is not defined" % varname)
1243 # Also check in output history
1243 # Also check in output history
1244 ns_refs.append(self.history_manager.output_hist)
1244 ns_refs.append(self.history_manager.output_hist)
1245 for ns in ns_refs:
1245 for ns in ns_refs:
1246 to_delete = [n for n, o in iteritems(ns) if o is obj]
1246 to_delete = [n for n, o in iteritems(ns) if o is obj]
1247 for name in to_delete:
1247 for name in to_delete:
1248 del ns[name]
1248 del ns[name]
1249
1249
1250 # displayhook keeps extra references, but not in a dictionary
1250 # displayhook keeps extra references, but not in a dictionary
1251 for name in ('_', '__', '___'):
1251 for name in ('_', '__', '___'):
1252 if getattr(self.displayhook, name) is obj:
1252 if getattr(self.displayhook, name) is obj:
1253 setattr(self.displayhook, name, None)
1253 setattr(self.displayhook, name, None)
1254
1254
1255 def reset_selective(self, regex=None):
1255 def reset_selective(self, regex=None):
1256 """Clear selective variables from internal namespaces based on a
1256 """Clear selective variables from internal namespaces based on a
1257 specified regular expression.
1257 specified regular expression.
1258
1258
1259 Parameters
1259 Parameters
1260 ----------
1260 ----------
1261 regex : string or compiled pattern, optional
1261 regex : string or compiled pattern, optional
1262 A regular expression pattern that will be used in searching
1262 A regular expression pattern that will be used in searching
1263 variable names in the users namespaces.
1263 variable names in the users namespaces.
1264 """
1264 """
1265 if regex is not None:
1265 if regex is not None:
1266 try:
1266 try:
1267 m = re.compile(regex)
1267 m = re.compile(regex)
1268 except TypeError:
1268 except TypeError:
1269 raise TypeError('regex must be a string or compiled pattern')
1269 raise TypeError('regex must be a string or compiled pattern')
1270 # Search for keys in each namespace that match the given regex
1270 # Search for keys in each namespace that match the given regex
1271 # If a match is found, delete the key/value pair.
1271 # If a match is found, delete the key/value pair.
1272 for ns in self.all_ns_refs:
1272 for ns in self.all_ns_refs:
1273 for var in ns:
1273 for var in ns:
1274 if m.search(var):
1274 if m.search(var):
1275 del ns[var]
1275 del ns[var]
1276
1276
1277 def push(self, variables, interactive=True):
1277 def push(self, variables, interactive=True):
1278 """Inject a group of variables into the IPython user namespace.
1278 """Inject a group of variables into the IPython user namespace.
1279
1279
1280 Parameters
1280 Parameters
1281 ----------
1281 ----------
1282 variables : dict, str or list/tuple of str
1282 variables : dict, str or list/tuple of str
1283 The variables to inject into the user's namespace. If a dict, a
1283 The variables to inject into the user's namespace. If a dict, a
1284 simple update is done. If a str, the string is assumed to have
1284 simple update is done. If a str, the string is assumed to have
1285 variable names separated by spaces. A list/tuple of str can also
1285 variable names separated by spaces. A list/tuple of str can also
1286 be used to give the variable names. If just the variable names are
1286 be used to give the variable names. If just the variable names are
1287 give (list/tuple/str) then the variable values looked up in the
1287 give (list/tuple/str) then the variable values looked up in the
1288 callers frame.
1288 callers frame.
1289 interactive : bool
1289 interactive : bool
1290 If True (default), the variables will be listed with the ``who``
1290 If True (default), the variables will be listed with the ``who``
1291 magic.
1291 magic.
1292 """
1292 """
1293 vdict = None
1293 vdict = None
1294
1294
1295 # We need a dict of name/value pairs to do namespace updates.
1295 # We need a dict of name/value pairs to do namespace updates.
1296 if isinstance(variables, dict):
1296 if isinstance(variables, dict):
1297 vdict = variables
1297 vdict = variables
1298 elif isinstance(variables, string_types+(list, tuple)):
1298 elif isinstance(variables, string_types+(list, tuple)):
1299 if isinstance(variables, string_types):
1299 if isinstance(variables, string_types):
1300 vlist = variables.split()
1300 vlist = variables.split()
1301 else:
1301 else:
1302 vlist = variables
1302 vlist = variables
1303 vdict = {}
1303 vdict = {}
1304 cf = sys._getframe(1)
1304 cf = sys._getframe(1)
1305 for name in vlist:
1305 for name in vlist:
1306 try:
1306 try:
1307 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1307 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1308 except:
1308 except:
1309 print('Could not get variable %s from %s' %
1309 print('Could not get variable %s from %s' %
1310 (name,cf.f_code.co_name))
1310 (name,cf.f_code.co_name))
1311 else:
1311 else:
1312 raise ValueError('variables must be a dict/str/list/tuple')
1312 raise ValueError('variables must be a dict/str/list/tuple')
1313
1313
1314 # Propagate variables to user namespace
1314 # Propagate variables to user namespace
1315 self.user_ns.update(vdict)
1315 self.user_ns.update(vdict)
1316
1316
1317 # And configure interactive visibility
1317 # And configure interactive visibility
1318 user_ns_hidden = self.user_ns_hidden
1318 user_ns_hidden = self.user_ns_hidden
1319 if interactive:
1319 if interactive:
1320 for name in vdict:
1320 for name in vdict:
1321 user_ns_hidden.pop(name, None)
1321 user_ns_hidden.pop(name, None)
1322 else:
1322 else:
1323 user_ns_hidden.update(vdict)
1323 user_ns_hidden.update(vdict)
1324
1324
1325 def drop_by_id(self, variables):
1325 def drop_by_id(self, variables):
1326 """Remove a dict of variables from the user namespace, if they are the
1326 """Remove a dict of variables from the user namespace, if they are the
1327 same as the values in the dictionary.
1327 same as the values in the dictionary.
1328
1328
1329 This is intended for use by extensions: variables that they've added can
1329 This is intended for use by extensions: variables that they've added can
1330 be taken back out if they are unloaded, without removing any that the
1330 be taken back out if they are unloaded, without removing any that the
1331 user has overwritten.
1331 user has overwritten.
1332
1332
1333 Parameters
1333 Parameters
1334 ----------
1334 ----------
1335 variables : dict
1335 variables : dict
1336 A dictionary mapping object names (as strings) to the objects.
1336 A dictionary mapping object names (as strings) to the objects.
1337 """
1337 """
1338 for name, obj in iteritems(variables):
1338 for name, obj in iteritems(variables):
1339 if name in self.user_ns and self.user_ns[name] is obj:
1339 if name in self.user_ns and self.user_ns[name] is obj:
1340 del self.user_ns[name]
1340 del self.user_ns[name]
1341 self.user_ns_hidden.pop(name, None)
1341 self.user_ns_hidden.pop(name, None)
1342
1342
1343 #-------------------------------------------------------------------------
1343 #-------------------------------------------------------------------------
1344 # Things related to object introspection
1344 # Things related to object introspection
1345 #-------------------------------------------------------------------------
1345 #-------------------------------------------------------------------------
1346
1346
1347 def _ofind(self, oname, namespaces=None):
1347 def _ofind(self, oname, namespaces=None):
1348 """Find an object in the available namespaces.
1348 """Find an object in the available namespaces.
1349
1349
1350 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1350 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1351
1351
1352 Has special code to detect magic functions.
1352 Has special code to detect magic functions.
1353 """
1353 """
1354 oname = oname.strip()
1354 oname = oname.strip()
1355 #print '1- oname: <%r>' % oname # dbg
1355 #print '1- oname: <%r>' % oname # dbg
1356 if not oname.startswith(ESC_MAGIC) and \
1356 if not oname.startswith(ESC_MAGIC) and \
1357 not oname.startswith(ESC_MAGIC2) and \
1357 not oname.startswith(ESC_MAGIC2) and \
1358 not py3compat.isidentifier(oname, dotted=True):
1358 not py3compat.isidentifier(oname, dotted=True):
1359 return dict(found=False)
1359 return dict(found=False)
1360
1360
1361 alias_ns = None
1361 alias_ns = None
1362 if namespaces is None:
1362 if namespaces is None:
1363 # Namespaces to search in:
1363 # Namespaces to search in:
1364 # Put them in a list. The order is important so that we
1364 # Put them in a list. The order is important so that we
1365 # find things in the same order that Python finds them.
1365 # find things in the same order that Python finds them.
1366 namespaces = [ ('Interactive', self.user_ns),
1366 namespaces = [ ('Interactive', self.user_ns),
1367 ('Interactive (global)', self.user_global_ns),
1367 ('Interactive (global)', self.user_global_ns),
1368 ('Python builtin', builtin_mod.__dict__),
1368 ('Python builtin', builtin_mod.__dict__),
1369 ]
1369 ]
1370
1370
1371 # initialize results to 'null'
1371 # initialize results to 'null'
1372 found = False; obj = None; ospace = None; ds = None;
1372 found = False; obj = None; ospace = None; ds = None;
1373 ismagic = False; isalias = False; parent = None
1373 ismagic = False; isalias = False; parent = None
1374
1374
1375 # We need to special-case 'print', which as of python2.6 registers as a
1375 # We need to special-case 'print', which as of python2.6 registers as a
1376 # function but should only be treated as one if print_function was
1376 # function but should only be treated as one if print_function was
1377 # loaded with a future import. In this case, just bail.
1377 # loaded with a future import. In this case, just bail.
1378 if (oname == 'print' and not py3compat.PY3 and not \
1378 if (oname == 'print' and not py3compat.PY3 and not \
1379 (self.compile.compiler_flags & __future__.CO_FUTURE_PRINT_FUNCTION)):
1379 (self.compile.compiler_flags & __future__.CO_FUTURE_PRINT_FUNCTION)):
1380 return {'found':found, 'obj':obj, 'namespace':ospace,
1380 return {'found':found, 'obj':obj, 'namespace':ospace,
1381 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1381 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1382
1382
1383 # Look for the given name by splitting it in parts. If the head is
1383 # Look for the given name by splitting it in parts. If the head is
1384 # found, then we look for all the remaining parts as members, and only
1384 # found, then we look for all the remaining parts as members, and only
1385 # declare success if we can find them all.
1385 # declare success if we can find them all.
1386 oname_parts = oname.split('.')
1386 oname_parts = oname.split('.')
1387 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1387 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1388 for nsname,ns in namespaces:
1388 for nsname,ns in namespaces:
1389 try:
1389 try:
1390 obj = ns[oname_head]
1390 obj = ns[oname_head]
1391 except KeyError:
1391 except KeyError:
1392 continue
1392 continue
1393 else:
1393 else:
1394 #print 'oname_rest:', oname_rest # dbg
1394 #print 'oname_rest:', oname_rest # dbg
1395 for part in oname_rest:
1395 for part in oname_rest:
1396 try:
1396 try:
1397 parent = obj
1397 parent = obj
1398 obj = getattr(obj,part)
1398 obj = getattr(obj,part)
1399 except:
1399 except:
1400 # Blanket except b/c some badly implemented objects
1400 # Blanket except b/c some badly implemented objects
1401 # allow __getattr__ to raise exceptions other than
1401 # allow __getattr__ to raise exceptions other than
1402 # AttributeError, which then crashes IPython.
1402 # AttributeError, which then crashes IPython.
1403 break
1403 break
1404 else:
1404 else:
1405 # If we finish the for loop (no break), we got all members
1405 # If we finish the for loop (no break), we got all members
1406 found = True
1406 found = True
1407 ospace = nsname
1407 ospace = nsname
1408 break # namespace loop
1408 break # namespace loop
1409
1409
1410 # Try to see if it's magic
1410 # Try to see if it's magic
1411 if not found:
1411 if not found:
1412 obj = None
1412 obj = None
1413 if oname.startswith(ESC_MAGIC2):
1413 if oname.startswith(ESC_MAGIC2):
1414 oname = oname.lstrip(ESC_MAGIC2)
1414 oname = oname.lstrip(ESC_MAGIC2)
1415 obj = self.find_cell_magic(oname)
1415 obj = self.find_cell_magic(oname)
1416 elif oname.startswith(ESC_MAGIC):
1416 elif oname.startswith(ESC_MAGIC):
1417 oname = oname.lstrip(ESC_MAGIC)
1417 oname = oname.lstrip(ESC_MAGIC)
1418 obj = self.find_line_magic(oname)
1418 obj = self.find_line_magic(oname)
1419 else:
1419 else:
1420 # search without prefix, so run? will find %run?
1420 # search without prefix, so run? will find %run?
1421 obj = self.find_line_magic(oname)
1421 obj = self.find_line_magic(oname)
1422 if obj is None:
1422 if obj is None:
1423 obj = self.find_cell_magic(oname)
1423 obj = self.find_cell_magic(oname)
1424 if obj is not None:
1424 if obj is not None:
1425 found = True
1425 found = True
1426 ospace = 'IPython internal'
1426 ospace = 'IPython internal'
1427 ismagic = True
1427 ismagic = True
1428
1428
1429 # Last try: special-case some literals like '', [], {}, etc:
1429 # Last try: special-case some literals like '', [], {}, etc:
1430 if not found and oname_head in ["''",'""','[]','{}','()']:
1430 if not found and oname_head in ["''",'""','[]','{}','()']:
1431 obj = eval(oname_head)
1431 obj = eval(oname_head)
1432 found = True
1432 found = True
1433 ospace = 'Interactive'
1433 ospace = 'Interactive'
1434
1434
1435 return {'found':found, 'obj':obj, 'namespace':ospace,
1435 return {'found':found, 'obj':obj, 'namespace':ospace,
1436 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1436 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1437
1437
1438 def _ofind_property(self, oname, info):
1438 def _ofind_property(self, oname, info):
1439 """Second part of object finding, to look for property details."""
1439 """Second part of object finding, to look for property details."""
1440 if info.found:
1440 if info.found:
1441 # Get the docstring of the class property if it exists.
1441 # Get the docstring of the class property if it exists.
1442 path = oname.split('.')
1442 path = oname.split('.')
1443 root = '.'.join(path[:-1])
1443 root = '.'.join(path[:-1])
1444 if info.parent is not None:
1444 if info.parent is not None:
1445 try:
1445 try:
1446 target = getattr(info.parent, '__class__')
1446 target = getattr(info.parent, '__class__')
1447 # The object belongs to a class instance.
1447 # The object belongs to a class instance.
1448 try:
1448 try:
1449 target = getattr(target, path[-1])
1449 target = getattr(target, path[-1])
1450 # The class defines the object.
1450 # The class defines the object.
1451 if isinstance(target, property):
1451 if isinstance(target, property):
1452 oname = root + '.__class__.' + path[-1]
1452 oname = root + '.__class__.' + path[-1]
1453 info = Struct(self._ofind(oname))
1453 info = Struct(self._ofind(oname))
1454 except AttributeError: pass
1454 except AttributeError: pass
1455 except AttributeError: pass
1455 except AttributeError: pass
1456
1456
1457 # We return either the new info or the unmodified input if the object
1457 # We return either the new info or the unmodified input if the object
1458 # hadn't been found
1458 # hadn't been found
1459 return info
1459 return info
1460
1460
1461 def _object_find(self, oname, namespaces=None):
1461 def _object_find(self, oname, namespaces=None):
1462 """Find an object and return a struct with info about it."""
1462 """Find an object and return a struct with info about it."""
1463 inf = Struct(self._ofind(oname, namespaces))
1463 inf = Struct(self._ofind(oname, namespaces))
1464 return Struct(self._ofind_property(oname, inf))
1464 return Struct(self._ofind_property(oname, inf))
1465
1465
1466 def _inspect(self, meth, oname, namespaces=None, **kw):
1466 def _inspect(self, meth, oname, namespaces=None, **kw):
1467 """Generic interface to the inspector system.
1467 """Generic interface to the inspector system.
1468
1468
1469 This function is meant to be called by pdef, pdoc & friends."""
1469 This function is meant to be called by pdef, pdoc & friends."""
1470 info = self._object_find(oname, namespaces)
1470 info = self._object_find(oname, namespaces)
1471 if info.found:
1471 if info.found:
1472 pmethod = getattr(self.inspector, meth)
1472 pmethod = getattr(self.inspector, meth)
1473 formatter = format_screen if info.ismagic else None
1473 formatter = format_screen if info.ismagic else None
1474 if meth == 'pdoc':
1474 if meth == 'pdoc':
1475 pmethod(info.obj, oname, formatter)
1475 pmethod(info.obj, oname, formatter)
1476 elif meth == 'pinfo':
1476 elif meth == 'pinfo':
1477 pmethod(info.obj, oname, formatter, info, **kw)
1477 pmethod(info.obj, oname, formatter, info, **kw)
1478 else:
1478 else:
1479 pmethod(info.obj, oname)
1479 pmethod(info.obj, oname)
1480 else:
1480 else:
1481 print('Object `%s` not found.' % oname)
1481 print('Object `%s` not found.' % oname)
1482 return 'not found' # so callers can take other action
1482 return 'not found' # so callers can take other action
1483
1483
1484 def object_inspect(self, oname, detail_level=0):
1484 def object_inspect(self, oname, detail_level=0):
1485 with self.builtin_trap:
1485 with self.builtin_trap:
1486 info = self._object_find(oname)
1486 info = self._object_find(oname)
1487 if info.found:
1487 if info.found:
1488 return self.inspector.info(info.obj, oname, info=info,
1488 return self.inspector.info(info.obj, oname, info=info,
1489 detail_level=detail_level
1489 detail_level=detail_level
1490 )
1490 )
1491 else:
1491 else:
1492 return oinspect.object_info(name=oname, found=False)
1492 return oinspect.object_info(name=oname, found=False)
1493
1493
1494 #-------------------------------------------------------------------------
1494 #-------------------------------------------------------------------------
1495 # Things related to history management
1495 # Things related to history management
1496 #-------------------------------------------------------------------------
1496 #-------------------------------------------------------------------------
1497
1497
1498 def init_history(self):
1498 def init_history(self):
1499 """Sets up the command history, and starts regular autosaves."""
1499 """Sets up the command history, and starts regular autosaves."""
1500 self.history_manager = HistoryManager(shell=self, parent=self)
1500 self.history_manager = HistoryManager(shell=self, parent=self)
1501 self.configurables.append(self.history_manager)
1501 self.configurables.append(self.history_manager)
1502
1502
1503 #-------------------------------------------------------------------------
1503 #-------------------------------------------------------------------------
1504 # Things related to exception handling and tracebacks (not debugging)
1504 # Things related to exception handling and tracebacks (not debugging)
1505 #-------------------------------------------------------------------------
1505 #-------------------------------------------------------------------------
1506
1506
1507 def init_traceback_handlers(self, custom_exceptions):
1507 def init_traceback_handlers(self, custom_exceptions):
1508 # Syntax error handler.
1508 # Syntax error handler.
1509 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor')
1509 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor')
1510
1510
1511 # The interactive one is initialized with an offset, meaning we always
1511 # The interactive one is initialized with an offset, meaning we always
1512 # want to remove the topmost item in the traceback, which is our own
1512 # want to remove the topmost item in the traceback, which is our own
1513 # internal code. Valid modes: ['Plain','Context','Verbose']
1513 # internal code. Valid modes: ['Plain','Context','Verbose']
1514 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1514 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1515 color_scheme='NoColor',
1515 color_scheme='NoColor',
1516 tb_offset = 1,
1516 tb_offset = 1,
1517 check_cache=check_linecache_ipython)
1517 check_cache=check_linecache_ipython)
1518
1518
1519 # The instance will store a pointer to the system-wide exception hook,
1519 # The instance will store a pointer to the system-wide exception hook,
1520 # so that runtime code (such as magics) can access it. This is because
1520 # so that runtime code (such as magics) can access it. This is because
1521 # during the read-eval loop, it may get temporarily overwritten.
1521 # during the read-eval loop, it may get temporarily overwritten.
1522 self.sys_excepthook = sys.excepthook
1522 self.sys_excepthook = sys.excepthook
1523
1523
1524 # and add any custom exception handlers the user may have specified
1524 # and add any custom exception handlers the user may have specified
1525 self.set_custom_exc(*custom_exceptions)
1525 self.set_custom_exc(*custom_exceptions)
1526
1526
1527 # Set the exception mode
1527 # Set the exception mode
1528 self.InteractiveTB.set_mode(mode=self.xmode)
1528 self.InteractiveTB.set_mode(mode=self.xmode)
1529
1529
1530 def set_custom_exc(self, exc_tuple, handler):
1530 def set_custom_exc(self, exc_tuple, handler):
1531 """set_custom_exc(exc_tuple,handler)
1531 """set_custom_exc(exc_tuple,handler)
1532
1532
1533 Set a custom exception handler, which will be called if any of the
1533 Set a custom exception handler, which will be called if any of the
1534 exceptions in exc_tuple occur in the mainloop (specifically, in the
1534 exceptions in exc_tuple occur in the mainloop (specifically, in the
1535 run_code() method).
1535 run_code() method).
1536
1536
1537 Parameters
1537 Parameters
1538 ----------
1538 ----------
1539
1539
1540 exc_tuple : tuple of exception classes
1540 exc_tuple : tuple of exception classes
1541 A *tuple* of exception classes, for which to call the defined
1541 A *tuple* of exception classes, for which to call the defined
1542 handler. It is very important that you use a tuple, and NOT A
1542 handler. It is very important that you use a tuple, and NOT A
1543 LIST here, because of the way Python's except statement works. If
1543 LIST here, because of the way Python's except statement works. If
1544 you only want to trap a single exception, use a singleton tuple::
1544 you only want to trap a single exception, use a singleton tuple::
1545
1545
1546 exc_tuple == (MyCustomException,)
1546 exc_tuple == (MyCustomException,)
1547
1547
1548 handler : callable
1548 handler : callable
1549 handler must have the following signature::
1549 handler must have the following signature::
1550
1550
1551 def my_handler(self, etype, value, tb, tb_offset=None):
1551 def my_handler(self, etype, value, tb, tb_offset=None):
1552 ...
1552 ...
1553 return structured_traceback
1553 return structured_traceback
1554
1554
1555 Your handler must return a structured traceback (a list of strings),
1555 Your handler must return a structured traceback (a list of strings),
1556 or None.
1556 or None.
1557
1557
1558 This will be made into an instance method (via types.MethodType)
1558 This will be made into an instance method (via types.MethodType)
1559 of IPython itself, and it will be called if any of the exceptions
1559 of IPython itself, and it will be called if any of the exceptions
1560 listed in the exc_tuple are caught. If the handler is None, an
1560 listed in the exc_tuple are caught. If the handler is None, an
1561 internal basic one is used, which just prints basic info.
1561 internal basic one is used, which just prints basic info.
1562
1562
1563 To protect IPython from crashes, if your handler ever raises an
1563 To protect IPython from crashes, if your handler ever raises an
1564 exception or returns an invalid result, it will be immediately
1564 exception or returns an invalid result, it will be immediately
1565 disabled.
1565 disabled.
1566
1566
1567 WARNING: by putting in your own exception handler into IPython's main
1567 WARNING: by putting in your own exception handler into IPython's main
1568 execution loop, you run a very good chance of nasty crashes. This
1568 execution loop, you run a very good chance of nasty crashes. This
1569 facility should only be used if you really know what you are doing."""
1569 facility should only be used if you really know what you are doing."""
1570
1570
1571 assert type(exc_tuple)==type(()) , \
1571 assert type(exc_tuple)==type(()) , \
1572 "The custom exceptions must be given AS A TUPLE."
1572 "The custom exceptions must be given AS A TUPLE."
1573
1573
1574 def dummy_handler(self,etype,value,tb,tb_offset=None):
1574 def dummy_handler(self,etype,value,tb,tb_offset=None):
1575 print('*** Simple custom exception handler ***')
1575 print('*** Simple custom exception handler ***')
1576 print('Exception type :',etype)
1576 print('Exception type :',etype)
1577 print('Exception value:',value)
1577 print('Exception value:',value)
1578 print('Traceback :',tb)
1578 print('Traceback :',tb)
1579 #print 'Source code :','\n'.join(self.buffer)
1579 #print 'Source code :','\n'.join(self.buffer)
1580
1580
1581 def validate_stb(stb):
1581 def validate_stb(stb):
1582 """validate structured traceback return type
1582 """validate structured traceback return type
1583
1583
1584 return type of CustomTB *should* be a list of strings, but allow
1584 return type of CustomTB *should* be a list of strings, but allow
1585 single strings or None, which are harmless.
1585 single strings or None, which are harmless.
1586
1586
1587 This function will *always* return a list of strings,
1587 This function will *always* return a list of strings,
1588 and will raise a TypeError if stb is inappropriate.
1588 and will raise a TypeError if stb is inappropriate.
1589 """
1589 """
1590 msg = "CustomTB must return list of strings, not %r" % stb
1590 msg = "CustomTB must return list of strings, not %r" % stb
1591 if stb is None:
1591 if stb is None:
1592 return []
1592 return []
1593 elif isinstance(stb, string_types):
1593 elif isinstance(stb, string_types):
1594 return [stb]
1594 return [stb]
1595 elif not isinstance(stb, list):
1595 elif not isinstance(stb, list):
1596 raise TypeError(msg)
1596 raise TypeError(msg)
1597 # it's a list
1597 # it's a list
1598 for line in stb:
1598 for line in stb:
1599 # check every element
1599 # check every element
1600 if not isinstance(line, string_types):
1600 if not isinstance(line, string_types):
1601 raise TypeError(msg)
1601 raise TypeError(msg)
1602 return stb
1602 return stb
1603
1603
1604 if handler is None:
1604 if handler is None:
1605 wrapped = dummy_handler
1605 wrapped = dummy_handler
1606 else:
1606 else:
1607 def wrapped(self,etype,value,tb,tb_offset=None):
1607 def wrapped(self,etype,value,tb,tb_offset=None):
1608 """wrap CustomTB handler, to protect IPython from user code
1608 """wrap CustomTB handler, to protect IPython from user code
1609
1609
1610 This makes it harder (but not impossible) for custom exception
1610 This makes it harder (but not impossible) for custom exception
1611 handlers to crash IPython.
1611 handlers to crash IPython.
1612 """
1612 """
1613 try:
1613 try:
1614 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1614 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1615 return validate_stb(stb)
1615 return validate_stb(stb)
1616 except:
1616 except:
1617 # clear custom handler immediately
1617 # clear custom handler immediately
1618 self.set_custom_exc((), None)
1618 self.set_custom_exc((), None)
1619 print("Custom TB Handler failed, unregistering", file=io.stderr)
1619 print("Custom TB Handler failed, unregistering", file=io.stderr)
1620 # show the exception in handler first
1620 # show the exception in handler first
1621 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1621 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1622 print(self.InteractiveTB.stb2text(stb), file=io.stdout)
1622 print(self.InteractiveTB.stb2text(stb), file=io.stdout)
1623 print("The original exception:", file=io.stdout)
1623 print("The original exception:", file=io.stdout)
1624 stb = self.InteractiveTB.structured_traceback(
1624 stb = self.InteractiveTB.structured_traceback(
1625 (etype,value,tb), tb_offset=tb_offset
1625 (etype,value,tb), tb_offset=tb_offset
1626 )
1626 )
1627 return stb
1627 return stb
1628
1628
1629 self.CustomTB = types.MethodType(wrapped,self)
1629 self.CustomTB = types.MethodType(wrapped,self)
1630 self.custom_exceptions = exc_tuple
1630 self.custom_exceptions = exc_tuple
1631
1631
1632 def excepthook(self, etype, value, tb):
1632 def excepthook(self, etype, value, tb):
1633 """One more defense for GUI apps that call sys.excepthook.
1633 """One more defense for GUI apps that call sys.excepthook.
1634
1634
1635 GUI frameworks like wxPython trap exceptions and call
1635 GUI frameworks like wxPython trap exceptions and call
1636 sys.excepthook themselves. I guess this is a feature that
1636 sys.excepthook themselves. I guess this is a feature that
1637 enables them to keep running after exceptions that would
1637 enables them to keep running after exceptions that would
1638 otherwise kill their mainloop. This is a bother for IPython
1638 otherwise kill their mainloop. This is a bother for IPython
1639 which excepts to catch all of the program exceptions with a try:
1639 which excepts to catch all of the program exceptions with a try:
1640 except: statement.
1640 except: statement.
1641
1641
1642 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1642 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1643 any app directly invokes sys.excepthook, it will look to the user like
1643 any app directly invokes sys.excepthook, it will look to the user like
1644 IPython crashed. In order to work around this, we can disable the
1644 IPython crashed. In order to work around this, we can disable the
1645 CrashHandler and replace it with this excepthook instead, which prints a
1645 CrashHandler and replace it with this excepthook instead, which prints a
1646 regular traceback using our InteractiveTB. In this fashion, apps which
1646 regular traceback using our InteractiveTB. In this fashion, apps which
1647 call sys.excepthook will generate a regular-looking exception from
1647 call sys.excepthook will generate a regular-looking exception from
1648 IPython, and the CrashHandler will only be triggered by real IPython
1648 IPython, and the CrashHandler will only be triggered by real IPython
1649 crashes.
1649 crashes.
1650
1650
1651 This hook should be used sparingly, only in places which are not likely
1651 This hook should be used sparingly, only in places which are not likely
1652 to be true IPython errors.
1652 to be true IPython errors.
1653 """
1653 """
1654 self.showtraceback((etype,value,tb),tb_offset=0)
1654 self.showtraceback((etype,value,tb),tb_offset=0)
1655
1655
1656 def _get_exc_info(self, exc_tuple=None):
1656 def _get_exc_info(self, exc_tuple=None):
1657 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1657 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1658
1658
1659 Ensures sys.last_type,value,traceback hold the exc_info we found,
1659 Ensures sys.last_type,value,traceback hold the exc_info we found,
1660 from whichever source.
1660 from whichever source.
1661
1661
1662 raises ValueError if none of these contain any information
1662 raises ValueError if none of these contain any information
1663 """
1663 """
1664 if exc_tuple is None:
1664 if exc_tuple is None:
1665 etype, value, tb = sys.exc_info()
1665 etype, value, tb = sys.exc_info()
1666 else:
1666 else:
1667 etype, value, tb = exc_tuple
1667 etype, value, tb = exc_tuple
1668
1668
1669 if etype is None:
1669 if etype is None:
1670 if hasattr(sys, 'last_type'):
1670 if hasattr(sys, 'last_type'):
1671 etype, value, tb = sys.last_type, sys.last_value, \
1671 etype, value, tb = sys.last_type, sys.last_value, \
1672 sys.last_traceback
1672 sys.last_traceback
1673
1673
1674 if etype is None:
1674 if etype is None:
1675 raise ValueError("No exception to find")
1675 raise ValueError("No exception to find")
1676
1676
1677 # Now store the exception info in sys.last_type etc.
1677 # Now store the exception info in sys.last_type etc.
1678 # WARNING: these variables are somewhat deprecated and not
1678 # WARNING: these variables are somewhat deprecated and not
1679 # necessarily safe to use in a threaded environment, but tools
1679 # necessarily safe to use in a threaded environment, but tools
1680 # like pdb depend on their existence, so let's set them. If we
1680 # like pdb depend on their existence, so let's set them. If we
1681 # find problems in the field, we'll need to revisit their use.
1681 # find problems in the field, we'll need to revisit their use.
1682 sys.last_type = etype
1682 sys.last_type = etype
1683 sys.last_value = value
1683 sys.last_value = value
1684 sys.last_traceback = tb
1684 sys.last_traceback = tb
1685
1685
1686 return etype, value, tb
1686 return etype, value, tb
1687
1687
1688 def show_usage_error(self, exc):
1688 def show_usage_error(self, exc):
1689 """Show a short message for UsageErrors
1689 """Show a short message for UsageErrors
1690
1690
1691 These are special exceptions that shouldn't show a traceback.
1691 These are special exceptions that shouldn't show a traceback.
1692 """
1692 """
1693 self.write_err("UsageError: %s" % exc)
1693 self.write_err("UsageError: %s" % exc)
1694
1694
1695 def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None,
1695 def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None,
1696 exception_only=False):
1696 exception_only=False):
1697 """Display the exception that just occurred.
1697 """Display the exception that just occurred.
1698
1698
1699 If nothing is known about the exception, this is the method which
1699 If nothing is known about the exception, this is the method which
1700 should be used throughout the code for presenting user tracebacks,
1700 should be used throughout the code for presenting user tracebacks,
1701 rather than directly invoking the InteractiveTB object.
1701 rather than directly invoking the InteractiveTB object.
1702
1702
1703 A specific showsyntaxerror() also exists, but this method can take
1703 A specific showsyntaxerror() also exists, but this method can take
1704 care of calling it if needed, so unless you are explicitly catching a
1704 care of calling it if needed, so unless you are explicitly catching a
1705 SyntaxError exception, don't try to analyze the stack manually and
1705 SyntaxError exception, don't try to analyze the stack manually and
1706 simply call this method."""
1706 simply call this method."""
1707
1707
1708 try:
1708 try:
1709 try:
1709 try:
1710 etype, value, tb = self._get_exc_info(exc_tuple)
1710 etype, value, tb = self._get_exc_info(exc_tuple)
1711 except ValueError:
1711 except ValueError:
1712 self.write_err('No traceback available to show.\n')
1712 self.write_err('No traceback available to show.\n')
1713 return
1713 return
1714
1714
1715 if issubclass(etype, SyntaxError):
1715 if issubclass(etype, SyntaxError):
1716 # Though this won't be called by syntax errors in the input
1716 # Though this won't be called by syntax errors in the input
1717 # line, there may be SyntaxError cases with imported code.
1717 # line, there may be SyntaxError cases with imported code.
1718 self.showsyntaxerror(filename)
1718 self.showsyntaxerror(filename)
1719 elif etype is UsageError:
1719 elif etype is UsageError:
1720 self.show_usage_error(value)
1720 self.show_usage_error(value)
1721 else:
1721 else:
1722 if exception_only:
1722 if exception_only:
1723 stb = ['An exception has occurred, use %tb to see '
1723 stb = ['An exception has occurred, use %tb to see '
1724 'the full traceback.\n']
1724 'the full traceback.\n']
1725 stb.extend(self.InteractiveTB.get_exception_only(etype,
1725 stb.extend(self.InteractiveTB.get_exception_only(etype,
1726 value))
1726 value))
1727 else:
1727 else:
1728 try:
1728 try:
1729 # Exception classes can customise their traceback - we
1729 # Exception classes can customise their traceback - we
1730 # use this in IPython.parallel for exceptions occurring
1730 # use this in IPython.parallel for exceptions occurring
1731 # in the engines. This should return a list of strings.
1731 # in the engines. This should return a list of strings.
1732 stb = value._render_traceback_()
1732 stb = value._render_traceback_()
1733 except Exception:
1733 except Exception:
1734 stb = self.InteractiveTB.structured_traceback(etype,
1734 stb = self.InteractiveTB.structured_traceback(etype,
1735 value, tb, tb_offset=tb_offset)
1735 value, tb, tb_offset=tb_offset)
1736
1736
1737 self._showtraceback(etype, value, stb)
1737 self._showtraceback(etype, value, stb)
1738 if self.call_pdb:
1738 if self.call_pdb:
1739 # drop into debugger
1739 # drop into debugger
1740 self.debugger(force=True)
1740 self.debugger(force=True)
1741 return
1741 return
1742
1742
1743 # Actually show the traceback
1743 # Actually show the traceback
1744 self._showtraceback(etype, value, stb)
1744 self._showtraceback(etype, value, stb)
1745
1745
1746 except KeyboardInterrupt:
1746 except KeyboardInterrupt:
1747 self.write_err("\nKeyboardInterrupt\n")
1747 self.write_err("\nKeyboardInterrupt\n")
1748
1748
1749 def _showtraceback(self, etype, evalue, stb):
1749 def _showtraceback(self, etype, evalue, stb):
1750 """Actually show a traceback.
1750 """Actually show a traceback.
1751
1751
1752 Subclasses may override this method to put the traceback on a different
1752 Subclasses may override this method to put the traceback on a different
1753 place, like a side channel.
1753 place, like a side channel.
1754 """
1754 """
1755 print(self.InteractiveTB.stb2text(stb), file=io.stdout)
1755 print(self.InteractiveTB.stb2text(stb), file=io.stdout)
1756
1756
1757 def showsyntaxerror(self, filename=None):
1757 def showsyntaxerror(self, filename=None):
1758 """Display the syntax error that just occurred.
1758 """Display the syntax error that just occurred.
1759
1759
1760 This doesn't display a stack trace because there isn't one.
1760 This doesn't display a stack trace because there isn't one.
1761
1761
1762 If a filename is given, it is stuffed in the exception instead
1762 If a filename is given, it is stuffed in the exception instead
1763 of what was there before (because Python's parser always uses
1763 of what was there before (because Python's parser always uses
1764 "<string>" when reading from a string).
1764 "<string>" when reading from a string).
1765 """
1765 """
1766 etype, value, last_traceback = self._get_exc_info()
1766 etype, value, last_traceback = self._get_exc_info()
1767
1767
1768 if filename and issubclass(etype, SyntaxError):
1768 if filename and issubclass(etype, SyntaxError):
1769 try:
1769 try:
1770 value.filename = filename
1770 value.filename = filename
1771 except:
1771 except:
1772 # Not the format we expect; leave it alone
1772 # Not the format we expect; leave it alone
1773 pass
1773 pass
1774
1774
1775 stb = self.SyntaxTB.structured_traceback(etype, value, [])
1775 stb = self.SyntaxTB.structured_traceback(etype, value, [])
1776 self._showtraceback(etype, value, stb)
1776 self._showtraceback(etype, value, stb)
1777
1777
1778 # This is overridden in TerminalInteractiveShell to show a message about
1778 # This is overridden in TerminalInteractiveShell to show a message about
1779 # the %paste magic.
1779 # the %paste magic.
1780 def showindentationerror(self):
1780 def showindentationerror(self):
1781 """Called by run_cell when there's an IndentationError in code entered
1781 """Called by run_cell when there's an IndentationError in code entered
1782 at the prompt.
1782 at the prompt.
1783
1783
1784 This is overridden in TerminalInteractiveShell to show a message about
1784 This is overridden in TerminalInteractiveShell to show a message about
1785 the %paste magic."""
1785 the %paste magic."""
1786 self.showsyntaxerror()
1786 self.showsyntaxerror()
1787
1787
1788 #-------------------------------------------------------------------------
1788 #-------------------------------------------------------------------------
1789 # Things related to readline
1789 # Things related to readline
1790 #-------------------------------------------------------------------------
1790 #-------------------------------------------------------------------------
1791
1791
1792 def init_readline(self):
1792 def init_readline(self):
1793 """Command history completion/saving/reloading."""
1793 """Command history completion/saving/reloading."""
1794
1794
1795 if self.readline_use:
1795 if self.readline_use:
1796 import IPython.utils.rlineimpl as readline
1796 import IPython.utils.rlineimpl as readline
1797
1797
1798 self.rl_next_input = None
1798 self.rl_next_input = None
1799 self.rl_do_indent = False
1799 self.rl_do_indent = False
1800
1800
1801 if not self.readline_use or not readline.have_readline:
1801 if not self.readline_use or not readline.have_readline:
1802 self.has_readline = False
1802 self.has_readline = False
1803 self.readline = None
1803 self.readline = None
1804 # Set a number of methods that depend on readline to be no-op
1804 # Set a number of methods that depend on readline to be no-op
1805 self.readline_no_record = no_op_context
1805 self.readline_no_record = no_op_context
1806 self.set_readline_completer = no_op
1806 self.set_readline_completer = no_op
1807 self.set_custom_completer = no_op
1807 self.set_custom_completer = no_op
1808 if self.readline_use:
1808 if self.readline_use:
1809 warn('Readline services not available or not loaded.')
1809 warn('Readline services not available or not loaded.')
1810 else:
1810 else:
1811 self.has_readline = True
1811 self.has_readline = True
1812 self.readline = readline
1812 self.readline = readline
1813 sys.modules['readline'] = readline
1813 sys.modules['readline'] = readline
1814
1814
1815 # Platform-specific configuration
1815 # Platform-specific configuration
1816 if os.name == 'nt':
1816 if os.name == 'nt':
1817 # FIXME - check with Frederick to see if we can harmonize
1817 # FIXME - check with Frederick to see if we can harmonize
1818 # naming conventions with pyreadline to avoid this
1818 # naming conventions with pyreadline to avoid this
1819 # platform-dependent check
1819 # platform-dependent check
1820 self.readline_startup_hook = readline.set_pre_input_hook
1820 self.readline_startup_hook = readline.set_pre_input_hook
1821 else:
1821 else:
1822 self.readline_startup_hook = readline.set_startup_hook
1822 self.readline_startup_hook = readline.set_startup_hook
1823
1823
1824 # Load user's initrc file (readline config)
1824 # Load user's initrc file (readline config)
1825 # Or if libedit is used, load editrc.
1825 # Or if libedit is used, load editrc.
1826 inputrc_name = os.environ.get('INPUTRC')
1826 inputrc_name = os.environ.get('INPUTRC')
1827 if inputrc_name is None:
1827 if inputrc_name is None:
1828 inputrc_name = '.inputrc'
1828 inputrc_name = '.inputrc'
1829 if readline.uses_libedit:
1829 if readline.uses_libedit:
1830 inputrc_name = '.editrc'
1830 inputrc_name = '.editrc'
1831 inputrc_name = os.path.join(self.home_dir, inputrc_name)
1831 inputrc_name = os.path.join(self.home_dir, inputrc_name)
1832 if os.path.isfile(inputrc_name):
1832 if os.path.isfile(inputrc_name):
1833 try:
1833 try:
1834 readline.read_init_file(inputrc_name)
1834 readline.read_init_file(inputrc_name)
1835 except:
1835 except:
1836 warn('Problems reading readline initialization file <%s>'
1836 warn('Problems reading readline initialization file <%s>'
1837 % inputrc_name)
1837 % inputrc_name)
1838
1838
1839 # Configure readline according to user's prefs
1839 # Configure readline according to user's prefs
1840 # This is only done if GNU readline is being used. If libedit
1840 # This is only done if GNU readline is being used. If libedit
1841 # is being used (as on Leopard) the readline config is
1841 # is being used (as on Leopard) the readline config is
1842 # not run as the syntax for libedit is different.
1842 # not run as the syntax for libedit is different.
1843 if not readline.uses_libedit:
1843 if not readline.uses_libedit:
1844 for rlcommand in self.readline_parse_and_bind:
1844 for rlcommand in self.readline_parse_and_bind:
1845 #print "loading rl:",rlcommand # dbg
1845 #print "loading rl:",rlcommand # dbg
1846 readline.parse_and_bind(rlcommand)
1846 readline.parse_and_bind(rlcommand)
1847
1847
1848 # Remove some chars from the delimiters list. If we encounter
1848 # Remove some chars from the delimiters list. If we encounter
1849 # unicode chars, discard them.
1849 # unicode chars, discard them.
1850 delims = readline.get_completer_delims()
1850 delims = readline.get_completer_delims()
1851 if not py3compat.PY3:
1851 if not py3compat.PY3:
1852 delims = delims.encode("ascii", "ignore")
1852 delims = delims.encode("ascii", "ignore")
1853 for d in self.readline_remove_delims:
1853 for d in self.readline_remove_delims:
1854 delims = delims.replace(d, "")
1854 delims = delims.replace(d, "")
1855 delims = delims.replace(ESC_MAGIC, '')
1855 delims = delims.replace(ESC_MAGIC, '')
1856 readline.set_completer_delims(delims)
1856 readline.set_completer_delims(delims)
1857 # Store these so we can restore them if something like rpy2 modifies
1857 # Store these so we can restore them if something like rpy2 modifies
1858 # them.
1858 # them.
1859 self.readline_delims = delims
1859 self.readline_delims = delims
1860 # otherwise we end up with a monster history after a while:
1860 # otherwise we end up with a monster history after a while:
1861 readline.set_history_length(self.history_length)
1861 readline.set_history_length(self.history_length)
1862
1862
1863 self.refill_readline_hist()
1863 self.refill_readline_hist()
1864 self.readline_no_record = ReadlineNoRecord(self)
1864 self.readline_no_record = ReadlineNoRecord(self)
1865
1865
1866 # Configure auto-indent for all platforms
1866 # Configure auto-indent for all platforms
1867 self.set_autoindent(self.autoindent)
1867 self.set_autoindent(self.autoindent)
1868
1868
1869 def refill_readline_hist(self):
1869 def refill_readline_hist(self):
1870 # Load the last 1000 lines from history
1870 # Load the last 1000 lines from history
1871 self.readline.clear_history()
1871 self.readline.clear_history()
1872 stdin_encoding = sys.stdin.encoding or "utf-8"
1872 stdin_encoding = sys.stdin.encoding or "utf-8"
1873 last_cell = u""
1873 last_cell = u""
1874 for _, _, cell in self.history_manager.get_tail(1000,
1874 for _, _, cell in self.history_manager.get_tail(1000,
1875 include_latest=True):
1875 include_latest=True):
1876 # Ignore blank lines and consecutive duplicates
1876 # Ignore blank lines and consecutive duplicates
1877 cell = cell.rstrip()
1877 cell = cell.rstrip()
1878 if cell and (cell != last_cell):
1878 if cell and (cell != last_cell):
1879 try:
1879 try:
1880 if self.multiline_history:
1880 if self.multiline_history:
1881 self.readline.add_history(py3compat.unicode_to_str(cell,
1881 self.readline.add_history(py3compat.unicode_to_str(cell,
1882 stdin_encoding))
1882 stdin_encoding))
1883 else:
1883 else:
1884 for line in cell.splitlines():
1884 for line in cell.splitlines():
1885 self.readline.add_history(py3compat.unicode_to_str(line,
1885 self.readline.add_history(py3compat.unicode_to_str(line,
1886 stdin_encoding))
1886 stdin_encoding))
1887 last_cell = cell
1887 last_cell = cell
1888
1888
1889 except TypeError:
1889 except TypeError:
1890 # The history DB can get corrupted so it returns strings
1890 # The history DB can get corrupted so it returns strings
1891 # containing null bytes, which readline objects to.
1891 # containing null bytes, which readline objects to.
1892 continue
1892 continue
1893
1893
1894 @skip_doctest
1894 @skip_doctest
1895 def set_next_input(self, s):
1895 def set_next_input(self, s):
1896 """ Sets the 'default' input string for the next command line.
1896 """ Sets the 'default' input string for the next command line.
1897
1897
1898 Requires readline.
1898 Requires readline.
1899
1899
1900 Example::
1900 Example::
1901
1901
1902 In [1]: _ip.set_next_input("Hello Word")
1902 In [1]: _ip.set_next_input("Hello Word")
1903 In [2]: Hello Word_ # cursor is here
1903 In [2]: Hello Word_ # cursor is here
1904 """
1904 """
1905 self.rl_next_input = py3compat.cast_bytes_py2(s)
1905 self.rl_next_input = py3compat.cast_bytes_py2(s)
1906
1906
1907 # Maybe move this to the terminal subclass?
1907 # Maybe move this to the terminal subclass?
1908 def pre_readline(self):
1908 def pre_readline(self):
1909 """readline hook to be used at the start of each line.
1909 """readline hook to be used at the start of each line.
1910
1910
1911 Currently it handles auto-indent only."""
1911 Currently it handles auto-indent only."""
1912
1912
1913 if self.rl_do_indent:
1913 if self.rl_do_indent:
1914 self.readline.insert_text(self._indent_current_str())
1914 self.readline.insert_text(self._indent_current_str())
1915 if self.rl_next_input is not None:
1915 if self.rl_next_input is not None:
1916 self.readline.insert_text(self.rl_next_input)
1916 self.readline.insert_text(self.rl_next_input)
1917 self.rl_next_input = None
1917 self.rl_next_input = None
1918
1918
1919 def _indent_current_str(self):
1919 def _indent_current_str(self):
1920 """return the current level of indentation as a string"""
1920 """return the current level of indentation as a string"""
1921 return self.input_splitter.indent_spaces * ' '
1921 return self.input_splitter.indent_spaces * ' '
1922
1922
1923 #-------------------------------------------------------------------------
1923 #-------------------------------------------------------------------------
1924 # Things related to text completion
1924 # Things related to text completion
1925 #-------------------------------------------------------------------------
1925 #-------------------------------------------------------------------------
1926
1926
1927 def init_completer(self):
1927 def init_completer(self):
1928 """Initialize the completion machinery.
1928 """Initialize the completion machinery.
1929
1929
1930 This creates completion machinery that can be used by client code,
1930 This creates completion machinery that can be used by client code,
1931 either interactively in-process (typically triggered by the readline
1931 either interactively in-process (typically triggered by the readline
1932 library), programatically (such as in test suites) or out-of-prcess
1932 library), programatically (such as in test suites) or out-of-prcess
1933 (typically over the network by remote frontends).
1933 (typically over the network by remote frontends).
1934 """
1934 """
1935 from IPython.core.completer import IPCompleter
1935 from IPython.core.completer import IPCompleter
1936 from IPython.core.completerlib import (module_completer,
1936 from IPython.core.completerlib import (module_completer,
1937 magic_run_completer, cd_completer, reset_completer)
1937 magic_run_completer, cd_completer, reset_completer)
1938
1938
1939 self.Completer = IPCompleter(shell=self,
1939 self.Completer = IPCompleter(shell=self,
1940 namespace=self.user_ns,
1940 namespace=self.user_ns,
1941 global_namespace=self.user_global_ns,
1941 global_namespace=self.user_global_ns,
1942 use_readline=self.has_readline,
1942 use_readline=self.has_readline,
1943 parent=self,
1943 parent=self,
1944 )
1944 )
1945 self.configurables.append(self.Completer)
1945 self.configurables.append(self.Completer)
1946
1946
1947 # Add custom completers to the basic ones built into IPCompleter
1947 # Add custom completers to the basic ones built into IPCompleter
1948 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
1948 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
1949 self.strdispatchers['complete_command'] = sdisp
1949 self.strdispatchers['complete_command'] = sdisp
1950 self.Completer.custom_completers = sdisp
1950 self.Completer.custom_completers = sdisp
1951
1951
1952 self.set_hook('complete_command', module_completer, str_key = 'import')
1952 self.set_hook('complete_command', module_completer, str_key = 'import')
1953 self.set_hook('complete_command', module_completer, str_key = 'from')
1953 self.set_hook('complete_command', module_completer, str_key = 'from')
1954 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
1954 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
1955 self.set_hook('complete_command', cd_completer, str_key = '%cd')
1955 self.set_hook('complete_command', cd_completer, str_key = '%cd')
1956 self.set_hook('complete_command', reset_completer, str_key = '%reset')
1956 self.set_hook('complete_command', reset_completer, str_key = '%reset')
1957
1957
1958 # Only configure readline if we truly are using readline. IPython can
1958 # Only configure readline if we truly are using readline. IPython can
1959 # do tab-completion over the network, in GUIs, etc, where readline
1959 # do tab-completion over the network, in GUIs, etc, where readline
1960 # itself may be absent
1960 # itself may be absent
1961 if self.has_readline:
1961 if self.has_readline:
1962 self.set_readline_completer()
1962 self.set_readline_completer()
1963
1963
1964 def complete(self, text, line=None, cursor_pos=None):
1964 def complete(self, text, line=None, cursor_pos=None):
1965 """Return the completed text and a list of completions.
1965 """Return the completed text and a list of completions.
1966
1966
1967 Parameters
1967 Parameters
1968 ----------
1968 ----------
1969
1969
1970 text : string
1970 text : string
1971 A string of text to be completed on. It can be given as empty and
1971 A string of text to be completed on. It can be given as empty and
1972 instead a line/position pair are given. In this case, the
1972 instead a line/position pair are given. In this case, the
1973 completer itself will split the line like readline does.
1973 completer itself will split the line like readline does.
1974
1974
1975 line : string, optional
1975 line : string, optional
1976 The complete line that text is part of.
1976 The complete line that text is part of.
1977
1977
1978 cursor_pos : int, optional
1978 cursor_pos : int, optional
1979 The position of the cursor on the input line.
1979 The position of the cursor on the input line.
1980
1980
1981 Returns
1981 Returns
1982 -------
1982 -------
1983 text : string
1983 text : string
1984 The actual text that was completed.
1984 The actual text that was completed.
1985
1985
1986 matches : list
1986 matches : list
1987 A sorted list with all possible completions.
1987 A sorted list with all possible completions.
1988
1988
1989 The optional arguments allow the completion to take more context into
1989 The optional arguments allow the completion to take more context into
1990 account, and are part of the low-level completion API.
1990 account, and are part of the low-level completion API.
1991
1991
1992 This is a wrapper around the completion mechanism, similar to what
1992 This is a wrapper around the completion mechanism, similar to what
1993 readline does at the command line when the TAB key is hit. By
1993 readline does at the command line when the TAB key is hit. By
1994 exposing it as a method, it can be used by other non-readline
1994 exposing it as a method, it can be used by other non-readline
1995 environments (such as GUIs) for text completion.
1995 environments (such as GUIs) for text completion.
1996
1996
1997 Simple usage example:
1997 Simple usage example:
1998
1998
1999 In [1]: x = 'hello'
1999 In [1]: x = 'hello'
2000
2000
2001 In [2]: _ip.complete('x.l')
2001 In [2]: _ip.complete('x.l')
2002 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2002 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2003 """
2003 """
2004
2004
2005 # Inject names into __builtin__ so we can complete on the added names.
2005 # Inject names into __builtin__ so we can complete on the added names.
2006 with self.builtin_trap:
2006 with self.builtin_trap:
2007 return self.Completer.complete(text, line, cursor_pos)
2007 return self.Completer.complete(text, line, cursor_pos)
2008
2008
2009 def set_custom_completer(self, completer, pos=0):
2009 def set_custom_completer(self, completer, pos=0):
2010 """Adds a new custom completer function.
2010 """Adds a new custom completer function.
2011
2011
2012 The position argument (defaults to 0) is the index in the completers
2012 The position argument (defaults to 0) is the index in the completers
2013 list where you want the completer to be inserted."""
2013 list where you want the completer to be inserted."""
2014
2014
2015 newcomp = types.MethodType(completer,self.Completer)
2015 newcomp = types.MethodType(completer,self.Completer)
2016 self.Completer.matchers.insert(pos,newcomp)
2016 self.Completer.matchers.insert(pos,newcomp)
2017
2017
2018 def set_readline_completer(self):
2018 def set_readline_completer(self):
2019 """Reset readline's completer to be our own."""
2019 """Reset readline's completer to be our own."""
2020 self.readline.set_completer(self.Completer.rlcomplete)
2020 self.readline.set_completer(self.Completer.rlcomplete)
2021
2021
2022 def set_completer_frame(self, frame=None):
2022 def set_completer_frame(self, frame=None):
2023 """Set the frame of the completer."""
2023 """Set the frame of the completer."""
2024 if frame:
2024 if frame:
2025 self.Completer.namespace = frame.f_locals
2025 self.Completer.namespace = frame.f_locals
2026 self.Completer.global_namespace = frame.f_globals
2026 self.Completer.global_namespace = frame.f_globals
2027 else:
2027 else:
2028 self.Completer.namespace = self.user_ns
2028 self.Completer.namespace = self.user_ns
2029 self.Completer.global_namespace = self.user_global_ns
2029 self.Completer.global_namespace = self.user_global_ns
2030
2030
2031 #-------------------------------------------------------------------------
2031 #-------------------------------------------------------------------------
2032 # Things related to magics
2032 # Things related to magics
2033 #-------------------------------------------------------------------------
2033 #-------------------------------------------------------------------------
2034
2034
2035 def init_magics(self):
2035 def init_magics(self):
2036 from IPython.core import magics as m
2036 from IPython.core import magics as m
2037 self.magics_manager = magic.MagicsManager(shell=self,
2037 self.magics_manager = magic.MagicsManager(shell=self,
2038 parent=self,
2038 parent=self,
2039 user_magics=m.UserMagics(self))
2039 user_magics=m.UserMagics(self))
2040 self.configurables.append(self.magics_manager)
2040 self.configurables.append(self.magics_manager)
2041
2041
2042 # Expose as public API from the magics manager
2042 # Expose as public API from the magics manager
2043 self.register_magics = self.magics_manager.register
2043 self.register_magics = self.magics_manager.register
2044 self.define_magic = self.magics_manager.define_magic
2044 self.define_magic = self.magics_manager.define_magic
2045
2045
2046 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2046 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2047 m.ConfigMagics, m.DeprecatedMagics, m.DisplayMagics, m.ExecutionMagics,
2047 m.ConfigMagics, m.DeprecatedMagics, m.DisplayMagics, m.ExecutionMagics,
2048 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2048 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2049 m.NamespaceMagics, m.OSMagics, m.PylabMagics, m.ScriptMagics,
2049 m.NamespaceMagics, m.OSMagics, m.PylabMagics, m.ScriptMagics,
2050 )
2050 )
2051
2051
2052 # Register Magic Aliases
2052 # Register Magic Aliases
2053 mman = self.magics_manager
2053 mman = self.magics_manager
2054 # FIXME: magic aliases should be defined by the Magics classes
2054 # FIXME: magic aliases should be defined by the Magics classes
2055 # or in MagicsManager, not here
2055 # or in MagicsManager, not here
2056 mman.register_alias('ed', 'edit')
2056 mman.register_alias('ed', 'edit')
2057 mman.register_alias('hist', 'history')
2057 mman.register_alias('hist', 'history')
2058 mman.register_alias('rep', 'recall')
2058 mman.register_alias('rep', 'recall')
2059 mman.register_alias('SVG', 'svg', 'cell')
2059 mman.register_alias('SVG', 'svg', 'cell')
2060 mman.register_alias('HTML', 'html', 'cell')
2060 mman.register_alias('HTML', 'html', 'cell')
2061 mman.register_alias('file', 'writefile', 'cell')
2061 mman.register_alias('file', 'writefile', 'cell')
2062
2062
2063 # FIXME: Move the color initialization to the DisplayHook, which
2063 # FIXME: Move the color initialization to the DisplayHook, which
2064 # should be split into a prompt manager and displayhook. We probably
2064 # should be split into a prompt manager and displayhook. We probably
2065 # even need a centralize colors management object.
2065 # even need a centralize colors management object.
2066 self.magic('colors %s' % self.colors)
2066 self.magic('colors %s' % self.colors)
2067
2067
2068 # Defined here so that it's included in the documentation
2068 # Defined here so that it's included in the documentation
2069 @functools.wraps(magic.MagicsManager.register_function)
2069 @functools.wraps(magic.MagicsManager.register_function)
2070 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2070 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2071 self.magics_manager.register_function(func,
2071 self.magics_manager.register_function(func,
2072 magic_kind=magic_kind, magic_name=magic_name)
2072 magic_kind=magic_kind, magic_name=magic_name)
2073
2073
2074 def run_line_magic(self, magic_name, line):
2074 def run_line_magic(self, magic_name, line):
2075 """Execute the given line magic.
2075 """Execute the given line magic.
2076
2076
2077 Parameters
2077 Parameters
2078 ----------
2078 ----------
2079 magic_name : str
2079 magic_name : str
2080 Name of the desired magic function, without '%' prefix.
2080 Name of the desired magic function, without '%' prefix.
2081
2081
2082 line : str
2082 line : str
2083 The rest of the input line as a single string.
2083 The rest of the input line as a single string.
2084 """
2084 """
2085 fn = self.find_line_magic(magic_name)
2085 fn = self.find_line_magic(magic_name)
2086 if fn is None:
2086 if fn is None:
2087 cm = self.find_cell_magic(magic_name)
2087 cm = self.find_cell_magic(magic_name)
2088 etpl = "Line magic function `%%%s` not found%s."
2088 etpl = "Line magic function `%%%s` not found%s."
2089 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2089 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2090 'did you mean that instead?)' % magic_name )
2090 'did you mean that instead?)' % magic_name )
2091 error(etpl % (magic_name, extra))
2091 error(etpl % (magic_name, extra))
2092 else:
2092 else:
2093 # Note: this is the distance in the stack to the user's frame.
2093 # Note: this is the distance in the stack to the user's frame.
2094 # This will need to be updated if the internal calling logic gets
2094 # This will need to be updated if the internal calling logic gets
2095 # refactored, or else we'll be expanding the wrong variables.
2095 # refactored, or else we'll be expanding the wrong variables.
2096 stack_depth = 2
2096 stack_depth = 2
2097 magic_arg_s = self.var_expand(line, stack_depth)
2097 magic_arg_s = self.var_expand(line, stack_depth)
2098 # Put magic args in a list so we can call with f(*a) syntax
2098 # Put magic args in a list so we can call with f(*a) syntax
2099 args = [magic_arg_s]
2099 args = [magic_arg_s]
2100 kwargs = {}
2100 kwargs = {}
2101 # Grab local namespace if we need it:
2101 # Grab local namespace if we need it:
2102 if getattr(fn, "needs_local_scope", False):
2102 if getattr(fn, "needs_local_scope", False):
2103 kwargs['local_ns'] = sys._getframe(stack_depth).f_locals
2103 kwargs['local_ns'] = sys._getframe(stack_depth).f_locals
2104 with self.builtin_trap:
2104 with self.builtin_trap:
2105 result = fn(*args,**kwargs)
2105 result = fn(*args,**kwargs)
2106 return result
2106 return result
2107
2107
2108 def run_cell_magic(self, magic_name, line, cell):
2108 def run_cell_magic(self, magic_name, line, cell):
2109 """Execute the given cell magic.
2109 """Execute the given cell magic.
2110
2110
2111 Parameters
2111 Parameters
2112 ----------
2112 ----------
2113 magic_name : str
2113 magic_name : str
2114 Name of the desired magic function, without '%' prefix.
2114 Name of the desired magic function, without '%' prefix.
2115
2115
2116 line : str
2116 line : str
2117 The rest of the first input line as a single string.
2117 The rest of the first input line as a single string.
2118
2118
2119 cell : str
2119 cell : str
2120 The body of the cell as a (possibly multiline) string.
2120 The body of the cell as a (possibly multiline) string.
2121 """
2121 """
2122 fn = self.find_cell_magic(magic_name)
2122 fn = self.find_cell_magic(magic_name)
2123 if fn is None:
2123 if fn is None:
2124 lm = self.find_line_magic(magic_name)
2124 lm = self.find_line_magic(magic_name)
2125 etpl = "Cell magic `%%{0}` not found{1}."
2125 etpl = "Cell magic `%%{0}` not found{1}."
2126 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2126 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2127 'did you mean that instead?)'.format(magic_name))
2127 'did you mean that instead?)'.format(magic_name))
2128 error(etpl.format(magic_name, extra))
2128 error(etpl.format(magic_name, extra))
2129 elif cell == '':
2129 elif cell == '':
2130 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2130 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2131 if self.find_line_magic(magic_name) is not None:
2131 if self.find_line_magic(magic_name) is not None:
2132 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2132 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2133 raise UsageError(message)
2133 raise UsageError(message)
2134 else:
2134 else:
2135 # Note: this is the distance in the stack to the user's frame.
2135 # Note: this is the distance in the stack to the user's frame.
2136 # This will need to be updated if the internal calling logic gets
2136 # This will need to be updated if the internal calling logic gets
2137 # refactored, or else we'll be expanding the wrong variables.
2137 # refactored, or else we'll be expanding the wrong variables.
2138 stack_depth = 2
2138 stack_depth = 2
2139 magic_arg_s = self.var_expand(line, stack_depth)
2139 magic_arg_s = self.var_expand(line, stack_depth)
2140 with self.builtin_trap:
2140 with self.builtin_trap:
2141 result = fn(magic_arg_s, cell)
2141 result = fn(magic_arg_s, cell)
2142 return result
2142 return result
2143
2143
2144 def find_line_magic(self, magic_name):
2144 def find_line_magic(self, magic_name):
2145 """Find and return a line magic by name.
2145 """Find and return a line magic by name.
2146
2146
2147 Returns None if the magic isn't found."""
2147 Returns None if the magic isn't found."""
2148 return self.magics_manager.magics['line'].get(magic_name)
2148 return self.magics_manager.magics['line'].get(magic_name)
2149
2149
2150 def find_cell_magic(self, magic_name):
2150 def find_cell_magic(self, magic_name):
2151 """Find and return a cell magic by name.
2151 """Find and return a cell magic by name.
2152
2152
2153 Returns None if the magic isn't found."""
2153 Returns None if the magic isn't found."""
2154 return self.magics_manager.magics['cell'].get(magic_name)
2154 return self.magics_manager.magics['cell'].get(magic_name)
2155
2155
2156 def find_magic(self, magic_name, magic_kind='line'):
2156 def find_magic(self, magic_name, magic_kind='line'):
2157 """Find and return a magic of the given type by name.
2157 """Find and return a magic of the given type by name.
2158
2158
2159 Returns None if the magic isn't found."""
2159 Returns None if the magic isn't found."""
2160 return self.magics_manager.magics[magic_kind].get(magic_name)
2160 return self.magics_manager.magics[magic_kind].get(magic_name)
2161
2161
2162 def magic(self, arg_s):
2162 def magic(self, arg_s):
2163 """DEPRECATED. Use run_line_magic() instead.
2163 """DEPRECATED. Use run_line_magic() instead.
2164
2164
2165 Call a magic function by name.
2165 Call a magic function by name.
2166
2166
2167 Input: a string containing the name of the magic function to call and
2167 Input: a string containing the name of the magic function to call and
2168 any additional arguments to be passed to the magic.
2168 any additional arguments to be passed to the magic.
2169
2169
2170 magic('name -opt foo bar') is equivalent to typing at the ipython
2170 magic('name -opt foo bar') is equivalent to typing at the ipython
2171 prompt:
2171 prompt:
2172
2172
2173 In[1]: %name -opt foo bar
2173 In[1]: %name -opt foo bar
2174
2174
2175 To call a magic without arguments, simply use magic('name').
2175 To call a magic without arguments, simply use magic('name').
2176
2176
2177 This provides a proper Python function to call IPython's magics in any
2177 This provides a proper Python function to call IPython's magics in any
2178 valid Python code you can type at the interpreter, including loops and
2178 valid Python code you can type at the interpreter, including loops and
2179 compound statements.
2179 compound statements.
2180 """
2180 """
2181 # TODO: should we issue a loud deprecation warning here?
2181 # TODO: should we issue a loud deprecation warning here?
2182 magic_name, _, magic_arg_s = arg_s.partition(' ')
2182 magic_name, _, magic_arg_s = arg_s.partition(' ')
2183 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2183 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2184 return self.run_line_magic(magic_name, magic_arg_s)
2184 return self.run_line_magic(magic_name, magic_arg_s)
2185
2185
2186 #-------------------------------------------------------------------------
2186 #-------------------------------------------------------------------------
2187 # Things related to macros
2187 # Things related to macros
2188 #-------------------------------------------------------------------------
2188 #-------------------------------------------------------------------------
2189
2189
2190 def define_macro(self, name, themacro):
2190 def define_macro(self, name, themacro):
2191 """Define a new macro
2191 """Define a new macro
2192
2192
2193 Parameters
2193 Parameters
2194 ----------
2194 ----------
2195 name : str
2195 name : str
2196 The name of the macro.
2196 The name of the macro.
2197 themacro : str or Macro
2197 themacro : str or Macro
2198 The action to do upon invoking the macro. If a string, a new
2198 The action to do upon invoking the macro. If a string, a new
2199 Macro object is created by passing the string to it.
2199 Macro object is created by passing the string to it.
2200 """
2200 """
2201
2201
2202 from IPython.core import macro
2202 from IPython.core import macro
2203
2203
2204 if isinstance(themacro, string_types):
2204 if isinstance(themacro, string_types):
2205 themacro = macro.Macro(themacro)
2205 themacro = macro.Macro(themacro)
2206 if not isinstance(themacro, macro.Macro):
2206 if not isinstance(themacro, macro.Macro):
2207 raise ValueError('A macro must be a string or a Macro instance.')
2207 raise ValueError('A macro must be a string or a Macro instance.')
2208 self.user_ns[name] = themacro
2208 self.user_ns[name] = themacro
2209
2209
2210 #-------------------------------------------------------------------------
2210 #-------------------------------------------------------------------------
2211 # Things related to the running of system commands
2211 # Things related to the running of system commands
2212 #-------------------------------------------------------------------------
2212 #-------------------------------------------------------------------------
2213
2213
2214 def system_piped(self, cmd):
2214 def system_piped(self, cmd):
2215 """Call the given cmd in a subprocess, piping stdout/err
2215 """Call the given cmd in a subprocess, piping stdout/err
2216
2216
2217 Parameters
2217 Parameters
2218 ----------
2218 ----------
2219 cmd : str
2219 cmd : str
2220 Command to execute (can not end in '&', as background processes are
2220 Command to execute (can not end in '&', as background processes are
2221 not supported. Should not be a command that expects input
2221 not supported. Should not be a command that expects input
2222 other than simple text.
2222 other than simple text.
2223 """
2223 """
2224 if cmd.rstrip().endswith('&'):
2224 if cmd.rstrip().endswith('&'):
2225 # this is *far* from a rigorous test
2225 # this is *far* from a rigorous test
2226 # We do not support backgrounding processes because we either use
2226 # We do not support backgrounding processes because we either use
2227 # pexpect or pipes to read from. Users can always just call
2227 # pexpect or pipes to read from. Users can always just call
2228 # os.system() or use ip.system=ip.system_raw
2228 # os.system() or use ip.system=ip.system_raw
2229 # if they really want a background process.
2229 # if they really want a background process.
2230 raise OSError("Background processes not supported.")
2230 raise OSError("Background processes not supported.")
2231
2231
2232 # we explicitly do NOT return the subprocess status code, because
2232 # we explicitly do NOT return the subprocess status code, because
2233 # a non-None value would trigger :func:`sys.displayhook` calls.
2233 # a non-None value would trigger :func:`sys.displayhook` calls.
2234 # Instead, we store the exit_code in user_ns.
2234 # Instead, we store the exit_code in user_ns.
2235 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2235 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2236
2236
2237 def system_raw(self, cmd):
2237 def system_raw(self, cmd):
2238 """Call the given cmd in a subprocess using os.system on Windows or
2238 """Call the given cmd in a subprocess using os.system on Windows or
2239 subprocess.call using the system shell on other platforms.
2239 subprocess.call using the system shell on other platforms.
2240
2240
2241 Parameters
2241 Parameters
2242 ----------
2242 ----------
2243 cmd : str
2243 cmd : str
2244 Command to execute.
2244 Command to execute.
2245 """
2245 """
2246 cmd = self.var_expand(cmd, depth=1)
2246 cmd = self.var_expand(cmd, depth=1)
2247 # protect os.system from UNC paths on Windows, which it can't handle:
2247 # protect os.system from UNC paths on Windows, which it can't handle:
2248 if sys.platform == 'win32':
2248 if sys.platform == 'win32':
2249 from IPython.utils._process_win32 import AvoidUNCPath
2249 from IPython.utils._process_win32 import AvoidUNCPath
2250 with AvoidUNCPath() as path:
2250 with AvoidUNCPath() as path:
2251 if path is not None:
2251 if path is not None:
2252 cmd = '"pushd %s &&"%s' % (path, cmd)
2252 cmd = '"pushd %s &&"%s' % (path, cmd)
2253 cmd = py3compat.unicode_to_str(cmd)
2253 cmd = py3compat.unicode_to_str(cmd)
2254 ec = os.system(cmd)
2254 ec = os.system(cmd)
2255 else:
2255 else:
2256 cmd = py3compat.unicode_to_str(cmd)
2256 cmd = py3compat.unicode_to_str(cmd)
2257 # Call the cmd using the OS shell, instead of the default /bin/sh, if set.
2257 # Call the cmd using the OS shell, instead of the default /bin/sh, if set.
2258 ec = subprocess.call(cmd, shell=True, executable=os.environ.get('SHELL', None))
2258 ec = subprocess.call(cmd, shell=True, executable=os.environ.get('SHELL', None))
2259 # exit code is positive for program failure, or negative for
2259 # exit code is positive for program failure, or negative for
2260 # terminating signal number.
2260 # terminating signal number.
2261
2261
2262 # We explicitly do NOT return the subprocess status code, because
2262 # We explicitly do NOT return the subprocess status code, because
2263 # a non-None value would trigger :func:`sys.displayhook` calls.
2263 # a non-None value would trigger :func:`sys.displayhook` calls.
2264 # Instead, we store the exit_code in user_ns.
2264 # Instead, we store the exit_code in user_ns.
2265 self.user_ns['_exit_code'] = ec
2265 self.user_ns['_exit_code'] = ec
2266
2266
2267 # use piped system by default, because it is better behaved
2267 # use piped system by default, because it is better behaved
2268 system = system_piped
2268 system = system_piped
2269
2269
2270 def getoutput(self, cmd, split=True, depth=0):
2270 def getoutput(self, cmd, split=True, depth=0):
2271 """Get output (possibly including stderr) from a subprocess.
2271 """Get output (possibly including stderr) from a subprocess.
2272
2272
2273 Parameters
2273 Parameters
2274 ----------
2274 ----------
2275 cmd : str
2275 cmd : str
2276 Command to execute (can not end in '&', as background processes are
2276 Command to execute (can not end in '&', as background processes are
2277 not supported.
2277 not supported.
2278 split : bool, optional
2278 split : bool, optional
2279 If True, split the output into an IPython SList. Otherwise, an
2279 If True, split the output into an IPython SList. Otherwise, an
2280 IPython LSString is returned. These are objects similar to normal
2280 IPython LSString is returned. These are objects similar to normal
2281 lists and strings, with a few convenience attributes for easier
2281 lists and strings, with a few convenience attributes for easier
2282 manipulation of line-based output. You can use '?' on them for
2282 manipulation of line-based output. You can use '?' on them for
2283 details.
2283 details.
2284 depth : int, optional
2284 depth : int, optional
2285 How many frames above the caller are the local variables which should
2285 How many frames above the caller are the local variables which should
2286 be expanded in the command string? The default (0) assumes that the
2286 be expanded in the command string? The default (0) assumes that the
2287 expansion variables are in the stack frame calling this function.
2287 expansion variables are in the stack frame calling this function.
2288 """
2288 """
2289 if cmd.rstrip().endswith('&'):
2289 if cmd.rstrip().endswith('&'):
2290 # this is *far* from a rigorous test
2290 # this is *far* from a rigorous test
2291 raise OSError("Background processes not supported.")
2291 raise OSError("Background processes not supported.")
2292 out = getoutput(self.var_expand(cmd, depth=depth+1))
2292 out = getoutput(self.var_expand(cmd, depth=depth+1))
2293 if split:
2293 if split:
2294 out = SList(out.splitlines())
2294 out = SList(out.splitlines())
2295 else:
2295 else:
2296 out = LSString(out)
2296 out = LSString(out)
2297 return out
2297 return out
2298
2298
2299 #-------------------------------------------------------------------------
2299 #-------------------------------------------------------------------------
2300 # Things related to aliases
2300 # Things related to aliases
2301 #-------------------------------------------------------------------------
2301 #-------------------------------------------------------------------------
2302
2302
2303 def init_alias(self):
2303 def init_alias(self):
2304 self.alias_manager = AliasManager(shell=self, parent=self)
2304 self.alias_manager = AliasManager(shell=self, parent=self)
2305 self.configurables.append(self.alias_manager)
2305 self.configurables.append(self.alias_manager)
2306
2306
2307 #-------------------------------------------------------------------------
2307 #-------------------------------------------------------------------------
2308 # Things related to extensions
2308 # Things related to extensions
2309 #-------------------------------------------------------------------------
2309 #-------------------------------------------------------------------------
2310
2310
2311 def init_extension_manager(self):
2311 def init_extension_manager(self):
2312 self.extension_manager = ExtensionManager(shell=self, parent=self)
2312 self.extension_manager = ExtensionManager(shell=self, parent=self)
2313 self.configurables.append(self.extension_manager)
2313 self.configurables.append(self.extension_manager)
2314
2314
2315 #-------------------------------------------------------------------------
2315 #-------------------------------------------------------------------------
2316 # Things related to payloads
2316 # Things related to payloads
2317 #-------------------------------------------------------------------------
2317 #-------------------------------------------------------------------------
2318
2318
2319 def init_payload(self):
2319 def init_payload(self):
2320 self.payload_manager = PayloadManager(parent=self)
2320 self.payload_manager = PayloadManager(parent=self)
2321 self.configurables.append(self.payload_manager)
2321 self.configurables.append(self.payload_manager)
2322
2322
2323 #-------------------------------------------------------------------------
2323 #-------------------------------------------------------------------------
2324 # Things related to widgets
2324 # Things related to widgets
2325 #-------------------------------------------------------------------------
2325 #-------------------------------------------------------------------------
2326
2326
2327 def init_comms(self):
2327 def init_comms(self):
2328 # not implemented in the base class
2328 # not implemented in the base class
2329 pass
2329 pass
2330
2330
2331 #-------------------------------------------------------------------------
2331 #-------------------------------------------------------------------------
2332 # Things related to the prefilter
2332 # Things related to the prefilter
2333 #-------------------------------------------------------------------------
2333 #-------------------------------------------------------------------------
2334
2334
2335 def init_prefilter(self):
2335 def init_prefilter(self):
2336 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2336 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2337 self.configurables.append(self.prefilter_manager)
2337 self.configurables.append(self.prefilter_manager)
2338 # Ultimately this will be refactored in the new interpreter code, but
2338 # Ultimately this will be refactored in the new interpreter code, but
2339 # for now, we should expose the main prefilter method (there's legacy
2339 # for now, we should expose the main prefilter method (there's legacy
2340 # code out there that may rely on this).
2340 # code out there that may rely on this).
2341 self.prefilter = self.prefilter_manager.prefilter_lines
2341 self.prefilter = self.prefilter_manager.prefilter_lines
2342
2342
2343 def auto_rewrite_input(self, cmd):
2343 def auto_rewrite_input(self, cmd):
2344 """Print to the screen the rewritten form of the user's command.
2344 """Print to the screen the rewritten form of the user's command.
2345
2345
2346 This shows visual feedback by rewriting input lines that cause
2346 This shows visual feedback by rewriting input lines that cause
2347 automatic calling to kick in, like::
2347 automatic calling to kick in, like::
2348
2348
2349 /f x
2349 /f x
2350
2350
2351 into::
2351 into::
2352
2352
2353 ------> f(x)
2353 ------> f(x)
2354
2354
2355 after the user's input prompt. This helps the user understand that the
2355 after the user's input prompt. This helps the user understand that the
2356 input line was transformed automatically by IPython.
2356 input line was transformed automatically by IPython.
2357 """
2357 """
2358 if not self.show_rewritten_input:
2358 if not self.show_rewritten_input:
2359 return
2359 return
2360
2360
2361 rw = self.prompt_manager.render('rewrite') + cmd
2361 rw = self.prompt_manager.render('rewrite') + cmd
2362
2362
2363 try:
2363 try:
2364 # plain ascii works better w/ pyreadline, on some machines, so
2364 # plain ascii works better w/ pyreadline, on some machines, so
2365 # we use it and only print uncolored rewrite if we have unicode
2365 # we use it and only print uncolored rewrite if we have unicode
2366 rw = str(rw)
2366 rw = str(rw)
2367 print(rw, file=io.stdout)
2367 print(rw, file=io.stdout)
2368 except UnicodeEncodeError:
2368 except UnicodeEncodeError:
2369 print("------> " + cmd)
2369 print("------> " + cmd)
2370
2370
2371 #-------------------------------------------------------------------------
2371 #-------------------------------------------------------------------------
2372 # Things related to extracting values/expressions from kernel and user_ns
2372 # Things related to extracting values/expressions from kernel and user_ns
2373 #-------------------------------------------------------------------------
2373 #-------------------------------------------------------------------------
2374
2374
2375 def _user_obj_error(self):
2375 def _user_obj_error(self):
2376 """return simple exception dict
2376 """return simple exception dict
2377
2377
2378 for use in user_variables / expressions
2378 for use in user_variables / expressions
2379 """
2379 """
2380
2380
2381 etype, evalue, tb = self._get_exc_info()
2381 etype, evalue, tb = self._get_exc_info()
2382 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2382 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2383
2383
2384 exc_info = {
2384 exc_info = {
2385 u'status' : 'error',
2385 u'status' : 'error',
2386 u'traceback' : stb,
2386 u'traceback' : stb,
2387 u'ename' : unicode_type(etype.__name__),
2387 u'ename' : unicode_type(etype.__name__),
2388 u'evalue' : py3compat.safe_unicode(evalue),
2388 u'evalue' : py3compat.safe_unicode(evalue),
2389 }
2389 }
2390
2390
2391 return exc_info
2391 return exc_info
2392
2392
2393 def _format_user_obj(self, obj):
2393 def _format_user_obj(self, obj):
2394 """format a user object to display dict
2394 """format a user object to display dict
2395
2395
2396 for use in user_expressions / variables
2396 for use in user_expressions / variables
2397 """
2397 """
2398
2398
2399 data, md = self.display_formatter.format(obj)
2399 data, md = self.display_formatter.format(obj)
2400 value = {
2400 value = {
2401 'status' : 'ok',
2401 'status' : 'ok',
2402 'data' : data,
2402 'data' : data,
2403 'metadata' : md,
2403 'metadata' : md,
2404 }
2404 }
2405 return value
2405 return value
2406
2406
2407 def user_variables(self, names):
2407 def user_variables(self, names):
2408 """Get a list of variable names from the user's namespace.
2408 """Get a list of variable names from the user's namespace.
2409
2409
2410 Parameters
2410 Parameters
2411 ----------
2411 ----------
2412 names : list of strings
2412 names : list of strings
2413 A list of names of variables to be read from the user namespace.
2413 A list of names of variables to be read from the user namespace.
2414
2414
2415 Returns
2415 Returns
2416 -------
2416 -------
2417 A dict, keyed by the input names and with the rich mime-type repr(s) of each value.
2417 A dict, keyed by the input names and with the rich mime-type repr(s) of each value.
2418 Each element will be a sub-dict of the same form as a display_data message.
2418 Each element will be a sub-dict of the same form as a display_data message.
2419 """
2419 """
2420 out = {}
2420 out = {}
2421 user_ns = self.user_ns
2421 user_ns = self.user_ns
2422
2422
2423 for varname in names:
2423 for varname in names:
2424 try:
2424 try:
2425 value = self._format_user_obj(user_ns[varname])
2425 value = self._format_user_obj(user_ns[varname])
2426 except:
2426 except:
2427 value = self._user_obj_error()
2427 value = self._user_obj_error()
2428 out[varname] = value
2428 out[varname] = value
2429 return out
2429 return out
2430
2430
2431 def user_expressions(self, expressions):
2431 def user_expressions(self, expressions):
2432 """Evaluate a dict of expressions in the user's namespace.
2432 """Evaluate a dict of expressions in the user's namespace.
2433
2433
2434 Parameters
2434 Parameters
2435 ----------
2435 ----------
2436 expressions : dict
2436 expressions : dict
2437 A dict with string keys and string values. The expression values
2437 A dict with string keys and string values. The expression values
2438 should be valid Python expressions, each of which will be evaluated
2438 should be valid Python expressions, each of which will be evaluated
2439 in the user namespace.
2439 in the user namespace.
2440
2440
2441 Returns
2441 Returns
2442 -------
2442 -------
2443 A dict, keyed like the input expressions dict, with the rich mime-typed
2443 A dict, keyed like the input expressions dict, with the rich mime-typed
2444 display_data of each value.
2444 display_data of each value.
2445 """
2445 """
2446 out = {}
2446 out = {}
2447 user_ns = self.user_ns
2447 user_ns = self.user_ns
2448 global_ns = self.user_global_ns
2448 global_ns = self.user_global_ns
2449
2449
2450 for key, expr in iteritems(expressions):
2450 for key, expr in iteritems(expressions):
2451 try:
2451 try:
2452 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2452 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2453 except:
2453 except:
2454 value = self._user_obj_error()
2454 value = self._user_obj_error()
2455 out[key] = value
2455 out[key] = value
2456 return out
2456 return out
2457
2457
2458 #-------------------------------------------------------------------------
2458 #-------------------------------------------------------------------------
2459 # Things related to the running of code
2459 # Things related to the running of code
2460 #-------------------------------------------------------------------------
2460 #-------------------------------------------------------------------------
2461
2461
2462 def ex(self, cmd):
2462 def ex(self, cmd):
2463 """Execute a normal python statement in user namespace."""
2463 """Execute a normal python statement in user namespace."""
2464 with self.builtin_trap:
2464 with self.builtin_trap:
2465 exec(cmd, self.user_global_ns, self.user_ns)
2465 exec(cmd, self.user_global_ns, self.user_ns)
2466
2466
2467 def ev(self, expr):
2467 def ev(self, expr):
2468 """Evaluate python expression expr in user namespace.
2468 """Evaluate python expression expr in user namespace.
2469
2469
2470 Returns the result of evaluation
2470 Returns the result of evaluation
2471 """
2471 """
2472 with self.builtin_trap:
2472 with self.builtin_trap:
2473 return eval(expr, self.user_global_ns, self.user_ns)
2473 return eval(expr, self.user_global_ns, self.user_ns)
2474
2474
2475 def safe_execfile(self, fname, *where, **kw):
2475 def safe_execfile(self, fname, *where, **kw):
2476 """A safe version of the builtin execfile().
2476 """A safe version of the builtin execfile().
2477
2477
2478 This version will never throw an exception, but instead print
2478 This version will never throw an exception, but instead print
2479 helpful error messages to the screen. This only works on pure
2479 helpful error messages to the screen. This only works on pure
2480 Python files with the .py extension.
2480 Python files with the .py extension.
2481
2481
2482 Parameters
2482 Parameters
2483 ----------
2483 ----------
2484 fname : string
2484 fname : string
2485 The name of the file to be executed.
2485 The name of the file to be executed.
2486 where : tuple
2486 where : tuple
2487 One or two namespaces, passed to execfile() as (globals,locals).
2487 One or two namespaces, passed to execfile() as (globals,locals).
2488 If only one is given, it is passed as both.
2488 If only one is given, it is passed as both.
2489 exit_ignore : bool (False)
2489 exit_ignore : bool (False)
2490 If True, then silence SystemExit for non-zero status (it is always
2490 If True, then silence SystemExit for non-zero status (it is always
2491 silenced for zero status, as it is so common).
2491 silenced for zero status, as it is so common).
2492 raise_exceptions : bool (False)
2492 raise_exceptions : bool (False)
2493 If True raise exceptions everywhere. Meant for testing.
2493 If True raise exceptions everywhere. Meant for testing.
2494
2494
2495 """
2495 """
2496 kw.setdefault('exit_ignore', False)
2496 kw.setdefault('exit_ignore', False)
2497 kw.setdefault('raise_exceptions', False)
2497 kw.setdefault('raise_exceptions', False)
2498
2498
2499 fname = os.path.abspath(os.path.expanduser(fname))
2499 fname = os.path.abspath(os.path.expanduser(fname))
2500
2500
2501 # Make sure we can open the file
2501 # Make sure we can open the file
2502 try:
2502 try:
2503 with open(fname) as thefile:
2503 with open(fname) as thefile:
2504 pass
2504 pass
2505 except:
2505 except:
2506 warn('Could not open file <%s> for safe execution.' % fname)
2506 warn('Could not open file <%s> for safe execution.' % fname)
2507 return
2507 return
2508
2508
2509 # Find things also in current directory. This is needed to mimic the
2509 # Find things also in current directory. This is needed to mimic the
2510 # behavior of running a script from the system command line, where
2510 # behavior of running a script from the system command line, where
2511 # Python inserts the script's directory into sys.path
2511 # Python inserts the script's directory into sys.path
2512 dname = os.path.dirname(fname)
2512 dname = os.path.dirname(fname)
2513
2513
2514 with prepended_to_syspath(dname):
2514 with prepended_to_syspath(dname):
2515 try:
2515 try:
2516 py3compat.execfile(fname,*where)
2516 py3compat.execfile(fname,*where)
2517 except SystemExit as status:
2517 except SystemExit as status:
2518 # If the call was made with 0 or None exit status (sys.exit(0)
2518 # If the call was made with 0 or None exit status (sys.exit(0)
2519 # or sys.exit() ), don't bother showing a traceback, as both of
2519 # or sys.exit() ), don't bother showing a traceback, as both of
2520 # these are considered normal by the OS:
2520 # these are considered normal by the OS:
2521 # > python -c'import sys;sys.exit(0)'; echo $?
2521 # > python -c'import sys;sys.exit(0)'; echo $?
2522 # 0
2522 # 0
2523 # > python -c'import sys;sys.exit()'; echo $?
2523 # > python -c'import sys;sys.exit()'; echo $?
2524 # 0
2524 # 0
2525 # For other exit status, we show the exception unless
2525 # For other exit status, we show the exception unless
2526 # explicitly silenced, but only in short form.
2526 # explicitly silenced, but only in short form.
2527 if kw['raise_exceptions']:
2527 if kw['raise_exceptions']:
2528 raise
2528 raise
2529 if status.code and not kw['exit_ignore']:
2529 if status.code and not kw['exit_ignore']:
2530 self.showtraceback(exception_only=True)
2530 self.showtraceback(exception_only=True)
2531 except:
2531 except:
2532 if kw['raise_exceptions']:
2532 if kw['raise_exceptions']:
2533 raise
2533 raise
2534 self.showtraceback()
2534 self.showtraceback()
2535
2535
2536 def safe_execfile_ipy(self, fname):
2536 def safe_execfile_ipy(self, fname):
2537 """Like safe_execfile, but for .ipy files with IPython syntax.
2537 """Like safe_execfile, but for .ipy files with IPython syntax.
2538
2538
2539 Parameters
2539 Parameters
2540 ----------
2540 ----------
2541 fname : str
2541 fname : str
2542 The name of the file to execute. The filename must have a
2542 The name of the file to execute. The filename must have a
2543 .ipy extension.
2543 .ipy extension.
2544 """
2544 """
2545 fname = os.path.abspath(os.path.expanduser(fname))
2545 fname = os.path.abspath(os.path.expanduser(fname))
2546
2546
2547 # Make sure we can open the file
2547 # Make sure we can open the file
2548 try:
2548 try:
2549 with open(fname) as thefile:
2549 with open(fname) as thefile:
2550 pass
2550 pass
2551 except:
2551 except:
2552 warn('Could not open file <%s> for safe execution.' % fname)
2552 warn('Could not open file <%s> for safe execution.' % fname)
2553 return
2553 return
2554
2554
2555 # Find things also in current directory. This is needed to mimic the
2555 # Find things also in current directory. This is needed to mimic the
2556 # behavior of running a script from the system command line, where
2556 # behavior of running a script from the system command line, where
2557 # Python inserts the script's directory into sys.path
2557 # Python inserts the script's directory into sys.path
2558 dname = os.path.dirname(fname)
2558 dname = os.path.dirname(fname)
2559
2559
2560 with prepended_to_syspath(dname):
2560 with prepended_to_syspath(dname):
2561 try:
2561 try:
2562 with open(fname) as thefile:
2562 with open(fname) as thefile:
2563 # self.run_cell currently captures all exceptions
2563 # self.run_cell currently captures all exceptions
2564 # raised in user code. It would be nice if there were
2564 # raised in user code. It would be nice if there were
2565 # versions of runlines, execfile that did raise, so
2565 # versions of runlines, execfile that did raise, so
2566 # we could catch the errors.
2566 # we could catch the errors.
2567 self.run_cell(thefile.read(), store_history=False, shell_futures=False)
2567 self.run_cell(thefile.read(), store_history=False, shell_futures=False)
2568 except:
2568 except:
2569 self.showtraceback()
2569 self.showtraceback()
2570 warn('Unknown failure executing file: <%s>' % fname)
2570 warn('Unknown failure executing file: <%s>' % fname)
2571
2571
2572 def safe_run_module(self, mod_name, where):
2572 def safe_run_module(self, mod_name, where):
2573 """A safe version of runpy.run_module().
2573 """A safe version of runpy.run_module().
2574
2574
2575 This version will never throw an exception, but instead print
2575 This version will never throw an exception, but instead print
2576 helpful error messages to the screen.
2576 helpful error messages to the screen.
2577
2577
2578 `SystemExit` exceptions with status code 0 or None are ignored.
2578 `SystemExit` exceptions with status code 0 or None are ignored.
2579
2579
2580 Parameters
2580 Parameters
2581 ----------
2581 ----------
2582 mod_name : string
2582 mod_name : string
2583 The name of the module to be executed.
2583 The name of the module to be executed.
2584 where : dict
2584 where : dict
2585 The globals namespace.
2585 The globals namespace.
2586 """
2586 """
2587 try:
2587 try:
2588 try:
2588 try:
2589 where.update(
2589 where.update(
2590 runpy.run_module(str(mod_name), run_name="__main__",
2590 runpy.run_module(str(mod_name), run_name="__main__",
2591 alter_sys=True)
2591 alter_sys=True)
2592 )
2592 )
2593 except SystemExit as status:
2593 except SystemExit as status:
2594 if status.code:
2594 if status.code:
2595 raise
2595 raise
2596 except:
2596 except:
2597 self.showtraceback()
2597 self.showtraceback()
2598 warn('Unknown failure executing module: <%s>' % mod_name)
2598 warn('Unknown failure executing module: <%s>' % mod_name)
2599
2599
2600 def _run_cached_cell_magic(self, magic_name, line):
2600 def _run_cached_cell_magic(self, magic_name, line):
2601 """Special method to call a cell magic with the data stored in self.
2601 """Special method to call a cell magic with the data stored in self.
2602 """
2602 """
2603 cell = self._current_cell_magic_body
2603 cell = self._current_cell_magic_body
2604 self._current_cell_magic_body = None
2604 self._current_cell_magic_body = None
2605 return self.run_cell_magic(magic_name, line, cell)
2605 return self.run_cell_magic(magic_name, line, cell)
2606
2606
2607 def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=True):
2607 def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=True):
2608 """Run a complete IPython cell.
2608 """Run a complete IPython cell.
2609
2609
2610 Parameters
2610 Parameters
2611 ----------
2611 ----------
2612 raw_cell : str
2612 raw_cell : str
2613 The code (including IPython code such as %magic functions) to run.
2613 The code (including IPython code such as %magic functions) to run.
2614 store_history : bool
2614 store_history : bool
2615 If True, the raw and translated cell will be stored in IPython's
2615 If True, the raw and translated cell will be stored in IPython's
2616 history. For user code calling back into IPython's machinery, this
2616 history. For user code calling back into IPython's machinery, this
2617 should be set to False.
2617 should be set to False.
2618 silent : bool
2618 silent : bool
2619 If True, avoid side-effects, such as implicit displayhooks and
2619 If True, avoid side-effects, such as implicit displayhooks and
2620 and logging. silent=True forces store_history=False.
2620 and logging. silent=True forces store_history=False.
2621 shell_futures : bool
2621 shell_futures : bool
2622 If True, the code will share future statements with the interactive
2622 If True, the code will share future statements with the interactive
2623 shell. It will both be affected by previous __future__ imports, and
2623 shell. It will both be affected by previous __future__ imports, and
2624 any __future__ imports in the code will affect the shell. If False,
2624 any __future__ imports in the code will affect the shell. If False,
2625 __future__ imports are not shared in either direction.
2625 __future__ imports are not shared in either direction.
2626 """
2626 """
2627 if (not raw_cell) or raw_cell.isspace():
2627 if (not raw_cell) or raw_cell.isspace():
2628 return
2628 return
2629
2629
2630 if silent:
2630 if silent:
2631 store_history = False
2631 store_history = False
2632
2632
2633 self.input_transformer_manager.push(raw_cell)
2633 self.input_transformer_manager.push(raw_cell)
2634 cell = self.input_transformer_manager.source_reset()
2634 cell = self.input_transformer_manager.source_reset()
2635
2635
2636 # Our own compiler remembers the __future__ environment. If we want to
2636 # Our own compiler remembers the __future__ environment. If we want to
2637 # run code with a separate __future__ environment, use the default
2637 # run code with a separate __future__ environment, use the default
2638 # compiler
2638 # compiler
2639 compiler = self.compile if shell_futures else CachingCompiler()
2639 compiler = self.compile if shell_futures else CachingCompiler()
2640
2640
2641 with self.builtin_trap:
2641 with self.builtin_trap:
2642 prefilter_failed = False
2642 prefilter_failed = False
2643 if len(cell.splitlines()) == 1:
2643 if len(cell.splitlines()) == 1:
2644 try:
2644 try:
2645 # use prefilter_lines to handle trailing newlines
2645 # use prefilter_lines to handle trailing newlines
2646 # restore trailing newline for ast.parse
2646 # restore trailing newline for ast.parse
2647 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
2647 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
2648 except AliasError as e:
2648 except AliasError as e:
2649 error(e)
2649 error(e)
2650 prefilter_failed = True
2650 prefilter_failed = True
2651 except Exception:
2651 except Exception:
2652 # don't allow prefilter errors to crash IPython
2652 # don't allow prefilter errors to crash IPython
2653 self.showtraceback()
2653 self.showtraceback()
2654 prefilter_failed = True
2654 prefilter_failed = True
2655
2655
2656 # Store raw and processed history
2656 # Store raw and processed history
2657 if store_history:
2657 if store_history:
2658 self.history_manager.store_inputs(self.execution_count,
2658 self.history_manager.store_inputs(self.execution_count,
2659 cell, raw_cell)
2659 cell, raw_cell)
2660 if not silent:
2660 if not silent:
2661 self.logger.log(cell, raw_cell)
2661 self.logger.log(cell, raw_cell)
2662
2662
2663 if not prefilter_failed:
2663 if not prefilter_failed:
2664 # don't run if prefilter failed
2664 # don't run if prefilter failed
2665 cell_name = self.compile.cache(cell, self.execution_count)
2665 cell_name = self.compile.cache(cell, self.execution_count)
2666
2666
2667 with self.display_trap:
2667 with self.display_trap:
2668 try:
2668 try:
2669 code_ast = compiler.ast_parse(cell, filename=cell_name)
2669 code_ast = compiler.ast_parse(cell, filename=cell_name)
2670 except IndentationError:
2670 except IndentationError:
2671 self.showindentationerror()
2671 self.showindentationerror()
2672 if store_history:
2672 if store_history:
2673 self.execution_count += 1
2673 self.execution_count += 1
2674 return None
2674 return None
2675 except (OverflowError, SyntaxError, ValueError, TypeError,
2675 except (OverflowError, SyntaxError, ValueError, TypeError,
2676 MemoryError):
2676 MemoryError):
2677 self.showsyntaxerror()
2677 self.showsyntaxerror()
2678 if store_history:
2678 if store_history:
2679 self.execution_count += 1
2679 self.execution_count += 1
2680 return None
2680 return None
2681
2681
2682 code_ast = self.transform_ast(code_ast)
2682 code_ast = self.transform_ast(code_ast)
2683
2683
2684 interactivity = "none" if silent else self.ast_node_interactivity
2684 interactivity = "none" if silent else self.ast_node_interactivity
2685 self.run_ast_nodes(code_ast.body, cell_name,
2685 self.run_ast_nodes(code_ast.body, cell_name,
2686 interactivity=interactivity, compiler=compiler)
2686 interactivity=interactivity, compiler=compiler)
2687
2687
2688 # Execute any registered post-execution functions.
2688 # Execute any registered post-execution functions.
2689 # unless we are silent
2689 # unless we are silent
2690 post_exec = [] if silent else iteritems(self._post_execute)
2690 post_exec = [] if silent else iteritems(self._post_execute)
2691
2691
2692 for func, status in post_exec:
2692 for func, status in post_exec:
2693 if self.disable_failing_post_execute and not status:
2693 if self.disable_failing_post_execute and not status:
2694 continue
2694 continue
2695 try:
2695 try:
2696 func()
2696 func()
2697 except KeyboardInterrupt:
2697 except KeyboardInterrupt:
2698 print("\nKeyboardInterrupt", file=io.stderr)
2698 print("\nKeyboardInterrupt", file=io.stderr)
2699 except Exception:
2699 except Exception:
2700 # register as failing:
2700 # register as failing:
2701 self._post_execute[func] = False
2701 self._post_execute[func] = False
2702 self.showtraceback()
2702 self.showtraceback()
2703 print('\n'.join([
2703 print('\n'.join([
2704 "post-execution function %r produced an error." % func,
2704 "post-execution function %r produced an error." % func,
2705 "If this problem persists, you can disable failing post-exec functions with:",
2705 "If this problem persists, you can disable failing post-exec functions with:",
2706 "",
2706 "",
2707 " get_ipython().disable_failing_post_execute = True"
2707 " get_ipython().disable_failing_post_execute = True"
2708 ]), file=io.stderr)
2708 ]), file=io.stderr)
2709
2709
2710 if store_history:
2710 if store_history:
2711 # Write output to the database. Does nothing unless
2711 # Write output to the database. Does nothing unless
2712 # history output logging is enabled.
2712 # history output logging is enabled.
2713 self.history_manager.store_output(self.execution_count)
2713 self.history_manager.store_output(self.execution_count)
2714 # Each cell is a *single* input, regardless of how many lines it has
2714 # Each cell is a *single* input, regardless of how many lines it has
2715 self.execution_count += 1
2715 self.execution_count += 1
2716
2716
2717 def transform_ast(self, node):
2717 def transform_ast(self, node):
2718 """Apply the AST transformations from self.ast_transformers
2718 """Apply the AST transformations from self.ast_transformers
2719
2719
2720 Parameters
2720 Parameters
2721 ----------
2721 ----------
2722 node : ast.Node
2722 node : ast.Node
2723 The root node to be transformed. Typically called with the ast.Module
2723 The root node to be transformed. Typically called with the ast.Module
2724 produced by parsing user input.
2724 produced by parsing user input.
2725
2725
2726 Returns
2726 Returns
2727 -------
2727 -------
2728 An ast.Node corresponding to the node it was called with. Note that it
2728 An ast.Node corresponding to the node it was called with. Note that it
2729 may also modify the passed object, so don't rely on references to the
2729 may also modify the passed object, so don't rely on references to the
2730 original AST.
2730 original AST.
2731 """
2731 """
2732 for transformer in self.ast_transformers:
2732 for transformer in self.ast_transformers:
2733 try:
2733 try:
2734 node = transformer.visit(node)
2734 node = transformer.visit(node)
2735 except Exception:
2735 except Exception:
2736 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
2736 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
2737 self.ast_transformers.remove(transformer)
2737 self.ast_transformers.remove(transformer)
2738
2738
2739 if self.ast_transformers:
2739 if self.ast_transformers:
2740 ast.fix_missing_locations(node)
2740 ast.fix_missing_locations(node)
2741 return node
2741 return node
2742
2742
2743
2743
2744 def run_ast_nodes(self, nodelist, cell_name, interactivity='last_expr',
2744 def run_ast_nodes(self, nodelist, cell_name, interactivity='last_expr',
2745 compiler=compile):
2745 compiler=compile):
2746 """Run a sequence of AST nodes. The execution mode depends on the
2746 """Run a sequence of AST nodes. The execution mode depends on the
2747 interactivity parameter.
2747 interactivity parameter.
2748
2748
2749 Parameters
2749 Parameters
2750 ----------
2750 ----------
2751 nodelist : list
2751 nodelist : list
2752 A sequence of AST nodes to run.
2752 A sequence of AST nodes to run.
2753 cell_name : str
2753 cell_name : str
2754 Will be passed to the compiler as the filename of the cell. Typically
2754 Will be passed to the compiler as the filename of the cell. Typically
2755 the value returned by ip.compile.cache(cell).
2755 the value returned by ip.compile.cache(cell).
2756 interactivity : str
2756 interactivity : str
2757 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
2757 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
2758 run interactively (displaying output from expressions). 'last_expr'
2758 run interactively (displaying output from expressions). 'last_expr'
2759 will run the last node interactively only if it is an expression (i.e.
2759 will run the last node interactively only if it is an expression (i.e.
2760 expressions in loops or other blocks are not displayed. Other values
2760 expressions in loops or other blocks are not displayed. Other values
2761 for this parameter will raise a ValueError.
2761 for this parameter will raise a ValueError.
2762 compiler : callable
2762 compiler : callable
2763 A function with the same interface as the built-in compile(), to turn
2763 A function with the same interface as the built-in compile(), to turn
2764 the AST nodes into code objects. Default is the built-in compile().
2764 the AST nodes into code objects. Default is the built-in compile().
2765 """
2765 """
2766 if not nodelist:
2766 if not nodelist:
2767 return
2767 return
2768
2768
2769 if interactivity == 'last_expr':
2769 if interactivity == 'last_expr':
2770 if isinstance(nodelist[-1], ast.Expr):
2770 if isinstance(nodelist[-1], ast.Expr):
2771 interactivity = "last"
2771 interactivity = "last"
2772 else:
2772 else:
2773 interactivity = "none"
2773 interactivity = "none"
2774
2774
2775 if interactivity == 'none':
2775 if interactivity == 'none':
2776 to_run_exec, to_run_interactive = nodelist, []
2776 to_run_exec, to_run_interactive = nodelist, []
2777 elif interactivity == 'last':
2777 elif interactivity == 'last':
2778 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
2778 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
2779 elif interactivity == 'all':
2779 elif interactivity == 'all':
2780 to_run_exec, to_run_interactive = [], nodelist
2780 to_run_exec, to_run_interactive = [], nodelist
2781 else:
2781 else:
2782 raise ValueError("Interactivity was %r" % interactivity)
2782 raise ValueError("Interactivity was %r" % interactivity)
2783
2783
2784 exec_count = self.execution_count
2784 exec_count = self.execution_count
2785
2785
2786 try:
2786 try:
2787 for i, node in enumerate(to_run_exec):
2787 for i, node in enumerate(to_run_exec):
2788 mod = ast.Module([node])
2788 mod = ast.Module([node])
2789 code = compiler(mod, cell_name, "exec")
2789 code = compiler(mod, cell_name, "exec")
2790 if self.run_code(code):
2790 if self.run_code(code):
2791 return True
2791 return True
2792
2792
2793 for i, node in enumerate(to_run_interactive):
2793 for i, node in enumerate(to_run_interactive):
2794 mod = ast.Interactive([node])
2794 mod = ast.Interactive([node])
2795 code = compiler(mod, cell_name, "single")
2795 code = compiler(mod, cell_name, "single")
2796 if self.run_code(code):
2796 if self.run_code(code):
2797 return True
2797 return True
2798
2798
2799 # Flush softspace
2799 # Flush softspace
2800 if softspace(sys.stdout, 0):
2800 if softspace(sys.stdout, 0):
2801 print()
2801 print()
2802
2802
2803 except:
2803 except:
2804 # It's possible to have exceptions raised here, typically by
2804 # It's possible to have exceptions raised here, typically by
2805 # compilation of odd code (such as a naked 'return' outside a
2805 # compilation of odd code (such as a naked 'return' outside a
2806 # function) that did parse but isn't valid. Typically the exception
2806 # function) that did parse but isn't valid. Typically the exception
2807 # is a SyntaxError, but it's safest just to catch anything and show
2807 # is a SyntaxError, but it's safest just to catch anything and show
2808 # the user a traceback.
2808 # the user a traceback.
2809
2809
2810 # We do only one try/except outside the loop to minimize the impact
2810 # We do only one try/except outside the loop to minimize the impact
2811 # on runtime, and also because if any node in the node list is
2811 # on runtime, and also because if any node in the node list is
2812 # broken, we should stop execution completely.
2812 # broken, we should stop execution completely.
2813 self.showtraceback()
2813 self.showtraceback()
2814
2814
2815 return False
2815 return False
2816
2816
2817 def run_code(self, code_obj):
2817 def run_code(self, code_obj):
2818 """Execute a code object.
2818 """Execute a code object.
2819
2819
2820 When an exception occurs, self.showtraceback() is called to display a
2820 When an exception occurs, self.showtraceback() is called to display a
2821 traceback.
2821 traceback.
2822
2822
2823 Parameters
2823 Parameters
2824 ----------
2824 ----------
2825 code_obj : code object
2825 code_obj : code object
2826 A compiled code object, to be executed
2826 A compiled code object, to be executed
2827
2827
2828 Returns
2828 Returns
2829 -------
2829 -------
2830 False : successful execution.
2830 False : successful execution.
2831 True : an error occurred.
2831 True : an error occurred.
2832 """
2832 """
2833
2833
2834 # Set our own excepthook in case the user code tries to call it
2834 # Set our own excepthook in case the user code tries to call it
2835 # directly, so that the IPython crash handler doesn't get triggered
2835 # directly, so that the IPython crash handler doesn't get triggered
2836 old_excepthook,sys.excepthook = sys.excepthook, self.excepthook
2836 old_excepthook,sys.excepthook = sys.excepthook, self.excepthook
2837
2837
2838 # we save the original sys.excepthook in the instance, in case config
2838 # we save the original sys.excepthook in the instance, in case config
2839 # code (such as magics) needs access to it.
2839 # code (such as magics) needs access to it.
2840 self.sys_excepthook = old_excepthook
2840 self.sys_excepthook = old_excepthook
2841 outflag = 1 # happens in more places, so it's easier as default
2841 outflag = 1 # happens in more places, so it's easier as default
2842 try:
2842 try:
2843 try:
2843 try:
2844 self.hooks.pre_run_code_hook()
2844 self.hooks.pre_run_code_hook()
2845 #rprint('Running code', repr(code_obj)) # dbg
2845 #rprint('Running code', repr(code_obj)) # dbg
2846 exec(code_obj, self.user_global_ns, self.user_ns)
2846 exec(code_obj, self.user_global_ns, self.user_ns)
2847 finally:
2847 finally:
2848 # Reset our crash handler in place
2848 # Reset our crash handler in place
2849 sys.excepthook = old_excepthook
2849 sys.excepthook = old_excepthook
2850 except SystemExit:
2850 except SystemExit:
2851 self.showtraceback(exception_only=True)
2851 self.showtraceback(exception_only=True)
2852 warn("To exit: use 'exit', 'quit', or Ctrl-D.", level=1)
2852 warn("To exit: use 'exit', 'quit', or Ctrl-D.", level=1)
2853 except self.custom_exceptions:
2853 except self.custom_exceptions:
2854 etype,value,tb = sys.exc_info()
2854 etype,value,tb = sys.exc_info()
2855 self.CustomTB(etype,value,tb)
2855 self.CustomTB(etype,value,tb)
2856 except:
2856 except:
2857 self.showtraceback()
2857 self.showtraceback()
2858 else:
2858 else:
2859 outflag = 0
2859 outflag = 0
2860 return outflag
2860 return outflag
2861
2861
2862 # For backwards compatibility
2862 # For backwards compatibility
2863 runcode = run_code
2863 runcode = run_code
2864
2864
2865 #-------------------------------------------------------------------------
2865 #-------------------------------------------------------------------------
2866 # Things related to GUI support and pylab
2866 # Things related to GUI support and pylab
2867 #-------------------------------------------------------------------------
2867 #-------------------------------------------------------------------------
2868
2868
2869 def enable_gui(self, gui=None):
2869 def enable_gui(self, gui=None):
2870 raise NotImplementedError('Implement enable_gui in a subclass')
2870 raise NotImplementedError('Implement enable_gui in a subclass')
2871
2871
2872 def enable_matplotlib(self, gui=None):
2872 def enable_matplotlib(self, gui=None):
2873 """Enable interactive matplotlib and inline figure support.
2873 """Enable interactive matplotlib and inline figure support.
2874
2874
2875 This takes the following steps:
2875 This takes the following steps:
2876
2876
2877 1. select the appropriate eventloop and matplotlib backend
2877 1. select the appropriate eventloop and matplotlib backend
2878 2. set up matplotlib for interactive use with that backend
2878 2. set up matplotlib for interactive use with that backend
2879 3. configure formatters for inline figure display
2879 3. configure formatters for inline figure display
2880 4. enable the selected gui eventloop
2880 4. enable the selected gui eventloop
2881
2881
2882 Parameters
2882 Parameters
2883 ----------
2883 ----------
2884 gui : optional, string
2884 gui : optional, string
2885 If given, dictates the choice of matplotlib GUI backend to use
2885 If given, dictates the choice of matplotlib GUI backend to use
2886 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
2886 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
2887 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
2887 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
2888 matplotlib (as dictated by the matplotlib build-time options plus the
2888 matplotlib (as dictated by the matplotlib build-time options plus the
2889 user's matplotlibrc configuration file). Note that not all backends
2889 user's matplotlibrc configuration file). Note that not all backends
2890 make sense in all contexts, for example a terminal ipython can't
2890 make sense in all contexts, for example a terminal ipython can't
2891 display figures inline.
2891 display figures inline.
2892 """
2892 """
2893 from IPython.core import pylabtools as pt
2893 from IPython.core import pylabtools as pt
2894 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
2894 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
2895
2895
2896 if gui != 'inline':
2896 if gui != 'inline':
2897 # If we have our first gui selection, store it
2897 # If we have our first gui selection, store it
2898 if self.pylab_gui_select is None:
2898 if self.pylab_gui_select is None:
2899 self.pylab_gui_select = gui
2899 self.pylab_gui_select = gui
2900 # Otherwise if they are different
2900 # Otherwise if they are different
2901 elif gui != self.pylab_gui_select:
2901 elif gui != self.pylab_gui_select:
2902 print ('Warning: Cannot change to a different GUI toolkit: %s.'
2902 print ('Warning: Cannot change to a different GUI toolkit: %s.'
2903 ' Using %s instead.' % (gui, self.pylab_gui_select))
2903 ' Using %s instead.' % (gui, self.pylab_gui_select))
2904 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
2904 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
2905
2905
2906 pt.activate_matplotlib(backend)
2906 pt.activate_matplotlib(backend)
2907 pt.configure_inline_support(self, backend)
2907 pt.configure_inline_support(self, backend)
2908
2908
2909 # Now we must activate the gui pylab wants to use, and fix %run to take
2909 # Now we must activate the gui pylab wants to use, and fix %run to take
2910 # plot updates into account
2910 # plot updates into account
2911 self.enable_gui(gui)
2911 self.enable_gui(gui)
2912 self.magics_manager.registry['ExecutionMagics'].default_runner = \
2912 self.magics_manager.registry['ExecutionMagics'].default_runner = \
2913 pt.mpl_runner(self.safe_execfile)
2913 pt.mpl_runner(self.safe_execfile)
2914
2914
2915 return gui, backend
2915 return gui, backend
2916
2916
2917 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
2917 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
2918 """Activate pylab support at runtime.
2918 """Activate pylab support at runtime.
2919
2919
2920 This turns on support for matplotlib, preloads into the interactive
2920 This turns on support for matplotlib, preloads into the interactive
2921 namespace all of numpy and pylab, and configures IPython to correctly
2921 namespace all of numpy and pylab, and configures IPython to correctly
2922 interact with the GUI event loop. The GUI backend to be used can be
2922 interact with the GUI event loop. The GUI backend to be used can be
2923 optionally selected with the optional ``gui`` argument.
2923 optionally selected with the optional ``gui`` argument.
2924
2924
2925 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
2925 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
2926
2926
2927 Parameters
2927 Parameters
2928 ----------
2928 ----------
2929 gui : optional, string
2929 gui : optional, string
2930 If given, dictates the choice of matplotlib GUI backend to use
2930 If given, dictates the choice of matplotlib GUI backend to use
2931 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
2931 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
2932 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
2932 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
2933 matplotlib (as dictated by the matplotlib build-time options plus the
2933 matplotlib (as dictated by the matplotlib build-time options plus the
2934 user's matplotlibrc configuration file). Note that not all backends
2934 user's matplotlibrc configuration file). Note that not all backends
2935 make sense in all contexts, for example a terminal ipython can't
2935 make sense in all contexts, for example a terminal ipython can't
2936 display figures inline.
2936 display figures inline.
2937 import_all : optional, bool, default: True
2937 import_all : optional, bool, default: True
2938 Whether to do `from numpy import *` and `from pylab import *`
2938 Whether to do `from numpy import *` and `from pylab import *`
2939 in addition to module imports.
2939 in addition to module imports.
2940 welcome_message : deprecated
2940 welcome_message : deprecated
2941 This argument is ignored, no welcome message will be displayed.
2941 This argument is ignored, no welcome message will be displayed.
2942 """
2942 """
2943 from IPython.core.pylabtools import import_pylab
2943 from IPython.core.pylabtools import import_pylab
2944
2944
2945 gui, backend = self.enable_matplotlib(gui)
2945 gui, backend = self.enable_matplotlib(gui)
2946
2946
2947 # We want to prevent the loading of pylab to pollute the user's
2947 # We want to prevent the loading of pylab to pollute the user's
2948 # namespace as shown by the %who* magics, so we execute the activation
2948 # namespace as shown by the %who* magics, so we execute the activation
2949 # code in an empty namespace, and we update *both* user_ns and
2949 # code in an empty namespace, and we update *both* user_ns and
2950 # user_ns_hidden with this information.
2950 # user_ns_hidden with this information.
2951 ns = {}
2951 ns = {}
2952 import_pylab(ns, import_all)
2952 import_pylab(ns, import_all)
2953 # warn about clobbered names
2953 # warn about clobbered names
2954 ignored = set(["__builtins__"])
2954 ignored = set(["__builtins__"])
2955 both = set(ns).intersection(self.user_ns).difference(ignored)
2955 both = set(ns).intersection(self.user_ns).difference(ignored)
2956 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
2956 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
2957 self.user_ns.update(ns)
2957 self.user_ns.update(ns)
2958 self.user_ns_hidden.update(ns)
2958 self.user_ns_hidden.update(ns)
2959 return gui, backend, clobbered
2959 return gui, backend, clobbered
2960
2960
2961 #-------------------------------------------------------------------------
2961 #-------------------------------------------------------------------------
2962 # Utilities
2962 # Utilities
2963 #-------------------------------------------------------------------------
2963 #-------------------------------------------------------------------------
2964
2964
2965 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
2965 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
2966 """Expand python variables in a string.
2966 """Expand python variables in a string.
2967
2967
2968 The depth argument indicates how many frames above the caller should
2968 The depth argument indicates how many frames above the caller should
2969 be walked to look for the local namespace where to expand variables.
2969 be walked to look for the local namespace where to expand variables.
2970
2970
2971 The global namespace for expansion is always the user's interactive
2971 The global namespace for expansion is always the user's interactive
2972 namespace.
2972 namespace.
2973 """
2973 """
2974 ns = self.user_ns.copy()
2974 ns = self.user_ns.copy()
2975 ns.update(sys._getframe(depth+1).f_locals)
2975 ns.update(sys._getframe(depth+1).f_locals)
2976 try:
2976 try:
2977 # We have to use .vformat() here, because 'self' is a valid and common
2977 # We have to use .vformat() here, because 'self' is a valid and common
2978 # name, and expanding **ns for .format() would make it collide with
2978 # name, and expanding **ns for .format() would make it collide with
2979 # the 'self' argument of the method.
2979 # the 'self' argument of the method.
2980 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
2980 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
2981 except Exception:
2981 except Exception:
2982 # if formatter couldn't format, just let it go untransformed
2982 # if formatter couldn't format, just let it go untransformed
2983 pass
2983 pass
2984 return cmd
2984 return cmd
2985
2985
2986 def mktempfile(self, data=None, prefix='ipython_edit_'):
2986 def mktempfile(self, data=None, prefix='ipython_edit_'):
2987 """Make a new tempfile and return its filename.
2987 """Make a new tempfile and return its filename.
2988
2988
2989 This makes a call to tempfile.mktemp, but it registers the created
2989 This makes a call to tempfile.mktemp, but it registers the created
2990 filename internally so ipython cleans it up at exit time.
2990 filename internally so ipython cleans it up at exit time.
2991
2991
2992 Optional inputs:
2992 Optional inputs:
2993
2993
2994 - data(None): if data is given, it gets written out to the temp file
2994 - data(None): if data is given, it gets written out to the temp file
2995 immediately, and the file is closed again."""
2995 immediately, and the file is closed again."""
2996
2996
2997 filename = tempfile.mktemp('.py', prefix)
2997 filename = tempfile.mktemp('.py', prefix)
2998 self.tempfiles.append(filename)
2998 self.tempfiles.append(filename)
2999
2999
3000 if data:
3000 if data:
3001 tmp_file = open(filename,'w')
3001 tmp_file = open(filename,'w')
3002 tmp_file.write(data)
3002 tmp_file.write(data)
3003 tmp_file.close()
3003 tmp_file.close()
3004 return filename
3004 return filename
3005
3005
3006 # TODO: This should be removed when Term is refactored.
3006 # TODO: This should be removed when Term is refactored.
3007 def write(self,data):
3007 def write(self,data):
3008 """Write a string to the default output"""
3008 """Write a string to the default output"""
3009 io.stdout.write(data)
3009 io.stdout.write(data)
3010
3010
3011 # TODO: This should be removed when Term is refactored.
3011 # TODO: This should be removed when Term is refactored.
3012 def write_err(self,data):
3012 def write_err(self,data):
3013 """Write a string to the default error output"""
3013 """Write a string to the default error output"""
3014 io.stderr.write(data)
3014 io.stderr.write(data)
3015
3015
3016 def ask_yes_no(self, prompt, default=None):
3016 def ask_yes_no(self, prompt, default=None):
3017 if self.quiet:
3017 if self.quiet:
3018 return True
3018 return True
3019 return ask_yes_no(prompt,default)
3019 return ask_yes_no(prompt,default)
3020
3020
3021 def show_usage(self):
3021 def show_usage(self):
3022 """Show a usage message"""
3022 """Show a usage message"""
3023 page.page(IPython.core.usage.interactive_usage)
3023 page.page(IPython.core.usage.interactive_usage)
3024
3024
3025 def extract_input_lines(self, range_str, raw=False):
3025 def extract_input_lines(self, range_str, raw=False):
3026 """Return as a string a set of input history slices.
3026 """Return as a string a set of input history slices.
3027
3027
3028 Parameters
3028 Parameters
3029 ----------
3029 ----------
3030 range_str : string
3030 range_str : string
3031 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3031 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3032 since this function is for use by magic functions which get their
3032 since this function is for use by magic functions which get their
3033 arguments as strings. The number before the / is the session
3033 arguments as strings. The number before the / is the session
3034 number: ~n goes n back from the current session.
3034 number: ~n goes n back from the current session.
3035
3035
3036 Optional Parameters:
3036 Optional Parameters:
3037 - raw(False): by default, the processed input is used. If this is
3037 - raw(False): by default, the processed input is used. If this is
3038 true, the raw input history is used instead.
3038 true, the raw input history is used instead.
3039
3039
3040 Note that slices can be called with two notations:
3040 Note that slices can be called with two notations:
3041
3041
3042 N:M -> standard python form, means including items N...(M-1).
3042 N:M -> standard python form, means including items N...(M-1).
3043
3043
3044 N-M -> include items N..M (closed endpoint).
3044 N-M -> include items N..M (closed endpoint).
3045 """
3045 """
3046 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3046 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3047 return "\n".join(x for _, _, x in lines)
3047 return "\n".join(x for _, _, x in lines)
3048
3048
3049 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True):
3049 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True):
3050 """Get a code string from history, file, url, or a string or macro.
3050 """Get a code string from history, file, url, or a string or macro.
3051
3051
3052 This is mainly used by magic functions.
3052 This is mainly used by magic functions.
3053
3053
3054 Parameters
3054 Parameters
3055 ----------
3055 ----------
3056
3056
3057 target : str
3057 target : str
3058
3058
3059 A string specifying code to retrieve. This will be tried respectively
3059 A string specifying code to retrieve. This will be tried respectively
3060 as: ranges of input history (see %history for syntax), url,
3060 as: ranges of input history (see %history for syntax), url,
3061 correspnding .py file, filename, or an expression evaluating to a
3061 correspnding .py file, filename, or an expression evaluating to a
3062 string or Macro in the user namespace.
3062 string or Macro in the user namespace.
3063
3063
3064 raw : bool
3064 raw : bool
3065 If true (default), retrieve raw history. Has no effect on the other
3065 If true (default), retrieve raw history. Has no effect on the other
3066 retrieval mechanisms.
3066 retrieval mechanisms.
3067
3067
3068 py_only : bool (default False)
3068 py_only : bool (default False)
3069 Only try to fetch python code, do not try alternative methods to decode file
3069 Only try to fetch python code, do not try alternative methods to decode file
3070 if unicode fails.
3070 if unicode fails.
3071
3071
3072 Returns
3072 Returns
3073 -------
3073 -------
3074 A string of code.
3074 A string of code.
3075
3075
3076 ValueError is raised if nothing is found, and TypeError if it evaluates
3076 ValueError is raised if nothing is found, and TypeError if it evaluates
3077 to an object of another type. In each case, .args[0] is a printable
3077 to an object of another type. In each case, .args[0] is a printable
3078 message.
3078 message.
3079 """
3079 """
3080 code = self.extract_input_lines(target, raw=raw) # Grab history
3080 code = self.extract_input_lines(target, raw=raw) # Grab history
3081 if code:
3081 if code:
3082 return code
3082 return code
3083 utarget = unquote_filename(target)
3083 utarget = unquote_filename(target)
3084 try:
3084 try:
3085 if utarget.startswith(('http://', 'https://')):
3085 if utarget.startswith(('http://', 'https://')):
3086 return openpy.read_py_url(utarget, skip_encoding_cookie=skip_encoding_cookie)
3086 return openpy.read_py_url(utarget, skip_encoding_cookie=skip_encoding_cookie)
3087 except UnicodeDecodeError:
3087 except UnicodeDecodeError:
3088 if not py_only :
3088 if not py_only :
3089 from urllib import urlopen # Deferred import
3089 from urllib import urlopen # Deferred import
3090 response = urlopen(target)
3090 response = urlopen(target)
3091 return response.read().decode('latin1')
3091 return response.read().decode('latin1')
3092 raise ValueError(("'%s' seem to be unreadable.") % utarget)
3092 raise ValueError(("'%s' seem to be unreadable.") % utarget)
3093
3093
3094 potential_target = [target]
3094 potential_target = [target]
3095 try :
3095 try :
3096 potential_target.insert(0,get_py_filename(target))
3096 potential_target.insert(0,get_py_filename(target))
3097 except IOError:
3097 except IOError:
3098 pass
3098 pass
3099
3099
3100 for tgt in potential_target :
3100 for tgt in potential_target :
3101 if os.path.isfile(tgt): # Read file
3101 if os.path.isfile(tgt): # Read file
3102 try :
3102 try :
3103 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3103 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3104 except UnicodeDecodeError :
3104 except UnicodeDecodeError :
3105 if not py_only :
3105 if not py_only :
3106 with io_open(tgt,'r', encoding='latin1') as f :
3106 with io_open(tgt,'r', encoding='latin1') as f :
3107 return f.read()
3107 return f.read()
3108 raise ValueError(("'%s' seem to be unreadable.") % target)
3108 raise ValueError(("'%s' seem to be unreadable.") % target)
3109 elif os.path.isdir(os.path.expanduser(tgt)):
3109 elif os.path.isdir(os.path.expanduser(tgt)):
3110 raise ValueError("'%s' is a directory, not a regular file." % target)
3110 raise ValueError("'%s' is a directory, not a regular file." % target)
3111
3111
3112 try: # User namespace
3112 try: # User namespace
3113 codeobj = eval(target, self.user_ns)
3113 codeobj = eval(target, self.user_ns)
3114 except Exception:
3114 except Exception:
3115 raise ValueError(("'%s' was not found in history, as a file, url, "
3115 raise ValueError(("'%s' was not found in history, as a file, url, "
3116 "nor in the user namespace.") % target)
3116 "nor in the user namespace.") % target)
3117 if isinstance(codeobj, string_types):
3117 if isinstance(codeobj, string_types):
3118 return codeobj
3118 return codeobj
3119 elif isinstance(codeobj, Macro):
3119 elif isinstance(codeobj, Macro):
3120 return codeobj.value
3120 return codeobj.value
3121
3121
3122 raise TypeError("%s is neither a string nor a macro." % target,
3122 raise TypeError("%s is neither a string nor a macro." % target,
3123 codeobj)
3123 codeobj)
3124
3124
3125 #-------------------------------------------------------------------------
3125 #-------------------------------------------------------------------------
3126 # Things related to IPython exiting
3126 # Things related to IPython exiting
3127 #-------------------------------------------------------------------------
3127 #-------------------------------------------------------------------------
3128 def atexit_operations(self):
3128 def atexit_operations(self):
3129 """This will be executed at the time of exit.
3129 """This will be executed at the time of exit.
3130
3130
3131 Cleanup operations and saving of persistent data that is done
3131 Cleanup operations and saving of persistent data that is done
3132 unconditionally by IPython should be performed here.
3132 unconditionally by IPython should be performed here.
3133
3133
3134 For things that may depend on startup flags or platform specifics (such
3134 For things that may depend on startup flags or platform specifics (such
3135 as having readline or not), register a separate atexit function in the
3135 as having readline or not), register a separate atexit function in the
3136 code that has the appropriate information, rather than trying to
3136 code that has the appropriate information, rather than trying to
3137 clutter
3137 clutter
3138 """
3138 """
3139 # Close the history session (this stores the end time and line count)
3139 # Close the history session (this stores the end time and line count)
3140 # this must be *before* the tempfile cleanup, in case of temporary
3140 # this must be *before* the tempfile cleanup, in case of temporary
3141 # history db
3141 # history db
3142 self.history_manager.end_session()
3142 self.history_manager.end_session()
3143
3143
3144 # Cleanup all tempfiles left around
3144 # Cleanup all tempfiles left around
3145 for tfile in self.tempfiles:
3145 for tfile in self.tempfiles:
3146 try:
3146 try:
3147 os.unlink(tfile)
3147 os.unlink(tfile)
3148 except OSError:
3148 except OSError:
3149 pass
3149 pass
3150
3150
3151 # Clear all user namespaces to release all references cleanly.
3151 # Clear all user namespaces to release all references cleanly.
3152 self.reset(new_session=False)
3152 self.reset(new_session=False)
3153
3153
3154 # Run user hooks
3154 # Run user hooks
3155 self.hooks.shutdown_hook()
3155 self.hooks.shutdown_hook()
3156
3156
3157 def cleanup(self):
3157 def cleanup(self):
3158 self.restore_sys_module_state()
3158 self.restore_sys_module_state()
3159
3159
3160
3160
3161 class InteractiveShellABC(with_metaclass(abc.ABCMeta, object)):
3161 class InteractiveShellABC(with_metaclass(abc.ABCMeta, object)):
3162 """An abstract base class for InteractiveShell."""
3162 """An abstract base class for InteractiveShell."""
3163
3163
3164 InteractiveShellABC.register(InteractiveShell)
3164 InteractiveShellABC.register(InteractiveShell)
@@ -1,740 +1,741 b''
1 """Implementation of magic functions for interaction with the OS.
1 """Implementation of magic functions for interaction with the OS.
2
2
3 Note: this module is named 'osm' instead of 'os' to avoid a collision with the
3 Note: this module is named 'osm' instead of 'os' to avoid a collision with the
4 builtin.
4 builtin.
5 """
5 """
6 from __future__ import print_function
6 from __future__ import print_function
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (c) 2012 The IPython Development Team.
8 # Copyright (c) 2012 The IPython Development Team.
9 #
9 #
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11 #
11 #
12 # The full license is in the file COPYING.txt, distributed with this software.
12 # The full license is in the file COPYING.txt, distributed with this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 # Stdlib
19 # Stdlib
20 import io
20 import io
21 import os
21 import os
22 import re
22 import re
23 import sys
23 import sys
24 from pprint import pformat
24 from pprint import pformat
25
25
26 # Our own packages
26 # Our own packages
27 from IPython.core import magic_arguments
27 from IPython.core import magic_arguments
28 from IPython.core import oinspect
28 from IPython.core import oinspect
29 from IPython.core import page
29 from IPython.core import page
30 from IPython.core.alias import AliasError, Alias
30 from IPython.core.alias import AliasError, Alias
31 from IPython.core.error import UsageError
31 from IPython.core.error import UsageError
32 from IPython.core.magic import (
32 from IPython.core.magic import (
33 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
33 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
34 )
34 )
35 from IPython.testing.skipdoctest import skip_doctest
35 from IPython.testing.skipdoctest import skip_doctest
36 from IPython.utils.openpy import source_to_unicode
36 from IPython.utils.openpy import source_to_unicode
37 from IPython.utils.path import unquote_filename
37 from IPython.utils.path import unquote_filename
38 from IPython.utils.process import abbrev_cwd
38 from IPython.utils.process import abbrev_cwd
39 from IPython.utils import py3compat
39 from IPython.utils.py3compat import unicode_type
40 from IPython.utils.py3compat import unicode_type
40 from IPython.utils.terminal import set_term_title
41 from IPython.utils.terminal import set_term_title
41
42
42 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
43 # Magic implementation classes
44 # Magic implementation classes
44 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
45 @magics_class
46 @magics_class
46 class OSMagics(Magics):
47 class OSMagics(Magics):
47 """Magics to interact with the underlying OS (shell-type functionality).
48 """Magics to interact with the underlying OS (shell-type functionality).
48 """
49 """
49
50
50 @skip_doctest
51 @skip_doctest
51 @line_magic
52 @line_magic
52 def alias(self, parameter_s=''):
53 def alias(self, parameter_s=''):
53 """Define an alias for a system command.
54 """Define an alias for a system command.
54
55
55 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
56 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
56
57
57 Then, typing 'alias_name params' will execute the system command 'cmd
58 Then, typing 'alias_name params' will execute the system command 'cmd
58 params' (from your underlying operating system).
59 params' (from your underlying operating system).
59
60
60 Aliases have lower precedence than magic functions and Python normal
61 Aliases have lower precedence than magic functions and Python normal
61 variables, so if 'foo' is both a Python variable and an alias, the
62 variables, so if 'foo' is both a Python variable and an alias, the
62 alias can not be executed until 'del foo' removes the Python variable.
63 alias can not be executed until 'del foo' removes the Python variable.
63
64
64 You can use the %l specifier in an alias definition to represent the
65 You can use the %l specifier in an alias definition to represent the
65 whole line when the alias is called. For example::
66 whole line when the alias is called. For example::
66
67
67 In [2]: alias bracket echo "Input in brackets: <%l>"
68 In [2]: alias bracket echo "Input in brackets: <%l>"
68 In [3]: bracket hello world
69 In [3]: bracket hello world
69 Input in brackets: <hello world>
70 Input in brackets: <hello world>
70
71
71 You can also define aliases with parameters using %s specifiers (one
72 You can also define aliases with parameters using %s specifiers (one
72 per parameter)::
73 per parameter)::
73
74
74 In [1]: alias parts echo first %s second %s
75 In [1]: alias parts echo first %s second %s
75 In [2]: %parts A B
76 In [2]: %parts A B
76 first A second B
77 first A second B
77 In [3]: %parts A
78 In [3]: %parts A
78 Incorrect number of arguments: 2 expected.
79 Incorrect number of arguments: 2 expected.
79 parts is an alias to: 'echo first %s second %s'
80 parts is an alias to: 'echo first %s second %s'
80
81
81 Note that %l and %s are mutually exclusive. You can only use one or
82 Note that %l and %s are mutually exclusive. You can only use one or
82 the other in your aliases.
83 the other in your aliases.
83
84
84 Aliases expand Python variables just like system calls using ! or !!
85 Aliases expand Python variables just like system calls using ! or !!
85 do: all expressions prefixed with '$' get expanded. For details of
86 do: all expressions prefixed with '$' get expanded. For details of
86 the semantic rules, see PEP-215:
87 the semantic rules, see PEP-215:
87 http://www.python.org/peps/pep-0215.html. This is the library used by
88 http://www.python.org/peps/pep-0215.html. This is the library used by
88 IPython for variable expansion. If you want to access a true shell
89 IPython for variable expansion. If you want to access a true shell
89 variable, an extra $ is necessary to prevent its expansion by
90 variable, an extra $ is necessary to prevent its expansion by
90 IPython::
91 IPython::
91
92
92 In [6]: alias show echo
93 In [6]: alias show echo
93 In [7]: PATH='A Python string'
94 In [7]: PATH='A Python string'
94 In [8]: show $PATH
95 In [8]: show $PATH
95 A Python string
96 A Python string
96 In [9]: show $$PATH
97 In [9]: show $$PATH
97 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
98 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
98
99
99 You can use the alias facility to acess all of $PATH. See the %rehash
100 You can use the alias facility to acess all of $PATH. See the %rehash
100 and %rehashx functions, which automatically create aliases for the
101 and %rehashx functions, which automatically create aliases for the
101 contents of your $PATH.
102 contents of your $PATH.
102
103
103 If called with no parameters, %alias prints the current alias table."""
104 If called with no parameters, %alias prints the current alias table."""
104
105
105 par = parameter_s.strip()
106 par = parameter_s.strip()
106 if not par:
107 if not par:
107 aliases = sorted(self.shell.alias_manager.aliases)
108 aliases = sorted(self.shell.alias_manager.aliases)
108 # stored = self.shell.db.get('stored_aliases', {} )
109 # stored = self.shell.db.get('stored_aliases', {} )
109 # for k, v in stored:
110 # for k, v in stored:
110 # atab.append(k, v[0])
111 # atab.append(k, v[0])
111
112
112 print("Total number of aliases:", len(aliases))
113 print("Total number of aliases:", len(aliases))
113 sys.stdout.flush()
114 sys.stdout.flush()
114 return aliases
115 return aliases
115
116
116 # Now try to define a new one
117 # Now try to define a new one
117 try:
118 try:
118 alias,cmd = par.split(None, 1)
119 alias,cmd = par.split(None, 1)
119 except TypeError:
120 except TypeError:
120 print(oinspect.getdoc(self.alias))
121 print(oinspect.getdoc(self.alias))
121 return
122 return
122
123
123 try:
124 try:
124 self.shell.alias_manager.define_alias(alias, cmd)
125 self.shell.alias_manager.define_alias(alias, cmd)
125 except AliasError as e:
126 except AliasError as e:
126 print(e)
127 print(e)
127 # end magic_alias
128 # end magic_alias
128
129
129 @line_magic
130 @line_magic
130 def unalias(self, parameter_s=''):
131 def unalias(self, parameter_s=''):
131 """Remove an alias"""
132 """Remove an alias"""
132
133
133 aname = parameter_s.strip()
134 aname = parameter_s.strip()
134 try:
135 try:
135 self.shell.alias_manager.undefine_alias(aname)
136 self.shell.alias_manager.undefine_alias(aname)
136 except ValueError as e:
137 except ValueError as e:
137 print(e)
138 print(e)
138 return
139 return
139
140
140 stored = self.shell.db.get('stored_aliases', {} )
141 stored = self.shell.db.get('stored_aliases', {} )
141 if aname in stored:
142 if aname in stored:
142 print("Removing %stored alias",aname)
143 print("Removing %stored alias",aname)
143 del stored[aname]
144 del stored[aname]
144 self.shell.db['stored_aliases'] = stored
145 self.shell.db['stored_aliases'] = stored
145
146
146 @line_magic
147 @line_magic
147 def rehashx(self, parameter_s=''):
148 def rehashx(self, parameter_s=''):
148 """Update the alias table with all executable files in $PATH.
149 """Update the alias table with all executable files in $PATH.
149
150
150 This version explicitly checks that every entry in $PATH is a file
151 This version explicitly checks that every entry in $PATH is a file
151 with execute access (os.X_OK), so it is much slower than %rehash.
152 with execute access (os.X_OK), so it is much slower than %rehash.
152
153
153 Under Windows, it checks executability as a match against a
154 Under Windows, it checks executability as a match against a
154 '|'-separated string of extensions, stored in the IPython config
155 '|'-separated string of extensions, stored in the IPython config
155 variable win_exec_ext. This defaults to 'exe|com|bat'.
156 variable win_exec_ext. This defaults to 'exe|com|bat'.
156
157
157 This function also resets the root module cache of module completer,
158 This function also resets the root module cache of module completer,
158 used on slow filesystems.
159 used on slow filesystems.
159 """
160 """
160 from IPython.core.alias import InvalidAliasError
161 from IPython.core.alias import InvalidAliasError
161
162
162 # for the benefit of module completer in ipy_completers.py
163 # for the benefit of module completer in ipy_completers.py
163 del self.shell.db['rootmodules_cache']
164 del self.shell.db['rootmodules_cache']
164
165
165 path = [os.path.abspath(os.path.expanduser(p)) for p in
166 path = [os.path.abspath(os.path.expanduser(p)) for p in
166 os.environ.get('PATH','').split(os.pathsep)]
167 os.environ.get('PATH','').split(os.pathsep)]
167 path = filter(os.path.isdir,path)
168 path = filter(os.path.isdir,path)
168
169
169 syscmdlist = []
170 syscmdlist = []
170 # Now define isexec in a cross platform manner.
171 # Now define isexec in a cross platform manner.
171 if os.name == 'posix':
172 if os.name == 'posix':
172 isexec = lambda fname:os.path.isfile(fname) and \
173 isexec = lambda fname:os.path.isfile(fname) and \
173 os.access(fname,os.X_OK)
174 os.access(fname,os.X_OK)
174 else:
175 else:
175 try:
176 try:
176 winext = os.environ['pathext'].replace(';','|').replace('.','')
177 winext = os.environ['pathext'].replace(';','|').replace('.','')
177 except KeyError:
178 except KeyError:
178 winext = 'exe|com|bat|py'
179 winext = 'exe|com|bat|py'
179 if 'py' not in winext:
180 if 'py' not in winext:
180 winext += '|py'
181 winext += '|py'
181 execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
182 execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
182 isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
183 isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
183 savedir = os.getcwdu()
184 savedir = py3compat.getcwd()
184
185
185 # Now walk the paths looking for executables to alias.
186 # Now walk the paths looking for executables to alias.
186 try:
187 try:
187 # write the whole loop for posix/Windows so we don't have an if in
188 # write the whole loop for posix/Windows so we don't have an if in
188 # the innermost part
189 # the innermost part
189 if os.name == 'posix':
190 if os.name == 'posix':
190 for pdir in path:
191 for pdir in path:
191 os.chdir(pdir)
192 os.chdir(pdir)
192 for ff in os.listdir(pdir):
193 for ff in os.listdir(pdir):
193 if isexec(ff):
194 if isexec(ff):
194 try:
195 try:
195 # Removes dots from the name since ipython
196 # Removes dots from the name since ipython
196 # will assume names with dots to be python.
197 # will assume names with dots to be python.
197 if not self.shell.alias_manager.is_alias(ff):
198 if not self.shell.alias_manager.is_alias(ff):
198 self.shell.alias_manager.define_alias(
199 self.shell.alias_manager.define_alias(
199 ff.replace('.',''), ff)
200 ff.replace('.',''), ff)
200 except InvalidAliasError:
201 except InvalidAliasError:
201 pass
202 pass
202 else:
203 else:
203 syscmdlist.append(ff)
204 syscmdlist.append(ff)
204 else:
205 else:
205 no_alias = Alias.blacklist
206 no_alias = Alias.blacklist
206 for pdir in path:
207 for pdir in path:
207 os.chdir(pdir)
208 os.chdir(pdir)
208 for ff in os.listdir(pdir):
209 for ff in os.listdir(pdir):
209 base, ext = os.path.splitext(ff)
210 base, ext = os.path.splitext(ff)
210 if isexec(ff) and base.lower() not in no_alias:
211 if isexec(ff) and base.lower() not in no_alias:
211 if ext.lower() == '.exe':
212 if ext.lower() == '.exe':
212 ff = base
213 ff = base
213 try:
214 try:
214 # Removes dots from the name since ipython
215 # Removes dots from the name since ipython
215 # will assume names with dots to be python.
216 # will assume names with dots to be python.
216 self.shell.alias_manager.define_alias(
217 self.shell.alias_manager.define_alias(
217 base.lower().replace('.',''), ff)
218 base.lower().replace('.',''), ff)
218 except InvalidAliasError:
219 except InvalidAliasError:
219 pass
220 pass
220 syscmdlist.append(ff)
221 syscmdlist.append(ff)
221 self.shell.db['syscmdlist'] = syscmdlist
222 self.shell.db['syscmdlist'] = syscmdlist
222 finally:
223 finally:
223 os.chdir(savedir)
224 os.chdir(savedir)
224
225
225 @skip_doctest
226 @skip_doctest
226 @line_magic
227 @line_magic
227 def pwd(self, parameter_s=''):
228 def pwd(self, parameter_s=''):
228 """Return the current working directory path.
229 """Return the current working directory path.
229
230
230 Examples
231 Examples
231 --------
232 --------
232 ::
233 ::
233
234
234 In [9]: pwd
235 In [9]: pwd
235 Out[9]: '/home/tsuser/sprint/ipython'
236 Out[9]: '/home/tsuser/sprint/ipython'
236 """
237 """
237 return os.getcwdu()
238 return py3compat.getcwd()
238
239
239 @skip_doctest
240 @skip_doctest
240 @line_magic
241 @line_magic
241 def cd(self, parameter_s=''):
242 def cd(self, parameter_s=''):
242 """Change the current working directory.
243 """Change the current working directory.
243
244
244 This command automatically maintains an internal list of directories
245 This command automatically maintains an internal list of directories
245 you visit during your IPython session, in the variable _dh. The
246 you visit during your IPython session, in the variable _dh. The
246 command %dhist shows this history nicely formatted. You can also
247 command %dhist shows this history nicely formatted. You can also
247 do 'cd -<tab>' to see directory history conveniently.
248 do 'cd -<tab>' to see directory history conveniently.
248
249
249 Usage:
250 Usage:
250
251
251 cd 'dir': changes to directory 'dir'.
252 cd 'dir': changes to directory 'dir'.
252
253
253 cd -: changes to the last visited directory.
254 cd -: changes to the last visited directory.
254
255
255 cd -<n>: changes to the n-th directory in the directory history.
256 cd -<n>: changes to the n-th directory in the directory history.
256
257
257 cd --foo: change to directory that matches 'foo' in history
258 cd --foo: change to directory that matches 'foo' in history
258
259
259 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
260 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
260 (note: cd <bookmark_name> is enough if there is no
261 (note: cd <bookmark_name> is enough if there is no
261 directory <bookmark_name>, but a bookmark with the name exists.)
262 directory <bookmark_name>, but a bookmark with the name exists.)
262 'cd -b <tab>' allows you to tab-complete bookmark names.
263 'cd -b <tab>' allows you to tab-complete bookmark names.
263
264
264 Options:
265 Options:
265
266
266 -q: quiet. Do not print the working directory after the cd command is
267 -q: quiet. Do not print the working directory after the cd command is
267 executed. By default IPython's cd command does print this directory,
268 executed. By default IPython's cd command does print this directory,
268 since the default prompts do not display path information.
269 since the default prompts do not display path information.
269
270
270 Note that !cd doesn't work for this purpose because the shell where
271 Note that !cd doesn't work for this purpose because the shell where
271 !command runs is immediately discarded after executing 'command'.
272 !command runs is immediately discarded after executing 'command'.
272
273
273 Examples
274 Examples
274 --------
275 --------
275 ::
276 ::
276
277
277 In [10]: cd parent/child
278 In [10]: cd parent/child
278 /home/tsuser/parent/child
279 /home/tsuser/parent/child
279 """
280 """
280
281
281 oldcwd = os.getcwdu()
282 oldcwd = py3compat.getcwd()
282 numcd = re.match(r'(-)(\d+)$',parameter_s)
283 numcd = re.match(r'(-)(\d+)$',parameter_s)
283 # jump in directory history by number
284 # jump in directory history by number
284 if numcd:
285 if numcd:
285 nn = int(numcd.group(2))
286 nn = int(numcd.group(2))
286 try:
287 try:
287 ps = self.shell.user_ns['_dh'][nn]
288 ps = self.shell.user_ns['_dh'][nn]
288 except IndexError:
289 except IndexError:
289 print('The requested directory does not exist in history.')
290 print('The requested directory does not exist in history.')
290 return
291 return
291 else:
292 else:
292 opts = {}
293 opts = {}
293 elif parameter_s.startswith('--'):
294 elif parameter_s.startswith('--'):
294 ps = None
295 ps = None
295 fallback = None
296 fallback = None
296 pat = parameter_s[2:]
297 pat = parameter_s[2:]
297 dh = self.shell.user_ns['_dh']
298 dh = self.shell.user_ns['_dh']
298 # first search only by basename (last component)
299 # first search only by basename (last component)
299 for ent in reversed(dh):
300 for ent in reversed(dh):
300 if pat in os.path.basename(ent) and os.path.isdir(ent):
301 if pat in os.path.basename(ent) and os.path.isdir(ent):
301 ps = ent
302 ps = ent
302 break
303 break
303
304
304 if fallback is None and pat in ent and os.path.isdir(ent):
305 if fallback is None and pat in ent and os.path.isdir(ent):
305 fallback = ent
306 fallback = ent
306
307
307 # if we have no last part match, pick the first full path match
308 # if we have no last part match, pick the first full path match
308 if ps is None:
309 if ps is None:
309 ps = fallback
310 ps = fallback
310
311
311 if ps is None:
312 if ps is None:
312 print("No matching entry in directory history")
313 print("No matching entry in directory history")
313 return
314 return
314 else:
315 else:
315 opts = {}
316 opts = {}
316
317
317
318
318 else:
319 else:
319 #turn all non-space-escaping backslashes to slashes,
320 #turn all non-space-escaping backslashes to slashes,
320 # for c:\windows\directory\names\
321 # for c:\windows\directory\names\
321 parameter_s = re.sub(r'\\(?! )','/', parameter_s)
322 parameter_s = re.sub(r'\\(?! )','/', parameter_s)
322 opts,ps = self.parse_options(parameter_s,'qb',mode='string')
323 opts,ps = self.parse_options(parameter_s,'qb',mode='string')
323 # jump to previous
324 # jump to previous
324 if ps == '-':
325 if ps == '-':
325 try:
326 try:
326 ps = self.shell.user_ns['_dh'][-2]
327 ps = self.shell.user_ns['_dh'][-2]
327 except IndexError:
328 except IndexError:
328 raise UsageError('%cd -: No previous directory to change to.')
329 raise UsageError('%cd -: No previous directory to change to.')
329 # jump to bookmark if needed
330 # jump to bookmark if needed
330 else:
331 else:
331 if not os.path.isdir(ps) or 'b' in opts:
332 if not os.path.isdir(ps) or 'b' in opts:
332 bkms = self.shell.db.get('bookmarks', {})
333 bkms = self.shell.db.get('bookmarks', {})
333
334
334 if ps in bkms:
335 if ps in bkms:
335 target = bkms[ps]
336 target = bkms[ps]
336 print('(bookmark:%s) -> %s' % (ps, target))
337 print('(bookmark:%s) -> %s' % (ps, target))
337 ps = target
338 ps = target
338 else:
339 else:
339 if 'b' in opts:
340 if 'b' in opts:
340 raise UsageError("Bookmark '%s' not found. "
341 raise UsageError("Bookmark '%s' not found. "
341 "Use '%%bookmark -l' to see your bookmarks." % ps)
342 "Use '%%bookmark -l' to see your bookmarks." % ps)
342
343
343 # strip extra quotes on Windows, because os.chdir doesn't like them
344 # strip extra quotes on Windows, because os.chdir doesn't like them
344 ps = unquote_filename(ps)
345 ps = unquote_filename(ps)
345 # at this point ps should point to the target dir
346 # at this point ps should point to the target dir
346 if ps:
347 if ps:
347 try:
348 try:
348 os.chdir(os.path.expanduser(ps))
349 os.chdir(os.path.expanduser(ps))
349 if hasattr(self.shell, 'term_title') and self.shell.term_title:
350 if hasattr(self.shell, 'term_title') and self.shell.term_title:
350 set_term_title('IPython: ' + abbrev_cwd())
351 set_term_title('IPython: ' + abbrev_cwd())
351 except OSError:
352 except OSError:
352 print(sys.exc_info()[1])
353 print(sys.exc_info()[1])
353 else:
354 else:
354 cwd = os.getcwdu()
355 cwd = py3compat.getcwd()
355 dhist = self.shell.user_ns['_dh']
356 dhist = self.shell.user_ns['_dh']
356 if oldcwd != cwd:
357 if oldcwd != cwd:
357 dhist.append(cwd)
358 dhist.append(cwd)
358 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
359 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
359
360
360 else:
361 else:
361 os.chdir(self.shell.home_dir)
362 os.chdir(self.shell.home_dir)
362 if hasattr(self.shell, 'term_title') and self.shell.term_title:
363 if hasattr(self.shell, 'term_title') and self.shell.term_title:
363 set_term_title('IPython: ' + '~')
364 set_term_title('IPython: ' + '~')
364 cwd = os.getcwdu()
365 cwd = py3compat.getcwd()
365 dhist = self.shell.user_ns['_dh']
366 dhist = self.shell.user_ns['_dh']
366
367
367 if oldcwd != cwd:
368 if oldcwd != cwd:
368 dhist.append(cwd)
369 dhist.append(cwd)
369 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
370 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
370 if not 'q' in opts and self.shell.user_ns['_dh']:
371 if not 'q' in opts and self.shell.user_ns['_dh']:
371 print(self.shell.user_ns['_dh'][-1])
372 print(self.shell.user_ns['_dh'][-1])
372
373
373
374
374 @line_magic
375 @line_magic
375 def env(self, parameter_s=''):
376 def env(self, parameter_s=''):
376 """List environment variables."""
377 """List environment variables."""
377
378
378 return dict(os.environ)
379 return dict(os.environ)
379
380
380 @line_magic
381 @line_magic
381 def pushd(self, parameter_s=''):
382 def pushd(self, parameter_s=''):
382 """Place the current dir on stack and change directory.
383 """Place the current dir on stack and change directory.
383
384
384 Usage:\\
385 Usage:\\
385 %pushd ['dirname']
386 %pushd ['dirname']
386 """
387 """
387
388
388 dir_s = self.shell.dir_stack
389 dir_s = self.shell.dir_stack
389 tgt = os.path.expanduser(unquote_filename(parameter_s))
390 tgt = os.path.expanduser(unquote_filename(parameter_s))
390 cwd = os.getcwdu().replace(self.shell.home_dir,'~')
391 cwd = py3compat.getcwd().replace(self.shell.home_dir,'~')
391 if tgt:
392 if tgt:
392 self.cd(parameter_s)
393 self.cd(parameter_s)
393 dir_s.insert(0,cwd)
394 dir_s.insert(0,cwd)
394 return self.shell.magic('dirs')
395 return self.shell.magic('dirs')
395
396
396 @line_magic
397 @line_magic
397 def popd(self, parameter_s=''):
398 def popd(self, parameter_s=''):
398 """Change to directory popped off the top of the stack.
399 """Change to directory popped off the top of the stack.
399 """
400 """
400 if not self.shell.dir_stack:
401 if not self.shell.dir_stack:
401 raise UsageError("%popd on empty stack")
402 raise UsageError("%popd on empty stack")
402 top = self.shell.dir_stack.pop(0)
403 top = self.shell.dir_stack.pop(0)
403 self.cd(top)
404 self.cd(top)
404 print("popd ->",top)
405 print("popd ->",top)
405
406
406 @line_magic
407 @line_magic
407 def dirs(self, parameter_s=''):
408 def dirs(self, parameter_s=''):
408 """Return the current directory stack."""
409 """Return the current directory stack."""
409
410
410 return self.shell.dir_stack
411 return self.shell.dir_stack
411
412
412 @line_magic
413 @line_magic
413 def dhist(self, parameter_s=''):
414 def dhist(self, parameter_s=''):
414 """Print your history of visited directories.
415 """Print your history of visited directories.
415
416
416 %dhist -> print full history\\
417 %dhist -> print full history\\
417 %dhist n -> print last n entries only\\
418 %dhist n -> print last n entries only\\
418 %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
419 %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
419
420
420 This history is automatically maintained by the %cd command, and
421 This history is automatically maintained by the %cd command, and
421 always available as the global list variable _dh. You can use %cd -<n>
422 always available as the global list variable _dh. You can use %cd -<n>
422 to go to directory number <n>.
423 to go to directory number <n>.
423
424
424 Note that most of time, you should view directory history by entering
425 Note that most of time, you should view directory history by entering
425 cd -<TAB>.
426 cd -<TAB>.
426
427
427 """
428 """
428
429
429 dh = self.shell.user_ns['_dh']
430 dh = self.shell.user_ns['_dh']
430 if parameter_s:
431 if parameter_s:
431 try:
432 try:
432 args = map(int,parameter_s.split())
433 args = map(int,parameter_s.split())
433 except:
434 except:
434 self.arg_err(self.dhist)
435 self.arg_err(self.dhist)
435 return
436 return
436 if len(args) == 1:
437 if len(args) == 1:
437 ini,fin = max(len(dh)-(args[0]),0),len(dh)
438 ini,fin = max(len(dh)-(args[0]),0),len(dh)
438 elif len(args) == 2:
439 elif len(args) == 2:
439 ini,fin = args
440 ini,fin = args
440 fin = min(fin, len(dh))
441 fin = min(fin, len(dh))
441 else:
442 else:
442 self.arg_err(self.dhist)
443 self.arg_err(self.dhist)
443 return
444 return
444 else:
445 else:
445 ini,fin = 0,len(dh)
446 ini,fin = 0,len(dh)
446 print('Directory history (kept in _dh)')
447 print('Directory history (kept in _dh)')
447 for i in range(ini, fin):
448 for i in range(ini, fin):
448 print("%d: %s" % (i, dh[i]))
449 print("%d: %s" % (i, dh[i]))
449
450
450 @skip_doctest
451 @skip_doctest
451 @line_magic
452 @line_magic
452 def sc(self, parameter_s=''):
453 def sc(self, parameter_s=''):
453 """Shell capture - run shell command and capture output (DEPRECATED use !).
454 """Shell capture - run shell command and capture output (DEPRECATED use !).
454
455
455 DEPRECATED. Suboptimal, retained for backwards compatibility.
456 DEPRECATED. Suboptimal, retained for backwards compatibility.
456
457
457 You should use the form 'var = !command' instead. Example:
458 You should use the form 'var = !command' instead. Example:
458
459
459 "%sc -l myfiles = ls ~" should now be written as
460 "%sc -l myfiles = ls ~" should now be written as
460
461
461 "myfiles = !ls ~"
462 "myfiles = !ls ~"
462
463
463 myfiles.s, myfiles.l and myfiles.n still apply as documented
464 myfiles.s, myfiles.l and myfiles.n still apply as documented
464 below.
465 below.
465
466
466 --
467 --
467 %sc [options] varname=command
468 %sc [options] varname=command
468
469
469 IPython will run the given command using commands.getoutput(), and
470 IPython will run the given command using commands.getoutput(), and
470 will then update the user's interactive namespace with a variable
471 will then update the user's interactive namespace with a variable
471 called varname, containing the value of the call. Your command can
472 called varname, containing the value of the call. Your command can
472 contain shell wildcards, pipes, etc.
473 contain shell wildcards, pipes, etc.
473
474
474 The '=' sign in the syntax is mandatory, and the variable name you
475 The '=' sign in the syntax is mandatory, and the variable name you
475 supply must follow Python's standard conventions for valid names.
476 supply must follow Python's standard conventions for valid names.
476
477
477 (A special format without variable name exists for internal use)
478 (A special format without variable name exists for internal use)
478
479
479 Options:
480 Options:
480
481
481 -l: list output. Split the output on newlines into a list before
482 -l: list output. Split the output on newlines into a list before
482 assigning it to the given variable. By default the output is stored
483 assigning it to the given variable. By default the output is stored
483 as a single string.
484 as a single string.
484
485
485 -v: verbose. Print the contents of the variable.
486 -v: verbose. Print the contents of the variable.
486
487
487 In most cases you should not need to split as a list, because the
488 In most cases you should not need to split as a list, because the
488 returned value is a special type of string which can automatically
489 returned value is a special type of string which can automatically
489 provide its contents either as a list (split on newlines) or as a
490 provide its contents either as a list (split on newlines) or as a
490 space-separated string. These are convenient, respectively, either
491 space-separated string. These are convenient, respectively, either
491 for sequential processing or to be passed to a shell command.
492 for sequential processing or to be passed to a shell command.
492
493
493 For example::
494 For example::
494
495
495 # Capture into variable a
496 # Capture into variable a
496 In [1]: sc a=ls *py
497 In [1]: sc a=ls *py
497
498
498 # a is a string with embedded newlines
499 # a is a string with embedded newlines
499 In [2]: a
500 In [2]: a
500 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
501 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
501
502
502 # which can be seen as a list:
503 # which can be seen as a list:
503 In [3]: a.l
504 In [3]: a.l
504 Out[3]: ['setup.py', 'win32_manual_post_install.py']
505 Out[3]: ['setup.py', 'win32_manual_post_install.py']
505
506
506 # or as a whitespace-separated string:
507 # or as a whitespace-separated string:
507 In [4]: a.s
508 In [4]: a.s
508 Out[4]: 'setup.py win32_manual_post_install.py'
509 Out[4]: 'setup.py win32_manual_post_install.py'
509
510
510 # a.s is useful to pass as a single command line:
511 # a.s is useful to pass as a single command line:
511 In [5]: !wc -l $a.s
512 In [5]: !wc -l $a.s
512 146 setup.py
513 146 setup.py
513 130 win32_manual_post_install.py
514 130 win32_manual_post_install.py
514 276 total
515 276 total
515
516
516 # while the list form is useful to loop over:
517 # while the list form is useful to loop over:
517 In [6]: for f in a.l:
518 In [6]: for f in a.l:
518 ...: !wc -l $f
519 ...: !wc -l $f
519 ...:
520 ...:
520 146 setup.py
521 146 setup.py
521 130 win32_manual_post_install.py
522 130 win32_manual_post_install.py
522
523
523 Similarly, the lists returned by the -l option are also special, in
524 Similarly, the lists returned by the -l option are also special, in
524 the sense that you can equally invoke the .s attribute on them to
525 the sense that you can equally invoke the .s attribute on them to
525 automatically get a whitespace-separated string from their contents::
526 automatically get a whitespace-separated string from their contents::
526
527
527 In [7]: sc -l b=ls *py
528 In [7]: sc -l b=ls *py
528
529
529 In [8]: b
530 In [8]: b
530 Out[8]: ['setup.py', 'win32_manual_post_install.py']
531 Out[8]: ['setup.py', 'win32_manual_post_install.py']
531
532
532 In [9]: b.s
533 In [9]: b.s
533 Out[9]: 'setup.py win32_manual_post_install.py'
534 Out[9]: 'setup.py win32_manual_post_install.py'
534
535
535 In summary, both the lists and strings used for output capture have
536 In summary, both the lists and strings used for output capture have
536 the following special attributes::
537 the following special attributes::
537
538
538 .l (or .list) : value as list.
539 .l (or .list) : value as list.
539 .n (or .nlstr): value as newline-separated string.
540 .n (or .nlstr): value as newline-separated string.
540 .s (or .spstr): value as space-separated string.
541 .s (or .spstr): value as space-separated string.
541 """
542 """
542
543
543 opts,args = self.parse_options(parameter_s, 'lv')
544 opts,args = self.parse_options(parameter_s, 'lv')
544 # Try to get a variable name and command to run
545 # Try to get a variable name and command to run
545 try:
546 try:
546 # the variable name must be obtained from the parse_options
547 # the variable name must be obtained from the parse_options
547 # output, which uses shlex.split to strip options out.
548 # output, which uses shlex.split to strip options out.
548 var,_ = args.split('=', 1)
549 var,_ = args.split('=', 1)
549 var = var.strip()
550 var = var.strip()
550 # But the command has to be extracted from the original input
551 # But the command has to be extracted from the original input
551 # parameter_s, not on what parse_options returns, to avoid the
552 # parameter_s, not on what parse_options returns, to avoid the
552 # quote stripping which shlex.split performs on it.
553 # quote stripping which shlex.split performs on it.
553 _,cmd = parameter_s.split('=', 1)
554 _,cmd = parameter_s.split('=', 1)
554 except ValueError:
555 except ValueError:
555 var,cmd = '',''
556 var,cmd = '',''
556 # If all looks ok, proceed
557 # If all looks ok, proceed
557 split = 'l' in opts
558 split = 'l' in opts
558 out = self.shell.getoutput(cmd, split=split)
559 out = self.shell.getoutput(cmd, split=split)
559 if 'v' in opts:
560 if 'v' in opts:
560 print('%s ==\n%s' % (var, pformat(out)))
561 print('%s ==\n%s' % (var, pformat(out)))
561 if var:
562 if var:
562 self.shell.user_ns.update({var:out})
563 self.shell.user_ns.update({var:out})
563 else:
564 else:
564 return out
565 return out
565
566
566 @line_cell_magic
567 @line_cell_magic
567 def sx(self, line='', cell=None):
568 def sx(self, line='', cell=None):
568 """Shell execute - run shell command and capture output (!! is short-hand).
569 """Shell execute - run shell command and capture output (!! is short-hand).
569
570
570 %sx command
571 %sx command
571
572
572 IPython will run the given command using commands.getoutput(), and
573 IPython will run the given command using commands.getoutput(), and
573 return the result formatted as a list (split on '\\n'). Since the
574 return the result formatted as a list (split on '\\n'). Since the
574 output is _returned_, it will be stored in ipython's regular output
575 output is _returned_, it will be stored in ipython's regular output
575 cache Out[N] and in the '_N' automatic variables.
576 cache Out[N] and in the '_N' automatic variables.
576
577
577 Notes:
578 Notes:
578
579
579 1) If an input line begins with '!!', then %sx is automatically
580 1) If an input line begins with '!!', then %sx is automatically
580 invoked. That is, while::
581 invoked. That is, while::
581
582
582 !ls
583 !ls
583
584
584 causes ipython to simply issue system('ls'), typing::
585 causes ipython to simply issue system('ls'), typing::
585
586
586 !!ls
587 !!ls
587
588
588 is a shorthand equivalent to::
589 is a shorthand equivalent to::
589
590
590 %sx ls
591 %sx ls
591
592
592 2) %sx differs from %sc in that %sx automatically splits into a list,
593 2) %sx differs from %sc in that %sx automatically splits into a list,
593 like '%sc -l'. The reason for this is to make it as easy as possible
594 like '%sc -l'. The reason for this is to make it as easy as possible
594 to process line-oriented shell output via further python commands.
595 to process line-oriented shell output via further python commands.
595 %sc is meant to provide much finer control, but requires more
596 %sc is meant to provide much finer control, but requires more
596 typing.
597 typing.
597
598
598 3) Just like %sc -l, this is a list with special attributes:
599 3) Just like %sc -l, this is a list with special attributes:
599 ::
600 ::
600
601
601 .l (or .list) : value as list.
602 .l (or .list) : value as list.
602 .n (or .nlstr): value as newline-separated string.
603 .n (or .nlstr): value as newline-separated string.
603 .s (or .spstr): value as whitespace-separated string.
604 .s (or .spstr): value as whitespace-separated string.
604
605
605 This is very useful when trying to use such lists as arguments to
606 This is very useful when trying to use such lists as arguments to
606 system commands."""
607 system commands."""
607
608
608 if cell is None:
609 if cell is None:
609 # line magic
610 # line magic
610 return self.shell.getoutput(line)
611 return self.shell.getoutput(line)
611 else:
612 else:
612 opts,args = self.parse_options(line, '', 'out=')
613 opts,args = self.parse_options(line, '', 'out=')
613 output = self.shell.getoutput(cell)
614 output = self.shell.getoutput(cell)
614 out_name = opts.get('out', opts.get('o'))
615 out_name = opts.get('out', opts.get('o'))
615 if out_name:
616 if out_name:
616 self.shell.user_ns[out_name] = output
617 self.shell.user_ns[out_name] = output
617 else:
618 else:
618 return output
619 return output
619
620
620 system = line_cell_magic('system')(sx)
621 system = line_cell_magic('system')(sx)
621 bang = cell_magic('!')(sx)
622 bang = cell_magic('!')(sx)
622
623
623 @line_magic
624 @line_magic
624 def bookmark(self, parameter_s=''):
625 def bookmark(self, parameter_s=''):
625 """Manage IPython's bookmark system.
626 """Manage IPython's bookmark system.
626
627
627 %bookmark <name> - set bookmark to current dir
628 %bookmark <name> - set bookmark to current dir
628 %bookmark <name> <dir> - set bookmark to <dir>
629 %bookmark <name> <dir> - set bookmark to <dir>
629 %bookmark -l - list all bookmarks
630 %bookmark -l - list all bookmarks
630 %bookmark -d <name> - remove bookmark
631 %bookmark -d <name> - remove bookmark
631 %bookmark -r - remove all bookmarks
632 %bookmark -r - remove all bookmarks
632
633
633 You can later on access a bookmarked folder with::
634 You can later on access a bookmarked folder with::
634
635
635 %cd -b <name>
636 %cd -b <name>
636
637
637 or simply '%cd <name>' if there is no directory called <name> AND
638 or simply '%cd <name>' if there is no directory called <name> AND
638 there is such a bookmark defined.
639 there is such a bookmark defined.
639
640
640 Your bookmarks persist through IPython sessions, but they are
641 Your bookmarks persist through IPython sessions, but they are
641 associated with each profile."""
642 associated with each profile."""
642
643
643 opts,args = self.parse_options(parameter_s,'drl',mode='list')
644 opts,args = self.parse_options(parameter_s,'drl',mode='list')
644 if len(args) > 2:
645 if len(args) > 2:
645 raise UsageError("%bookmark: too many arguments")
646 raise UsageError("%bookmark: too many arguments")
646
647
647 bkms = self.shell.db.get('bookmarks',{})
648 bkms = self.shell.db.get('bookmarks',{})
648
649
649 if 'd' in opts:
650 if 'd' in opts:
650 try:
651 try:
651 todel = args[0]
652 todel = args[0]
652 except IndexError:
653 except IndexError:
653 raise UsageError(
654 raise UsageError(
654 "%bookmark -d: must provide a bookmark to delete")
655 "%bookmark -d: must provide a bookmark to delete")
655 else:
656 else:
656 try:
657 try:
657 del bkms[todel]
658 del bkms[todel]
658 except KeyError:
659 except KeyError:
659 raise UsageError(
660 raise UsageError(
660 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
661 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
661
662
662 elif 'r' in opts:
663 elif 'r' in opts:
663 bkms = {}
664 bkms = {}
664 elif 'l' in opts:
665 elif 'l' in opts:
665 bks = bkms.keys()
666 bks = bkms.keys()
666 bks.sort()
667 bks.sort()
667 if bks:
668 if bks:
668 size = max(map(len, bks))
669 size = max(map(len, bks))
669 else:
670 else:
670 size = 0
671 size = 0
671 fmt = '%-'+str(size)+'s -> %s'
672 fmt = '%-'+str(size)+'s -> %s'
672 print('Current bookmarks:')
673 print('Current bookmarks:')
673 for bk in bks:
674 for bk in bks:
674 print(fmt % (bk, bkms[bk]))
675 print(fmt % (bk, bkms[bk]))
675 else:
676 else:
676 if not args:
677 if not args:
677 raise UsageError("%bookmark: You must specify the bookmark name")
678 raise UsageError("%bookmark: You must specify the bookmark name")
678 elif len(args)==1:
679 elif len(args)==1:
679 bkms[args[0]] = os.getcwdu()
680 bkms[args[0]] = py3compat.getcwd()
680 elif len(args)==2:
681 elif len(args)==2:
681 bkms[args[0]] = args[1]
682 bkms[args[0]] = args[1]
682 self.shell.db['bookmarks'] = bkms
683 self.shell.db['bookmarks'] = bkms
683
684
684 @line_magic
685 @line_magic
685 def pycat(self, parameter_s=''):
686 def pycat(self, parameter_s=''):
686 """Show a syntax-highlighted file through a pager.
687 """Show a syntax-highlighted file through a pager.
687
688
688 This magic is similar to the cat utility, but it will assume the file
689 This magic is similar to the cat utility, but it will assume the file
689 to be Python source and will show it with syntax highlighting.
690 to be Python source and will show it with syntax highlighting.
690
691
691 This magic command can either take a local filename, an url,
692 This magic command can either take a local filename, an url,
692 an history range (see %history) or a macro as argument ::
693 an history range (see %history) or a macro as argument ::
693
694
694 %pycat myscript.py
695 %pycat myscript.py
695 %pycat 7-27
696 %pycat 7-27
696 %pycat myMacro
697 %pycat myMacro
697 %pycat http://www.example.com/myscript.py
698 %pycat http://www.example.com/myscript.py
698 """
699 """
699 if not parameter_s:
700 if not parameter_s:
700 raise UsageError('Missing filename, URL, input history range, '
701 raise UsageError('Missing filename, URL, input history range, '
701 'or macro.')
702 'or macro.')
702
703
703 try :
704 try :
704 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
705 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
705 except (ValueError, IOError):
706 except (ValueError, IOError):
706 print("Error: no such file, variable, URL, history range or macro")
707 print("Error: no such file, variable, URL, history range or macro")
707 return
708 return
708
709
709 page.page(self.shell.pycolorize(source_to_unicode(cont)))
710 page.page(self.shell.pycolorize(source_to_unicode(cont)))
710
711
711 @magic_arguments.magic_arguments()
712 @magic_arguments.magic_arguments()
712 @magic_arguments.argument(
713 @magic_arguments.argument(
713 '-a', '--append', action='store_true', default=False,
714 '-a', '--append', action='store_true', default=False,
714 help='Append contents of the cell to an existing file. '
715 help='Append contents of the cell to an existing file. '
715 'The file will be created if it does not exist.'
716 'The file will be created if it does not exist.'
716 )
717 )
717 @magic_arguments.argument(
718 @magic_arguments.argument(
718 'filename', type=unicode_type,
719 'filename', type=unicode_type,
719 help='file to write'
720 help='file to write'
720 )
721 )
721 @cell_magic
722 @cell_magic
722 def writefile(self, line, cell):
723 def writefile(self, line, cell):
723 """Write the contents of the cell to a file.
724 """Write the contents of the cell to a file.
724
725
725 The file will be overwritten unless the -a (--append) flag is specified.
726 The file will be overwritten unless the -a (--append) flag is specified.
726 """
727 """
727 args = magic_arguments.parse_argstring(self.writefile, line)
728 args = magic_arguments.parse_argstring(self.writefile, line)
728 filename = os.path.expanduser(unquote_filename(args.filename))
729 filename = os.path.expanduser(unquote_filename(args.filename))
729
730
730 if os.path.exists(filename):
731 if os.path.exists(filename):
731 if args.append:
732 if args.append:
732 print("Appending to %s" % filename)
733 print("Appending to %s" % filename)
733 else:
734 else:
734 print("Overwriting %s" % filename)
735 print("Overwriting %s" % filename)
735 else:
736 else:
736 print("Writing %s" % filename)
737 print("Writing %s" % filename)
737
738
738 mode = 'a' if args.append else 'w'
739 mode = 'a' if args.append else 'w'
739 with io.open(filename, mode, encoding='utf-8') as f:
740 with io.open(filename, mode, encoding='utf-8') as f:
740 f.write(cell)
741 f.write(cell)
@@ -1,314 +1,315 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 IPython.config.application import Application
27 from IPython.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.utils.path import get_ipython_dir, get_ipython_package_dir
33 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
34 from IPython.utils import py3compat
34 from IPython.utils.traitlets import Unicode, Bool, Dict
35 from IPython.utils.traitlets import Unicode, Bool, Dict
35
36
36 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
37 # Constants
38 # Constants
38 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
39
40
40 create_help = """Create an IPython profile by name
41 create_help = """Create an IPython profile by name
41
42
42 Create an ipython profile directory by its name or
43 Create an ipython profile directory by its name or
43 profile directory path. Profile directories contain
44 profile directory path. Profile directories contain
44 configuration, log and security related files and are named
45 configuration, log and security related files and are named
45 using the convention 'profile_<name>'. By default they are
46 using the convention 'profile_<name>'. By default they are
46 located in your ipython directory. Once created, you will
47 located in your ipython directory. Once created, you will
47 can edit the configuration files in the profile
48 can edit the configuration files in the profile
48 directory to configure IPython. Most users will create a
49 directory to configure IPython. Most users will create a
49 profile directory by name,
50 profile directory by name,
50 `ipython profile create myprofile`, which will put the directory
51 `ipython profile create myprofile`, which will put the directory
51 in `<ipython_dir>/profile_myprofile`.
52 in `<ipython_dir>/profile_myprofile`.
52 """
53 """
53 list_help = """List available IPython profiles
54 list_help = """List available IPython profiles
54
55
55 List all available profiles, by profile location, that can
56 List all available profiles, by profile location, that can
56 be found in the current working directly or in the ipython
57 be found in the current working directly or in the ipython
57 directory. Profile directories are named using the convention
58 directory. Profile directories are named using the convention
58 'profile_<profile>'.
59 'profile_<profile>'.
59 """
60 """
60 profile_help = """Manage IPython profiles
61 profile_help = """Manage IPython profiles
61
62
62 Profile directories contain
63 Profile directories contain
63 configuration, log and security related files and are named
64 configuration, log and security related files and are named
64 using the convention 'profile_<name>'. By default they are
65 using the convention 'profile_<name>'. By default they are
65 located in your ipython directory. You can create profiles
66 located in your ipython directory. You can create profiles
66 with `ipython profile create <name>`, or see the profiles you
67 with `ipython profile create <name>`, or see the profiles you
67 already have with `ipython profile list`
68 already have with `ipython profile list`
68
69
69 To get started configuring IPython, simply do:
70 To get started configuring IPython, simply do:
70
71
71 $> ipython profile create
72 $> ipython profile create
72
73
73 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,
74 where you can edit ipython_config.py to start configuring IPython.
75 where you can edit ipython_config.py to start configuring IPython.
75
76
76 """
77 """
77
78
78 _list_examples = "ipython profile list # list all profiles"
79 _list_examples = "ipython profile list # list all profiles"
79
80
80 _create_examples = """
81 _create_examples = """
81 ipython profile create foo # create profile foo w/ default config files
82 ipython profile create foo # create profile foo w/ default config files
82 ipython profile create foo --reset # restage default config files over current
83 ipython profile create foo --reset # restage default config files over current
83 ipython profile create foo --parallel # also stage parallel config files
84 ipython profile create foo --parallel # also stage parallel config files
84 """
85 """
85
86
86 _main_examples = """
87 _main_examples = """
87 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
88 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
89
90
90 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'
91 """
92 """
92
93
93 #-----------------------------------------------------------------------------
94 #-----------------------------------------------------------------------------
94 # Profile Application Class (for `ipython profile` subcommand)
95 # Profile Application Class (for `ipython profile` subcommand)
95 #-----------------------------------------------------------------------------
96 #-----------------------------------------------------------------------------
96
97
97
98
98 def list_profiles_in(path):
99 def list_profiles_in(path):
99 """list profiles in a given root directory"""
100 """list profiles in a given root directory"""
100 files = os.listdir(path)
101 files = os.listdir(path)
101 profiles = []
102 profiles = []
102 for f in files:
103 for f in files:
103 try:
104 try:
104 full_path = os.path.join(path, f)
105 full_path = os.path.join(path, f)
105 except UnicodeError:
106 except UnicodeError:
106 continue
107 continue
107 if os.path.isdir(full_path) and f.startswith('profile_'):
108 if os.path.isdir(full_path) and f.startswith('profile_'):
108 profiles.append(f.split('_',1)[-1])
109 profiles.append(f.split('_',1)[-1])
109 return profiles
110 return profiles
110
111
111
112
112 def list_bundled_profiles():
113 def list_bundled_profiles():
113 """list profiles that are bundled with IPython."""
114 """list profiles that are bundled with IPython."""
114 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
115 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
115 files = os.listdir(path)
116 files = os.listdir(path)
116 profiles = []
117 profiles = []
117 for profile in files:
118 for profile in files:
118 full_path = os.path.join(path, profile)
119 full_path = os.path.join(path, profile)
119 if os.path.isdir(full_path) and profile != "__pycache__":
120 if os.path.isdir(full_path) and profile != "__pycache__":
120 profiles.append(profile)
121 profiles.append(profile)
121 return profiles
122 return profiles
122
123
123
124
124 class ProfileLocate(BaseIPythonApplication):
125 class ProfileLocate(BaseIPythonApplication):
125 description = """print the path to an IPython profile dir"""
126 description = """print the path to an IPython profile dir"""
126
127
127 def parse_command_line(self, argv=None):
128 def parse_command_line(self, argv=None):
128 super(ProfileLocate, self).parse_command_line(argv)
129 super(ProfileLocate, self).parse_command_line(argv)
129 if self.extra_args:
130 if self.extra_args:
130 self.profile = self.extra_args[0]
131 self.profile = self.extra_args[0]
131
132
132 def start(self):
133 def start(self):
133 print(self.profile_dir.location)
134 print(self.profile_dir.location)
134
135
135
136
136 class ProfileList(Application):
137 class ProfileList(Application):
137 name = u'ipython-profile'
138 name = u'ipython-profile'
138 description = list_help
139 description = list_help
139 examples = _list_examples
140 examples = _list_examples
140
141
141 aliases = Dict({
142 aliases = Dict({
142 'ipython-dir' : 'ProfileList.ipython_dir',
143 'ipython-dir' : 'ProfileList.ipython_dir',
143 'log-level' : 'Application.log_level',
144 'log-level' : 'Application.log_level',
144 })
145 })
145 flags = Dict(dict(
146 flags = Dict(dict(
146 debug = ({'Application' : {'log_level' : 0}},
147 debug = ({'Application' : {'log_level' : 0}},
147 "Set Application.log_level to 0, maximizing log output."
148 "Set Application.log_level to 0, maximizing log output."
148 )
149 )
149 ))
150 ))
150
151
151 ipython_dir = Unicode(get_ipython_dir(), config=True,
152 ipython_dir = Unicode(get_ipython_dir(), config=True,
152 help="""
153 help="""
153 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
154 configuration (through profiles), history storage, etc. The default
155 configuration (through profiles), history storage, etc. The default
155 is usually $HOME/.ipython. This options can also be specified through
156 is usually $HOME/.ipython. This options can also be specified through
156 the environment variable IPYTHONDIR.
157 the environment variable IPYTHONDIR.
157 """
158 """
158 )
159 )
159
160
160
161
161 def _print_profiles(self, profiles):
162 def _print_profiles(self, profiles):
162 """print list of profiles, indented."""
163 """print list of profiles, indented."""
163 for profile in profiles:
164 for profile in profiles:
164 print(' %s' % profile)
165 print(' %s' % profile)
165
166
166 def list_profile_dirs(self):
167 def list_profile_dirs(self):
167 profiles = list_bundled_profiles()
168 profiles = list_bundled_profiles()
168 if profiles:
169 if profiles:
169 print()
170 print()
170 print("Available profiles in IPython:")
171 print("Available profiles in IPython:")
171 self._print_profiles(profiles)
172 self._print_profiles(profiles)
172 print()
173 print()
173 print(" The first request for a bundled profile will copy it")
174 print(" The first request for a bundled profile will copy it")
174 print(" into your IPython directory (%s)," % self.ipython_dir)
175 print(" into your IPython directory (%s)," % self.ipython_dir)
175 print(" where you can customize it.")
176 print(" where you can customize it.")
176
177
177 profiles = list_profiles_in(self.ipython_dir)
178 profiles = list_profiles_in(self.ipython_dir)
178 if profiles:
179 if profiles:
179 print()
180 print()
180 print("Available profiles in %s:" % self.ipython_dir)
181 print("Available profiles in %s:" % self.ipython_dir)
181 self._print_profiles(profiles)
182 self._print_profiles(profiles)
182
183
183 profiles = list_profiles_in(os.getcwdu())
184 profiles = list_profiles_in(py3compat.getcwd())
184 if profiles:
185 if profiles:
185 print()
186 print()
186 print("Available profiles in current directory (%s):" % os.getcwdu())
187 print("Available profiles in current directory (%s):" % py3compat.getcwd())
187 self._print_profiles(profiles)
188 self._print_profiles(profiles)
188
189
189 print()
190 print()
190 print("To use any of the above profiles, start IPython with:")
191 print("To use any of the above profiles, start IPython with:")
191 print(" ipython --profile=<name>")
192 print(" ipython --profile=<name>")
192 print()
193 print()
193
194
194 def start(self):
195 def start(self):
195 self.list_profile_dirs()
196 self.list_profile_dirs()
196
197
197
198
198 create_flags = {}
199 create_flags = {}
199 create_flags.update(base_flags)
200 create_flags.update(base_flags)
200 # 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
201 create_flags.pop('init')
202 create_flags.pop('init')
202 create_flags['reset'] = ({'ProfileCreate': {'overwrite' : True}},
203 create_flags['reset'] = ({'ProfileCreate': {'overwrite' : True}},
203 "reset config files in this profile to the defaults.")
204 "reset config files in this profile to the defaults.")
204 create_flags['parallel'] = ({'ProfileCreate': {'parallel' : True}},
205 create_flags['parallel'] = ({'ProfileCreate': {'parallel' : True}},
205 "Include the config files for parallel "
206 "Include the config files for parallel "
206 "computing apps (ipengine, ipcontroller, etc.)")
207 "computing apps (ipengine, ipcontroller, etc.)")
207
208
208
209
209 class ProfileCreate(BaseIPythonApplication):
210 class ProfileCreate(BaseIPythonApplication):
210 name = u'ipython-profile'
211 name = u'ipython-profile'
211 description = create_help
212 description = create_help
212 examples = _create_examples
213 examples = _create_examples
213 auto_create = Bool(True, config=False)
214 auto_create = Bool(True, config=False)
214 def _log_format_default(self):
215 def _log_format_default(self):
215 return "[%(name)s] %(message)s"
216 return "[%(name)s] %(message)s"
216
217
217 def _copy_config_files_default(self):
218 def _copy_config_files_default(self):
218 return True
219 return True
219
220
220 parallel = Bool(False, config=True,
221 parallel = Bool(False, config=True,
221 help="whether to include parallel computing config files")
222 help="whether to include parallel computing config files")
222 def _parallel_changed(self, name, old, new):
223 def _parallel_changed(self, name, old, new):
223 parallel_files = [ 'ipcontroller_config.py',
224 parallel_files = [ 'ipcontroller_config.py',
224 'ipengine_config.py',
225 'ipengine_config.py',
225 'ipcluster_config.py'
226 'ipcluster_config.py'
226 ]
227 ]
227 if new:
228 if new:
228 for cf in parallel_files:
229 for cf in parallel_files:
229 self.config_files.append(cf)
230 self.config_files.append(cf)
230 else:
231 else:
231 for cf in parallel_files:
232 for cf in parallel_files:
232 if cf in self.config_files:
233 if cf in self.config_files:
233 self.config_files.remove(cf)
234 self.config_files.remove(cf)
234
235
235 def parse_command_line(self, argv):
236 def parse_command_line(self, argv):
236 super(ProfileCreate, self).parse_command_line(argv)
237 super(ProfileCreate, self).parse_command_line(argv)
237 # accept positional arg as profile name
238 # accept positional arg as profile name
238 if self.extra_args:
239 if self.extra_args:
239 self.profile = self.extra_args[0]
240 self.profile = self.extra_args[0]
240
241
241 flags = Dict(create_flags)
242 flags = Dict(create_flags)
242
243
243 classes = [ProfileDir]
244 classes = [ProfileDir]
244
245
245 def _import_app(self, app_path):
246 def _import_app(self, app_path):
246 """import an app class"""
247 """import an app class"""
247 app = None
248 app = None
248 name = app_path.rsplit('.', 1)[-1]
249 name = app_path.rsplit('.', 1)[-1]
249 try:
250 try:
250 app = import_item(app_path)
251 app = import_item(app_path)
251 except ImportError as e:
252 except ImportError:
252 self.log.info("Couldn't import %s, config file will be excluded", name)
253 self.log.info("Couldn't import %s, config file will be excluded", name)
253 except Exception:
254 except Exception:
254 self.log.warn('Unexpected error importing %s', name, exc_info=True)
255 self.log.warn('Unexpected error importing %s', name, exc_info=True)
255 return app
256 return app
256
257
257 def init_config_files(self):
258 def init_config_files(self):
258 super(ProfileCreate, self).init_config_files()
259 super(ProfileCreate, self).init_config_files()
259 # use local imports, since these classes may import from here
260 # use local imports, since these classes may import from here
260 from IPython.terminal.ipapp import TerminalIPythonApp
261 from IPython.terminal.ipapp import TerminalIPythonApp
261 apps = [TerminalIPythonApp]
262 apps = [TerminalIPythonApp]
262 for app_path in (
263 for app_path in (
263 'IPython.qt.console.qtconsoleapp.IPythonQtConsoleApp',
264 'IPython.qt.console.qtconsoleapp.IPythonQtConsoleApp',
264 'IPython.html.notebookapp.NotebookApp',
265 'IPython.html.notebookapp.NotebookApp',
265 'IPython.nbconvert.nbconvertapp.NbConvertApp',
266 'IPython.nbconvert.nbconvertapp.NbConvertApp',
266 ):
267 ):
267 app = self._import_app(app_path)
268 app = self._import_app(app_path)
268 if app is not None:
269 if app is not None:
269 apps.append(app)
270 apps.append(app)
270 if self.parallel:
271 if self.parallel:
271 from IPython.parallel.apps.ipcontrollerapp import IPControllerApp
272 from IPython.parallel.apps.ipcontrollerapp import IPControllerApp
272 from IPython.parallel.apps.ipengineapp import IPEngineApp
273 from IPython.parallel.apps.ipengineapp import IPEngineApp
273 from IPython.parallel.apps.ipclusterapp import IPClusterStart
274 from IPython.parallel.apps.ipclusterapp import IPClusterStart
274 from IPython.parallel.apps.iploggerapp import IPLoggerApp
275 from IPython.parallel.apps.iploggerapp import IPLoggerApp
275 apps.extend([
276 apps.extend([
276 IPControllerApp,
277 IPControllerApp,
277 IPEngineApp,
278 IPEngineApp,
278 IPClusterStart,
279 IPClusterStart,
279 IPLoggerApp,
280 IPLoggerApp,
280 ])
281 ])
281 for App in apps:
282 for App in apps:
282 app = App()
283 app = App()
283 app.config.update(self.config)
284 app.config.update(self.config)
284 app.log = self.log
285 app.log = self.log
285 app.overwrite = self.overwrite
286 app.overwrite = self.overwrite
286 app.copy_config_files=True
287 app.copy_config_files=True
287 app.profile = self.profile
288 app.profile = self.profile
288 app.init_profile_dir()
289 app.init_profile_dir()
289 app.init_config_files()
290 app.init_config_files()
290
291
291 def stage_default_config_file(self):
292 def stage_default_config_file(self):
292 pass
293 pass
293
294
294
295
295 class ProfileApp(Application):
296 class ProfileApp(Application):
296 name = u'ipython-profile'
297 name = u'ipython-profile'
297 description = profile_help
298 description = profile_help
298 examples = _main_examples
299 examples = _main_examples
299
300
300 subcommands = Dict(dict(
301 subcommands = Dict(dict(
301 create = (ProfileCreate, ProfileCreate.description.splitlines()[0]),
302 create = (ProfileCreate, ProfileCreate.description.splitlines()[0]),
302 list = (ProfileList, ProfileList.description.splitlines()[0]),
303 list = (ProfileList, ProfileList.description.splitlines()[0]),
303 locate = (ProfileLocate, ProfileLocate.description.splitlines()[0]),
304 locate = (ProfileLocate, ProfileLocate.description.splitlines()[0]),
304 ))
305 ))
305
306
306 def start(self):
307 def start(self):
307 if self.subapp is None:
308 if self.subapp is None:
308 print("No subcommand specified. Must specify one of: %s"%(self.subcommands.keys()))
309 print("No subcommand specified. Must specify one of: %s"%(self.subcommands.keys()))
309 print()
310 print()
310 self.print_description()
311 self.print_description()
311 self.print_subcommands()
312 self.print_subcommands()
312 self.exit(1)
313 self.exit(1)
313 else:
314 else:
314 return self.subapp.start()
315 return self.subapp.start()
@@ -1,273 +1,274 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 An object for managing IPython profile directories.
3 An object for managing IPython profile directories.
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 * Fernando Perez
8 * Fernando Perez
9 * Min RK
9 * Min RK
10
10
11 """
11 """
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Copyright (C) 2011 The IPython Development Team
14 # Copyright (C) 2011 The IPython Development Team
15 #
15 #
16 # Distributed under the terms of the BSD License. The full license is in
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
17 # the file COPYING, distributed as part of this software.
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Imports
21 # Imports
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 import os
24 import os
25 import shutil
25 import shutil
26 import errno
26 import errno
27
27
28 from IPython.config.configurable import LoggingConfigurable
28 from IPython.config.configurable import LoggingConfigurable
29 from IPython.utils.path import get_ipython_package_dir, expand_path
29 from IPython.utils.path import get_ipython_package_dir, expand_path
30 from IPython.utils import py3compat
30 from IPython.utils.traitlets import Unicode, Bool
31 from IPython.utils.traitlets import Unicode, Bool
31
32
32 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
33 # Classes and functions
34 # Classes and functions
34 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
35
36
36
37
37 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
38 # Module errors
39 # Module errors
39 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
40
41
41 class ProfileDirError(Exception):
42 class ProfileDirError(Exception):
42 pass
43 pass
43
44
44
45
45 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
46 # Class for managing profile directories
47 # Class for managing profile directories
47 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
48
49
49 class ProfileDir(LoggingConfigurable):
50 class ProfileDir(LoggingConfigurable):
50 """An object to manage the profile directory and its resources.
51 """An object to manage the profile directory and its resources.
51
52
52 The profile directory is used by all IPython applications, to manage
53 The profile directory is used by all IPython applications, to manage
53 configuration, logging and security.
54 configuration, logging and security.
54
55
55 This object knows how to find, create and manage these directories. This
56 This object knows how to find, create and manage these directories. This
56 should be used by any code that wants to handle profiles.
57 should be used by any code that wants to handle profiles.
57 """
58 """
58
59
59 security_dir_name = Unicode('security')
60 security_dir_name = Unicode('security')
60 log_dir_name = Unicode('log')
61 log_dir_name = Unicode('log')
61 startup_dir_name = Unicode('startup')
62 startup_dir_name = Unicode('startup')
62 pid_dir_name = Unicode('pid')
63 pid_dir_name = Unicode('pid')
63 static_dir_name = Unicode('static')
64 static_dir_name = Unicode('static')
64 security_dir = Unicode(u'')
65 security_dir = Unicode(u'')
65 log_dir = Unicode(u'')
66 log_dir = Unicode(u'')
66 startup_dir = Unicode(u'')
67 startup_dir = Unicode(u'')
67 pid_dir = Unicode(u'')
68 pid_dir = Unicode(u'')
68 static_dir = Unicode(u'')
69 static_dir = Unicode(u'')
69
70
70 location = Unicode(u'', config=True,
71 location = Unicode(u'', config=True,
71 help="""Set the profile location directly. This overrides the logic used by the
72 help="""Set the profile location directly. This overrides the logic used by the
72 `profile` option.""",
73 `profile` option.""",
73 )
74 )
74
75
75 _location_isset = Bool(False) # flag for detecting multiply set location
76 _location_isset = Bool(False) # flag for detecting multiply set location
76
77
77 def _location_changed(self, name, old, new):
78 def _location_changed(self, name, old, new):
78 if self._location_isset:
79 if self._location_isset:
79 raise RuntimeError("Cannot set profile location more than once.")
80 raise RuntimeError("Cannot set profile location more than once.")
80 self._location_isset = True
81 self._location_isset = True
81 if not os.path.isdir(new):
82 if not os.path.isdir(new):
82 os.makedirs(new)
83 os.makedirs(new)
83
84
84 # ensure config files exist:
85 # ensure config files exist:
85 self.security_dir = os.path.join(new, self.security_dir_name)
86 self.security_dir = os.path.join(new, self.security_dir_name)
86 self.log_dir = os.path.join(new, self.log_dir_name)
87 self.log_dir = os.path.join(new, self.log_dir_name)
87 self.startup_dir = os.path.join(new, self.startup_dir_name)
88 self.startup_dir = os.path.join(new, self.startup_dir_name)
88 self.pid_dir = os.path.join(new, self.pid_dir_name)
89 self.pid_dir = os.path.join(new, self.pid_dir_name)
89 self.static_dir = os.path.join(new, self.static_dir_name)
90 self.static_dir = os.path.join(new, self.static_dir_name)
90 self.check_dirs()
91 self.check_dirs()
91
92
92 def _log_dir_changed(self, name, old, new):
93 def _log_dir_changed(self, name, old, new):
93 self.check_log_dir()
94 self.check_log_dir()
94
95
95 def _mkdir(self, path, mode=None):
96 def _mkdir(self, path, mode=None):
96 """ensure a directory exists at a given path
97 """ensure a directory exists at a given path
97
98
98 This is a version of os.mkdir, with the following differences:
99 This is a version of os.mkdir, with the following differences:
99
100
100 - returns True if it created the directory, False otherwise
101 - returns True if it created the directory, False otherwise
101 - ignores EEXIST, protecting against race conditions where
102 - ignores EEXIST, protecting against race conditions where
102 the dir may have been created in between the check and
103 the dir may have been created in between the check and
103 the creation
104 the creation
104 - sets permissions if requested and the dir already exists
105 - sets permissions if requested and the dir already exists
105 """
106 """
106 if os.path.exists(path):
107 if os.path.exists(path):
107 if mode and os.stat(path).st_mode != mode:
108 if mode and os.stat(path).st_mode != mode:
108 try:
109 try:
109 os.chmod(path, mode)
110 os.chmod(path, mode)
110 except OSError:
111 except OSError:
111 self.log.warn(
112 self.log.warn(
112 "Could not set permissions on %s",
113 "Could not set permissions on %s",
113 path
114 path
114 )
115 )
115 return False
116 return False
116 try:
117 try:
117 if mode:
118 if mode:
118 os.mkdir(path, mode)
119 os.mkdir(path, mode)
119 else:
120 else:
120 os.mkdir(path)
121 os.mkdir(path)
121 except OSError as e:
122 except OSError as e:
122 if e.errno == errno.EEXIST:
123 if e.errno == errno.EEXIST:
123 return False
124 return False
124 else:
125 else:
125 raise
126 raise
126
127
127 return True
128 return True
128
129
129 def check_log_dir(self):
130 def check_log_dir(self):
130 self._mkdir(self.log_dir)
131 self._mkdir(self.log_dir)
131
132
132 def _startup_dir_changed(self, name, old, new):
133 def _startup_dir_changed(self, name, old, new):
133 self.check_startup_dir()
134 self.check_startup_dir()
134
135
135 def check_startup_dir(self):
136 def check_startup_dir(self):
136 self._mkdir(self.startup_dir)
137 self._mkdir(self.startup_dir)
137
138
138 readme = os.path.join(self.startup_dir, 'README')
139 readme = os.path.join(self.startup_dir, 'README')
139 src = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'README_STARTUP')
140 src = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'README_STARTUP')
140
141
141 if not os.path.exists(src):
142 if not os.path.exists(src):
142 self.log.warn("Could not copy README_STARTUP to startup dir. Source file %s does not exist.", src)
143 self.log.warn("Could not copy README_STARTUP to startup dir. Source file %s does not exist.", src)
143
144
144 if os.path.exists(src) and not os.path.exists(readme):
145 if os.path.exists(src) and not os.path.exists(readme):
145 shutil.copy(src, readme)
146 shutil.copy(src, readme)
146
147
147 def _security_dir_changed(self, name, old, new):
148 def _security_dir_changed(self, name, old, new):
148 self.check_security_dir()
149 self.check_security_dir()
149
150
150 def check_security_dir(self):
151 def check_security_dir(self):
151 self._mkdir(self.security_dir, 0o40700)
152 self._mkdir(self.security_dir, 0o40700)
152
153
153 def _pid_dir_changed(self, name, old, new):
154 def _pid_dir_changed(self, name, old, new):
154 self.check_pid_dir()
155 self.check_pid_dir()
155
156
156 def check_pid_dir(self):
157 def check_pid_dir(self):
157 self._mkdir(self.pid_dir, 0o40700)
158 self._mkdir(self.pid_dir, 0o40700)
158
159
159 def _static_dir_changed(self, name, old, new):
160 def _static_dir_changed(self, name, old, new):
160 self.check_startup_dir()
161 self.check_startup_dir()
161
162
162 def check_static_dir(self):
163 def check_static_dir(self):
163 self._mkdir(self.static_dir)
164 self._mkdir(self.static_dir)
164 custom = os.path.join(self.static_dir, 'custom')
165 custom = os.path.join(self.static_dir, 'custom')
165 self._mkdir(custom)
166 self._mkdir(custom)
166 from IPython.html import DEFAULT_STATIC_FILES_PATH
167 from IPython.html import DEFAULT_STATIC_FILES_PATH
167 for fname in ('custom.js', 'custom.css'):
168 for fname in ('custom.js', 'custom.css'):
168 src = os.path.join(DEFAULT_STATIC_FILES_PATH, 'custom', fname)
169 src = os.path.join(DEFAULT_STATIC_FILES_PATH, 'custom', fname)
169 dest = os.path.join(custom, fname)
170 dest = os.path.join(custom, fname)
170 if not os.path.exists(src):
171 if not os.path.exists(src):
171 self.log.warn("Could not copy default file to static dir. Source file %s does not exist.", src)
172 self.log.warn("Could not copy default file to static dir. Source file %s does not exist.", src)
172 continue
173 continue
173 if not os.path.exists(dest):
174 if not os.path.exists(dest):
174 shutil.copy(src, dest)
175 shutil.copy(src, dest)
175
176
176 def check_dirs(self):
177 def check_dirs(self):
177 self.check_security_dir()
178 self.check_security_dir()
178 self.check_log_dir()
179 self.check_log_dir()
179 self.check_pid_dir()
180 self.check_pid_dir()
180 self.check_startup_dir()
181 self.check_startup_dir()
181 self.check_static_dir()
182 self.check_static_dir()
182
183
183 def copy_config_file(self, config_file, path=None, overwrite=False):
184 def copy_config_file(self, config_file, path=None, overwrite=False):
184 """Copy a default config file into the active profile directory.
185 """Copy a default config file into the active profile directory.
185
186
186 Default configuration files are kept in :mod:`IPython.config.default`.
187 Default configuration files are kept in :mod:`IPython.config.default`.
187 This function moves these from that location to the working profile
188 This function moves these from that location to the working profile
188 directory.
189 directory.
189 """
190 """
190 dst = os.path.join(self.location, config_file)
191 dst = os.path.join(self.location, config_file)
191 if os.path.isfile(dst) and not overwrite:
192 if os.path.isfile(dst) and not overwrite:
192 return False
193 return False
193 if path is None:
194 if path is None:
194 path = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
195 path = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
195 src = os.path.join(path, config_file)
196 src = os.path.join(path, config_file)
196 shutil.copy(src, dst)
197 shutil.copy(src, dst)
197 return True
198 return True
198
199
199 @classmethod
200 @classmethod
200 def create_profile_dir(cls, profile_dir, config=None):
201 def create_profile_dir(cls, profile_dir, config=None):
201 """Create a new profile directory given a full path.
202 """Create a new profile directory given a full path.
202
203
203 Parameters
204 Parameters
204 ----------
205 ----------
205 profile_dir : str
206 profile_dir : str
206 The full path to the profile directory. If it does exist, it will
207 The full path to the profile directory. If it does exist, it will
207 be used. If not, it will be created.
208 be used. If not, it will be created.
208 """
209 """
209 return cls(location=profile_dir, config=config)
210 return cls(location=profile_dir, config=config)
210
211
211 @classmethod
212 @classmethod
212 def create_profile_dir_by_name(cls, path, name=u'default', config=None):
213 def create_profile_dir_by_name(cls, path, name=u'default', config=None):
213 """Create a profile dir by profile name and path.
214 """Create a profile dir by profile name and path.
214
215
215 Parameters
216 Parameters
216 ----------
217 ----------
217 path : unicode
218 path : unicode
218 The path (directory) to put the profile directory in.
219 The path (directory) to put the profile directory in.
219 name : unicode
220 name : unicode
220 The name of the profile. The name of the profile directory will
221 The name of the profile. The name of the profile directory will
221 be "profile_<profile>".
222 be "profile_<profile>".
222 """
223 """
223 if not os.path.isdir(path):
224 if not os.path.isdir(path):
224 raise ProfileDirError('Directory not found: %s' % path)
225 raise ProfileDirError('Directory not found: %s' % path)
225 profile_dir = os.path.join(path, u'profile_' + name)
226 profile_dir = os.path.join(path, u'profile_' + name)
226 return cls(location=profile_dir, config=config)
227 return cls(location=profile_dir, config=config)
227
228
228 @classmethod
229 @classmethod
229 def find_profile_dir_by_name(cls, ipython_dir, name=u'default', config=None):
230 def find_profile_dir_by_name(cls, ipython_dir, name=u'default', config=None):
230 """Find an existing profile dir by profile name, return its ProfileDir.
231 """Find an existing profile dir by profile name, return its ProfileDir.
231
232
232 This searches through a sequence of paths for a profile dir. If it
233 This searches through a sequence of paths for a profile dir. If it
233 is not found, a :class:`ProfileDirError` exception will be raised.
234 is not found, a :class:`ProfileDirError` exception will be raised.
234
235
235 The search path algorithm is:
236 The search path algorithm is:
236 1. ``os.getcwdu()``
237 1. ``py3compat.getcwd()``
237 2. ``ipython_dir``
238 2. ``ipython_dir``
238
239
239 Parameters
240 Parameters
240 ----------
241 ----------
241 ipython_dir : unicode or str
242 ipython_dir : unicode or str
242 The IPython directory to use.
243 The IPython directory to use.
243 name : unicode or str
244 name : unicode or str
244 The name of the profile. The name of the profile directory
245 The name of the profile. The name of the profile directory
245 will be "profile_<profile>".
246 will be "profile_<profile>".
246 """
247 """
247 dirname = u'profile_' + name
248 dirname = u'profile_' + name
248 paths = [os.getcwdu(), ipython_dir]
249 paths = [py3compat.getcwd(), ipython_dir]
249 for p in paths:
250 for p in paths:
250 profile_dir = os.path.join(p, dirname)
251 profile_dir = os.path.join(p, dirname)
251 if os.path.isdir(profile_dir):
252 if os.path.isdir(profile_dir):
252 return cls(location=profile_dir, config=config)
253 return cls(location=profile_dir, config=config)
253 else:
254 else:
254 raise ProfileDirError('Profile directory not found in paths: %s' % dirname)
255 raise ProfileDirError('Profile directory not found in paths: %s' % dirname)
255
256
256 @classmethod
257 @classmethod
257 def find_profile_dir(cls, profile_dir, config=None):
258 def find_profile_dir(cls, profile_dir, config=None):
258 """Find/create a profile dir and return its ProfileDir.
259 """Find/create a profile dir and return its ProfileDir.
259
260
260 This will create the profile directory if it doesn't exist.
261 This will create the profile directory if it doesn't exist.
261
262
262 Parameters
263 Parameters
263 ----------
264 ----------
264 profile_dir : unicode or str
265 profile_dir : unicode or str
265 The path of the profile directory. This is expanded using
266 The path of the profile directory. This is expanded using
266 :func:`IPython.utils.genutils.expand_path`.
267 :func:`IPython.utils.genutils.expand_path`.
267 """
268 """
268 profile_dir = expand_path(profile_dir)
269 profile_dir = expand_path(profile_dir)
269 if not os.path.isdir(profile_dir):
270 if not os.path.isdir(profile_dir):
270 raise ProfileDirError('Profile directory not found: %s' % profile_dir)
271 raise ProfileDirError('Profile directory not found: %s' % profile_dir)
271 return cls(location=profile_dir, config=config)
272 return cls(location=profile_dir, config=config)
272
273
273
274
@@ -1,439 +1,439 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Classes for handling input/output prompts.
2 """Classes for handling input/output prompts.
3
3
4 Authors:
4 Authors:
5
5
6 * Fernando Perez
6 * Fernando Perez
7 * Brian Granger
7 * Brian Granger
8 * Thomas Kluyver
8 * Thomas Kluyver
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2011 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
13 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import os
23 import os
24 import re
24 import re
25 import socket
25 import socket
26 import sys
26 import sys
27 import time
27 import time
28
28
29 from string import Formatter
29 from string import Formatter
30
30
31 from IPython.config.configurable import Configurable
31 from IPython.config.configurable import Configurable
32 from IPython.core import release
32 from IPython.core import release
33 from IPython.utils import coloransi, py3compat
33 from IPython.utils import coloransi, py3compat
34 from IPython.utils.traitlets import (Unicode, Instance, Dict, Bool, Int)
34 from IPython.utils.traitlets import (Unicode, Instance, Dict, Bool, Int)
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Color schemes for prompts
37 # Color schemes for prompts
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39
39
40 InputColors = coloransi.InputTermColors # just a shorthand
40 InputColors = coloransi.InputTermColors # just a shorthand
41 Colors = coloransi.TermColors # just a shorthand
41 Colors = coloransi.TermColors # just a shorthand
42
42
43 color_lists = dict(normal=Colors(), inp=InputColors(), nocolor=coloransi.NoColors())
43 color_lists = dict(normal=Colors(), inp=InputColors(), nocolor=coloransi.NoColors())
44
44
45 PColNoColors = coloransi.ColorScheme(
45 PColNoColors = coloransi.ColorScheme(
46 'NoColor',
46 'NoColor',
47 in_prompt = InputColors.NoColor, # Input prompt
47 in_prompt = InputColors.NoColor, # Input prompt
48 in_number = InputColors.NoColor, # Input prompt number
48 in_number = InputColors.NoColor, # Input prompt number
49 in_prompt2 = InputColors.NoColor, # Continuation prompt
49 in_prompt2 = InputColors.NoColor, # Continuation prompt
50 in_normal = InputColors.NoColor, # color off (usu. Colors.Normal)
50 in_normal = InputColors.NoColor, # color off (usu. Colors.Normal)
51
51
52 out_prompt = Colors.NoColor, # Output prompt
52 out_prompt = Colors.NoColor, # Output prompt
53 out_number = Colors.NoColor, # Output prompt number
53 out_number = Colors.NoColor, # Output prompt number
54
54
55 normal = Colors.NoColor # color off (usu. Colors.Normal)
55 normal = Colors.NoColor # color off (usu. Colors.Normal)
56 )
56 )
57
57
58 # make some schemes as instances so we can copy them for modification easily:
58 # make some schemes as instances so we can copy them for modification easily:
59 PColLinux = coloransi.ColorScheme(
59 PColLinux = coloransi.ColorScheme(
60 'Linux',
60 'Linux',
61 in_prompt = InputColors.Green,
61 in_prompt = InputColors.Green,
62 in_number = InputColors.LightGreen,
62 in_number = InputColors.LightGreen,
63 in_prompt2 = InputColors.Green,
63 in_prompt2 = InputColors.Green,
64 in_normal = InputColors.Normal, # color off (usu. Colors.Normal)
64 in_normal = InputColors.Normal, # color off (usu. Colors.Normal)
65
65
66 out_prompt = Colors.Red,
66 out_prompt = Colors.Red,
67 out_number = Colors.LightRed,
67 out_number = Colors.LightRed,
68
68
69 normal = Colors.Normal
69 normal = Colors.Normal
70 )
70 )
71
71
72 # Slightly modified Linux for light backgrounds
72 # Slightly modified Linux for light backgrounds
73 PColLightBG = PColLinux.copy('LightBG')
73 PColLightBG = PColLinux.copy('LightBG')
74
74
75 PColLightBG.colors.update(
75 PColLightBG.colors.update(
76 in_prompt = InputColors.Blue,
76 in_prompt = InputColors.Blue,
77 in_number = InputColors.LightBlue,
77 in_number = InputColors.LightBlue,
78 in_prompt2 = InputColors.Blue
78 in_prompt2 = InputColors.Blue
79 )
79 )
80
80
81 #-----------------------------------------------------------------------------
81 #-----------------------------------------------------------------------------
82 # Utilities
82 # Utilities
83 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
84
84
85 class LazyEvaluate(object):
85 class LazyEvaluate(object):
86 """This is used for formatting strings with values that need to be updated
86 """This is used for formatting strings with values that need to be updated
87 at that time, such as the current time or working directory."""
87 at that time, such as the current time or working directory."""
88 def __init__(self, func, *args, **kwargs):
88 def __init__(self, func, *args, **kwargs):
89 self.func = func
89 self.func = func
90 self.args = args
90 self.args = args
91 self.kwargs = kwargs
91 self.kwargs = kwargs
92
92
93 def __call__(self, **kwargs):
93 def __call__(self, **kwargs):
94 self.kwargs.update(kwargs)
94 self.kwargs.update(kwargs)
95 return self.func(*self.args, **self.kwargs)
95 return self.func(*self.args, **self.kwargs)
96
96
97 def __str__(self):
97 def __str__(self):
98 return str(self())
98 return str(self())
99
99
100 def __unicode__(self):
100 def __unicode__(self):
101 return py3compat.unicode_type(self())
101 return py3compat.unicode_type(self())
102
102
103 def __format__(self, format_spec):
103 def __format__(self, format_spec):
104 return format(self(), format_spec)
104 return format(self(), format_spec)
105
105
106 def multiple_replace(dict, text):
106 def multiple_replace(dict, text):
107 """ Replace in 'text' all occurences of any key in the given
107 """ Replace in 'text' all occurences of any key in the given
108 dictionary by its corresponding value. Returns the new string."""
108 dictionary by its corresponding value. Returns the new string."""
109
109
110 # Function by Xavier Defrang, originally found at:
110 # Function by Xavier Defrang, originally found at:
111 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81330
111 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81330
112
112
113 # Create a regular expression from the dictionary keys
113 # Create a regular expression from the dictionary keys
114 regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
114 regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
115 # For each match, look-up corresponding value in dictionary
115 # For each match, look-up corresponding value in dictionary
116 return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
116 return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
117
117
118 #-----------------------------------------------------------------------------
118 #-----------------------------------------------------------------------------
119 # Special characters that can be used in prompt templates, mainly bash-like
119 # Special characters that can be used in prompt templates, mainly bash-like
120 #-----------------------------------------------------------------------------
120 #-----------------------------------------------------------------------------
121
121
122 # If $HOME isn't defined (Windows), make it an absurd string so that it can
122 # If $HOME isn't defined (Windows), make it an absurd string so that it can
123 # never be expanded out into '~'. Basically anything which can never be a
123 # never be expanded out into '~'. Basically anything which can never be a
124 # reasonable directory name will do, we just want the $HOME -> '~' operation
124 # reasonable directory name will do, we just want the $HOME -> '~' operation
125 # to become a no-op. We pre-compute $HOME here so it's not done on every
125 # to become a no-op. We pre-compute $HOME here so it's not done on every
126 # prompt call.
126 # prompt call.
127
127
128 # FIXME:
128 # FIXME:
129
129
130 # - This should be turned into a class which does proper namespace management,
130 # - This should be turned into a class which does proper namespace management,
131 # since the prompt specials need to be evaluated in a certain namespace.
131 # since the prompt specials need to be evaluated in a certain namespace.
132 # Currently it's just globals, which need to be managed manually by code
132 # Currently it's just globals, which need to be managed manually by code
133 # below.
133 # below.
134
134
135 # - I also need to split up the color schemes from the prompt specials
135 # - I also need to split up the color schemes from the prompt specials
136 # somehow. I don't have a clean design for that quite yet.
136 # somehow. I don't have a clean design for that quite yet.
137
137
138 HOME = py3compat.str_to_unicode(os.environ.get("HOME","//////:::::ZZZZZ,,,~~~"))
138 HOME = py3compat.str_to_unicode(os.environ.get("HOME","//////:::::ZZZZZ,,,~~~"))
139
139
140 # This is needed on FreeBSD, and maybe other systems which symlink /home to
140 # This is needed on FreeBSD, and maybe other systems which symlink /home to
141 # /usr/home, but retain the $HOME variable as pointing to /home
141 # /usr/home, but retain the $HOME variable as pointing to /home
142 HOME = os.path.realpath(HOME)
142 HOME = os.path.realpath(HOME)
143
143
144 # We precompute a few more strings here for the prompt_specials, which are
144 # We precompute a few more strings here for the prompt_specials, which are
145 # fixed once ipython starts. This reduces the runtime overhead of computing
145 # fixed once ipython starts. This reduces the runtime overhead of computing
146 # prompt strings.
146 # prompt strings.
147 USER = py3compat.str_to_unicode(os.environ.get("USER",''))
147 USER = py3compat.str_to_unicode(os.environ.get("USER",''))
148 HOSTNAME = py3compat.str_to_unicode(socket.gethostname())
148 HOSTNAME = py3compat.str_to_unicode(socket.gethostname())
149 HOSTNAME_SHORT = HOSTNAME.split(".")[0]
149 HOSTNAME_SHORT = HOSTNAME.split(".")[0]
150 ROOT_SYMBOL = "#" if (os.name=='nt' or os.getuid()==0) else "$"
150 ROOT_SYMBOL = "#" if (os.name=='nt' or os.getuid()==0) else "$"
151
151
152 prompt_abbreviations = {
152 prompt_abbreviations = {
153 # Prompt/history count
153 # Prompt/history count
154 '%n' : '{color.number}' '{count}' '{color.prompt}',
154 '%n' : '{color.number}' '{count}' '{color.prompt}',
155 r'\#': '{color.number}' '{count}' '{color.prompt}',
155 r'\#': '{color.number}' '{count}' '{color.prompt}',
156 # Just the prompt counter number, WITHOUT any coloring wrappers, so users
156 # Just the prompt counter number, WITHOUT any coloring wrappers, so users
157 # can get numbers displayed in whatever color they want.
157 # can get numbers displayed in whatever color they want.
158 r'\N': '{count}',
158 r'\N': '{count}',
159
159
160 # Prompt/history count, with the actual digits replaced by dots. Used
160 # Prompt/history count, with the actual digits replaced by dots. Used
161 # mainly in continuation prompts (prompt_in2)
161 # mainly in continuation prompts (prompt_in2)
162 r'\D': '{dots}',
162 r'\D': '{dots}',
163
163
164 # Current time
164 # Current time
165 r'\T' : '{time}',
165 r'\T' : '{time}',
166 # Current working directory
166 # Current working directory
167 r'\w': '{cwd}',
167 r'\w': '{cwd}',
168 # Basename of current working directory.
168 # Basename of current working directory.
169 # (use os.sep to make this portable across OSes)
169 # (use os.sep to make this portable across OSes)
170 r'\W' : '{cwd_last}',
170 r'\W' : '{cwd_last}',
171 # These X<N> are an extension to the normal bash prompts. They return
171 # These X<N> are an extension to the normal bash prompts. They return
172 # N terms of the path, after replacing $HOME with '~'
172 # N terms of the path, after replacing $HOME with '~'
173 r'\X0': '{cwd_x[0]}',
173 r'\X0': '{cwd_x[0]}',
174 r'\X1': '{cwd_x[1]}',
174 r'\X1': '{cwd_x[1]}',
175 r'\X2': '{cwd_x[2]}',
175 r'\X2': '{cwd_x[2]}',
176 r'\X3': '{cwd_x[3]}',
176 r'\X3': '{cwd_x[3]}',
177 r'\X4': '{cwd_x[4]}',
177 r'\X4': '{cwd_x[4]}',
178 r'\X5': '{cwd_x[5]}',
178 r'\X5': '{cwd_x[5]}',
179 # Y<N> are similar to X<N>, but they show '~' if it's the directory
179 # Y<N> are similar to X<N>, but they show '~' if it's the directory
180 # N+1 in the list. Somewhat like %cN in tcsh.
180 # N+1 in the list. Somewhat like %cN in tcsh.
181 r'\Y0': '{cwd_y[0]}',
181 r'\Y0': '{cwd_y[0]}',
182 r'\Y1': '{cwd_y[1]}',
182 r'\Y1': '{cwd_y[1]}',
183 r'\Y2': '{cwd_y[2]}',
183 r'\Y2': '{cwd_y[2]}',
184 r'\Y3': '{cwd_y[3]}',
184 r'\Y3': '{cwd_y[3]}',
185 r'\Y4': '{cwd_y[4]}',
185 r'\Y4': '{cwd_y[4]}',
186 r'\Y5': '{cwd_y[5]}',
186 r'\Y5': '{cwd_y[5]}',
187 # Hostname up to first .
187 # Hostname up to first .
188 r'\h': HOSTNAME_SHORT,
188 r'\h': HOSTNAME_SHORT,
189 # Full hostname
189 # Full hostname
190 r'\H': HOSTNAME,
190 r'\H': HOSTNAME,
191 # Username of current user
191 # Username of current user
192 r'\u': USER,
192 r'\u': USER,
193 # Escaped '\'
193 # Escaped '\'
194 '\\\\': '\\',
194 '\\\\': '\\',
195 # Newline
195 # Newline
196 r'\n': '\n',
196 r'\n': '\n',
197 # Carriage return
197 # Carriage return
198 r'\r': '\r',
198 r'\r': '\r',
199 # Release version
199 # Release version
200 r'\v': release.version,
200 r'\v': release.version,
201 # Root symbol ($ or #)
201 # Root symbol ($ or #)
202 r'\$': ROOT_SYMBOL,
202 r'\$': ROOT_SYMBOL,
203 }
203 }
204
204
205 #-----------------------------------------------------------------------------
205 #-----------------------------------------------------------------------------
206 # More utilities
206 # More utilities
207 #-----------------------------------------------------------------------------
207 #-----------------------------------------------------------------------------
208
208
209 def cwd_filt(depth):
209 def cwd_filt(depth):
210 """Return the last depth elements of the current working directory.
210 """Return the last depth elements of the current working directory.
211
211
212 $HOME is always replaced with '~'.
212 $HOME is always replaced with '~'.
213 If depth==0, the full path is returned."""
213 If depth==0, the full path is returned."""
214
214
215 cwd = os.getcwdu().replace(HOME,"~")
215 cwd = py3compat.getcwd().replace(HOME,"~")
216 out = os.sep.join(cwd.split(os.sep)[-depth:])
216 out = os.sep.join(cwd.split(os.sep)[-depth:])
217 return out or os.sep
217 return out or os.sep
218
218
219 def cwd_filt2(depth):
219 def cwd_filt2(depth):
220 """Return the last depth elements of the current working directory.
220 """Return the last depth elements of the current working directory.
221
221
222 $HOME is always replaced with '~'.
222 $HOME is always replaced with '~'.
223 If depth==0, the full path is returned."""
223 If depth==0, the full path is returned."""
224
224
225 full_cwd = os.getcwdu()
225 full_cwd = py3compat.getcwd()
226 cwd = full_cwd.replace(HOME,"~").split(os.sep)
226 cwd = full_cwd.replace(HOME,"~").split(os.sep)
227 if '~' in cwd and len(cwd) == depth+1:
227 if '~' in cwd and len(cwd) == depth+1:
228 depth += 1
228 depth += 1
229 drivepart = ''
229 drivepart = ''
230 if sys.platform == 'win32' and len(cwd) > depth:
230 if sys.platform == 'win32' and len(cwd) > depth:
231 drivepart = os.path.splitdrive(full_cwd)[0]
231 drivepart = os.path.splitdrive(full_cwd)[0]
232 out = drivepart + '/'.join(cwd[-depth:])
232 out = drivepart + '/'.join(cwd[-depth:])
233
233
234 return out or os.sep
234 return out or os.sep
235
235
236 #-----------------------------------------------------------------------------
236 #-----------------------------------------------------------------------------
237 # Prompt classes
237 # Prompt classes
238 #-----------------------------------------------------------------------------
238 #-----------------------------------------------------------------------------
239
239
240 lazily_evaluate = {'time': LazyEvaluate(time.strftime, "%H:%M:%S"),
240 lazily_evaluate = {'time': LazyEvaluate(time.strftime, "%H:%M:%S"),
241 'cwd': LazyEvaluate(os.getcwdu),
241 'cwd': LazyEvaluate(py3compat.getcwd),
242 'cwd_last': LazyEvaluate(lambda: os.getcwdu().split(os.sep)[-1]),
242 'cwd_last': LazyEvaluate(lambda: py3compat.getcwd().split(os.sep)[-1]),
243 'cwd_x': [LazyEvaluate(lambda: os.getcwdu().replace(HOME,"~"))] +\
243 'cwd_x': [LazyEvaluate(lambda: py3compat.getcwd().replace(HOME,"~"))] +\
244 [LazyEvaluate(cwd_filt, x) for x in range(1,6)],
244 [LazyEvaluate(cwd_filt, x) for x in range(1,6)],
245 'cwd_y': [LazyEvaluate(cwd_filt2, x) for x in range(6)]
245 'cwd_y': [LazyEvaluate(cwd_filt2, x) for x in range(6)]
246 }
246 }
247
247
248 def _lenlastline(s):
248 def _lenlastline(s):
249 """Get the length of the last line. More intelligent than
249 """Get the length of the last line. More intelligent than
250 len(s.splitlines()[-1]).
250 len(s.splitlines()[-1]).
251 """
251 """
252 if not s or s.endswith(('\n', '\r')):
252 if not s or s.endswith(('\n', '\r')):
253 return 0
253 return 0
254 return len(s.splitlines()[-1])
254 return len(s.splitlines()[-1])
255
255
256
256
257 class UserNSFormatter(Formatter):
257 class UserNSFormatter(Formatter):
258 """A Formatter that falls back on a shell's user_ns and __builtins__ for name resolution"""
258 """A Formatter that falls back on a shell's user_ns and __builtins__ for name resolution"""
259 def __init__(self, shell):
259 def __init__(self, shell):
260 self.shell = shell
260 self.shell = shell
261
261
262 def get_value(self, key, args, kwargs):
262 def get_value(self, key, args, kwargs):
263 # try regular formatting first:
263 # try regular formatting first:
264 try:
264 try:
265 return Formatter.get_value(self, key, args, kwargs)
265 return Formatter.get_value(self, key, args, kwargs)
266 except Exception:
266 except Exception:
267 pass
267 pass
268 # next, look in user_ns and builtins:
268 # next, look in user_ns and builtins:
269 for container in (self.shell.user_ns, __builtins__):
269 for container in (self.shell.user_ns, __builtins__):
270 if key in container:
270 if key in container:
271 return container[key]
271 return container[key]
272 # nothing found, put error message in its place
272 # nothing found, put error message in its place
273 return "<ERROR: '%s' not found>" % key
273 return "<ERROR: '%s' not found>" % key
274
274
275
275
276 class PromptManager(Configurable):
276 class PromptManager(Configurable):
277 """This is the primary interface for producing IPython's prompts."""
277 """This is the primary interface for producing IPython's prompts."""
278 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
278 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
279
279
280 color_scheme_table = Instance(coloransi.ColorSchemeTable)
280 color_scheme_table = Instance(coloransi.ColorSchemeTable)
281 color_scheme = Unicode('Linux', config=True)
281 color_scheme = Unicode('Linux', config=True)
282 def _color_scheme_changed(self, name, new_value):
282 def _color_scheme_changed(self, name, new_value):
283 self.color_scheme_table.set_active_scheme(new_value)
283 self.color_scheme_table.set_active_scheme(new_value)
284 for pname in ['in', 'in2', 'out', 'rewrite']:
284 for pname in ['in', 'in2', 'out', 'rewrite']:
285 # We need to recalculate the number of invisible characters
285 # We need to recalculate the number of invisible characters
286 self.update_prompt(pname)
286 self.update_prompt(pname)
287
287
288 lazy_evaluate_fields = Dict(help="""
288 lazy_evaluate_fields = Dict(help="""
289 This maps field names used in the prompt templates to functions which
289 This maps field names used in the prompt templates to functions which
290 will be called when the prompt is rendered. This allows us to include
290 will be called when the prompt is rendered. This allows us to include
291 things like the current time in the prompts. Functions are only called
291 things like the current time in the prompts. Functions are only called
292 if they are used in the prompt.
292 if they are used in the prompt.
293 """)
293 """)
294 def _lazy_evaluate_fields_default(self): return lazily_evaluate.copy()
294 def _lazy_evaluate_fields_default(self): return lazily_evaluate.copy()
295
295
296 in_template = Unicode('In [\\#]: ', config=True,
296 in_template = Unicode('In [\\#]: ', config=True,
297 help="Input prompt. '\\#' will be transformed to the prompt number")
297 help="Input prompt. '\\#' will be transformed to the prompt number")
298 in2_template = Unicode(' .\\D.: ', config=True,
298 in2_template = Unicode(' .\\D.: ', config=True,
299 help="Continuation prompt.")
299 help="Continuation prompt.")
300 out_template = Unicode('Out[\\#]: ', config=True,
300 out_template = Unicode('Out[\\#]: ', config=True,
301 help="Output prompt. '\\#' will be transformed to the prompt number")
301 help="Output prompt. '\\#' will be transformed to the prompt number")
302
302
303 justify = Bool(True, config=True, help="""
303 justify = Bool(True, config=True, help="""
304 If True (default), each prompt will be right-aligned with the
304 If True (default), each prompt will be right-aligned with the
305 preceding one.
305 preceding one.
306 """)
306 """)
307
307
308 # We actually store the expanded templates here:
308 # We actually store the expanded templates here:
309 templates = Dict()
309 templates = Dict()
310
310
311 # The number of characters in the last prompt rendered, not including
311 # The number of characters in the last prompt rendered, not including
312 # colour characters.
312 # colour characters.
313 width = Int()
313 width = Int()
314 txtwidth = Int() # Not including right-justification
314 txtwidth = Int() # Not including right-justification
315
315
316 # The number of characters in each prompt which don't contribute to width
316 # The number of characters in each prompt which don't contribute to width
317 invisible_chars = Dict()
317 invisible_chars = Dict()
318 def _invisible_chars_default(self):
318 def _invisible_chars_default(self):
319 return {'in': 0, 'in2': 0, 'out': 0, 'rewrite':0}
319 return {'in': 0, 'in2': 0, 'out': 0, 'rewrite':0}
320
320
321 def __init__(self, shell, **kwargs):
321 def __init__(self, shell, **kwargs):
322 super(PromptManager, self).__init__(shell=shell, **kwargs)
322 super(PromptManager, self).__init__(shell=shell, **kwargs)
323
323
324 # Prepare colour scheme table
324 # Prepare colour scheme table
325 self.color_scheme_table = coloransi.ColorSchemeTable([PColNoColors,
325 self.color_scheme_table = coloransi.ColorSchemeTable([PColNoColors,
326 PColLinux, PColLightBG], self.color_scheme)
326 PColLinux, PColLightBG], self.color_scheme)
327
327
328 self._formatter = UserNSFormatter(shell)
328 self._formatter = UserNSFormatter(shell)
329 # Prepare templates & numbers of invisible characters
329 # Prepare templates & numbers of invisible characters
330 self.update_prompt('in', self.in_template)
330 self.update_prompt('in', self.in_template)
331 self.update_prompt('in2', self.in2_template)
331 self.update_prompt('in2', self.in2_template)
332 self.update_prompt('out', self.out_template)
332 self.update_prompt('out', self.out_template)
333 self.update_prompt('rewrite')
333 self.update_prompt('rewrite')
334 self.on_trait_change(self._update_prompt_trait, ['in_template',
334 self.on_trait_change(self._update_prompt_trait, ['in_template',
335 'in2_template', 'out_template'])
335 'in2_template', 'out_template'])
336
336
337 def update_prompt(self, name, new_template=None):
337 def update_prompt(self, name, new_template=None):
338 """This is called when a prompt template is updated. It processes
338 """This is called when a prompt template is updated. It processes
339 abbreviations used in the prompt template (like \#) and calculates how
339 abbreviations used in the prompt template (like \#) and calculates how
340 many invisible characters (ANSI colour escapes) the resulting prompt
340 many invisible characters (ANSI colour escapes) the resulting prompt
341 contains.
341 contains.
342
342
343 It is also called for each prompt on changing the colour scheme. In both
343 It is also called for each prompt on changing the colour scheme. In both
344 cases, traitlets should take care of calling this automatically.
344 cases, traitlets should take care of calling this automatically.
345 """
345 """
346 if new_template is not None:
346 if new_template is not None:
347 self.templates[name] = multiple_replace(prompt_abbreviations, new_template)
347 self.templates[name] = multiple_replace(prompt_abbreviations, new_template)
348 # We count invisible characters (colour escapes) on the last line of the
348 # We count invisible characters (colour escapes) on the last line of the
349 # prompt, to calculate the width for lining up subsequent prompts.
349 # prompt, to calculate the width for lining up subsequent prompts.
350 invis_chars = _lenlastline(self._render(name, color=True)) - \
350 invis_chars = _lenlastline(self._render(name, color=True)) - \
351 _lenlastline(self._render(name, color=False))
351 _lenlastline(self._render(name, color=False))
352 self.invisible_chars[name] = invis_chars
352 self.invisible_chars[name] = invis_chars
353
353
354 def _update_prompt_trait(self, traitname, new_template):
354 def _update_prompt_trait(self, traitname, new_template):
355 name = traitname[:-9] # Cut off '_template'
355 name = traitname[:-9] # Cut off '_template'
356 self.update_prompt(name, new_template)
356 self.update_prompt(name, new_template)
357
357
358 def _render(self, name, color=True, **kwargs):
358 def _render(self, name, color=True, **kwargs):
359 """Render but don't justify, or update the width or txtwidth attributes.
359 """Render but don't justify, or update the width or txtwidth attributes.
360 """
360 """
361 if name == 'rewrite':
361 if name == 'rewrite':
362 return self._render_rewrite(color=color)
362 return self._render_rewrite(color=color)
363
363
364 if color:
364 if color:
365 scheme = self.color_scheme_table.active_colors
365 scheme = self.color_scheme_table.active_colors
366 if name=='out':
366 if name=='out':
367 colors = color_lists['normal']
367 colors = color_lists['normal']
368 colors.number, colors.prompt, colors.normal = \
368 colors.number, colors.prompt, colors.normal = \
369 scheme.out_number, scheme.out_prompt, scheme.normal
369 scheme.out_number, scheme.out_prompt, scheme.normal
370 else:
370 else:
371 colors = color_lists['inp']
371 colors = color_lists['inp']
372 colors.number, colors.prompt, colors.normal = \
372 colors.number, colors.prompt, colors.normal = \
373 scheme.in_number, scheme.in_prompt, scheme.in_normal
373 scheme.in_number, scheme.in_prompt, scheme.in_normal
374 if name=='in2':
374 if name=='in2':
375 colors.prompt = scheme.in_prompt2
375 colors.prompt = scheme.in_prompt2
376 else:
376 else:
377 # No color
377 # No color
378 colors = color_lists['nocolor']
378 colors = color_lists['nocolor']
379 colors.number, colors.prompt, colors.normal = '', '', ''
379 colors.number, colors.prompt, colors.normal = '', '', ''
380
380
381 count = self.shell.execution_count # Shorthand
381 count = self.shell.execution_count # Shorthand
382 # Build the dictionary to be passed to string formatting
382 # Build the dictionary to be passed to string formatting
383 fmtargs = dict(color=colors, count=count,
383 fmtargs = dict(color=colors, count=count,
384 dots="."*len(str(count)),
384 dots="."*len(str(count)),
385 width=self.width, txtwidth=self.txtwidth )
385 width=self.width, txtwidth=self.txtwidth )
386 fmtargs.update(self.lazy_evaluate_fields)
386 fmtargs.update(self.lazy_evaluate_fields)
387 fmtargs.update(kwargs)
387 fmtargs.update(kwargs)
388
388
389 # Prepare the prompt
389 # Prepare the prompt
390 prompt = colors.prompt + self.templates[name] + colors.normal
390 prompt = colors.prompt + self.templates[name] + colors.normal
391
391
392 # Fill in required fields
392 # Fill in required fields
393 return self._formatter.format(prompt, **fmtargs)
393 return self._formatter.format(prompt, **fmtargs)
394
394
395 def _render_rewrite(self, color=True):
395 def _render_rewrite(self, color=True):
396 """Render the ---> rewrite prompt."""
396 """Render the ---> rewrite prompt."""
397 if color:
397 if color:
398 scheme = self.color_scheme_table.active_colors
398 scheme = self.color_scheme_table.active_colors
399 # We need a non-input version of these escapes
399 # We need a non-input version of these escapes
400 color_prompt = scheme.in_prompt.replace("\001","").replace("\002","")
400 color_prompt = scheme.in_prompt.replace("\001","").replace("\002","")
401 color_normal = scheme.normal
401 color_normal = scheme.normal
402 else:
402 else:
403 color_prompt, color_normal = '', ''
403 color_prompt, color_normal = '', ''
404
404
405 return color_prompt + "-> ".rjust(self.txtwidth, "-") + color_normal
405 return color_prompt + "-> ".rjust(self.txtwidth, "-") + color_normal
406
406
407 def render(self, name, color=True, just=None, **kwargs):
407 def render(self, name, color=True, just=None, **kwargs):
408 """
408 """
409 Render the selected prompt.
409 Render the selected prompt.
410
410
411 Parameters
411 Parameters
412 ----------
412 ----------
413 name : str
413 name : str
414 Which prompt to render. One of 'in', 'in2', 'out', 'rewrite'
414 Which prompt to render. One of 'in', 'in2', 'out', 'rewrite'
415 color : bool
415 color : bool
416 If True (default), include ANSI escape sequences for a coloured prompt.
416 If True (default), include ANSI escape sequences for a coloured prompt.
417 just : bool
417 just : bool
418 If True, justify the prompt to the width of the last prompt. The
418 If True, justify the prompt to the width of the last prompt. The
419 default is stored in self.justify.
419 default is stored in self.justify.
420 **kwargs :
420 **kwargs :
421 Additional arguments will be passed to the string formatting operation,
421 Additional arguments will be passed to the string formatting operation,
422 so they can override the values that would otherwise fill in the
422 so they can override the values that would otherwise fill in the
423 template.
423 template.
424
424
425 Returns
425 Returns
426 -------
426 -------
427 A string containing the rendered prompt.
427 A string containing the rendered prompt.
428 """
428 """
429 res = self._render(name, color=color, **kwargs)
429 res = self._render(name, color=color, **kwargs)
430
430
431 # Handle justification of prompt
431 # Handle justification of prompt
432 invis_chars = self.invisible_chars[name] if color else 0
432 invis_chars = self.invisible_chars[name] if color else 0
433 self.txtwidth = _lenlastline(res) - invis_chars
433 self.txtwidth = _lenlastline(res) - invis_chars
434 just = self.justify if (just is None) else just
434 just = self.justify if (just is None) else just
435 # If the prompt spans more than one line, don't try to justify it:
435 # If the prompt spans more than one line, don't try to justify it:
436 if just and name != 'in' and ('\n' not in res) and ('\r' not in res):
436 if just and name != 'in' and ('\n' not in res) and ('\r' not in res):
437 res = res.rjust(self.width + invis_chars)
437 res = res.rjust(self.width + invis_chars)
438 self.width = _lenlastline(res) - invis_chars
438 self.width = _lenlastline(res) - invis_chars
439 return res
439 return res
@@ -1,50 +1,50 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Tests for IPython.core.application"""
2 """Tests for IPython.core.application"""
3
3
4 import os
4 import os
5 import tempfile
5 import tempfile
6
6
7 from IPython.core.application import BaseIPythonApplication
7 from IPython.core.application import BaseIPythonApplication
8 from IPython.testing import decorators as dec
8 from IPython.testing import decorators as dec
9 from IPython.utils import py3compat
9 from IPython.utils import py3compat
10
10
11 @dec.onlyif_unicode_paths
11 @dec.onlyif_unicode_paths
12 def test_unicode_cwd():
12 def test_unicode_cwd():
13 """Check that IPython starts with non-ascii characters in the path."""
13 """Check that IPython starts with non-ascii characters in the path."""
14 wd = tempfile.mkdtemp(suffix=u"€")
14 wd = tempfile.mkdtemp(suffix=u"€")
15
15
16 old_wd = os.getcwdu()
16 old_wd = py3compat.getcwd()
17 os.chdir(wd)
17 os.chdir(wd)
18 #raise Exception(repr(os.getcwdu()))
18 #raise Exception(repr(py3compat.getcwd()))
19 try:
19 try:
20 app = BaseIPythonApplication()
20 app = BaseIPythonApplication()
21 # The lines below are copied from Application.initialize()
21 # The lines below are copied from Application.initialize()
22 app.init_profile_dir()
22 app.init_profile_dir()
23 app.init_config_files()
23 app.init_config_files()
24 app.load_config_file(suppress_errors=False)
24 app.load_config_file(suppress_errors=False)
25 finally:
25 finally:
26 os.chdir(old_wd)
26 os.chdir(old_wd)
27
27
28 @dec.onlyif_unicode_paths
28 @dec.onlyif_unicode_paths
29 def test_unicode_ipdir():
29 def test_unicode_ipdir():
30 """Check that IPython starts with non-ascii characters in the IP dir."""
30 """Check that IPython starts with non-ascii characters in the IP dir."""
31 ipdir = tempfile.mkdtemp(suffix=u"€")
31 ipdir = tempfile.mkdtemp(suffix=u"€")
32
32
33 # Create the config file, so it tries to load it.
33 # Create the config file, so it tries to load it.
34 with open(os.path.join(ipdir, 'ipython_config.py'), "w") as f:
34 with open(os.path.join(ipdir, 'ipython_config.py'), "w") as f:
35 pass
35 pass
36
36
37 old_ipdir1 = os.environ.pop("IPYTHONDIR", None)
37 old_ipdir1 = os.environ.pop("IPYTHONDIR", None)
38 old_ipdir2 = os.environ.pop("IPYTHON_DIR", None)
38 old_ipdir2 = os.environ.pop("IPYTHON_DIR", None)
39 os.environ["IPYTHONDIR"] = py3compat.unicode_to_str(ipdir, "utf-8")
39 os.environ["IPYTHONDIR"] = py3compat.unicode_to_str(ipdir, "utf-8")
40 try:
40 try:
41 app = BaseIPythonApplication()
41 app = BaseIPythonApplication()
42 # The lines below are copied from Application.initialize()
42 # The lines below are copied from Application.initialize()
43 app.init_profile_dir()
43 app.init_profile_dir()
44 app.init_config_files()
44 app.init_config_files()
45 app.load_config_file(suppress_errors=False)
45 app.load_config_file(suppress_errors=False)
46 finally:
46 finally:
47 if old_ipdir1:
47 if old_ipdir1:
48 os.environ["IPYTHONDIR"] = old_ipdir1
48 os.environ["IPYTHONDIR"] = old_ipdir1
49 if old_ipdir2:
49 if old_ipdir2:
50 os.environ["IPYTHONDIR"] = old_ipdir2
50 os.environ["IPYTHONDIR"] = old_ipdir2
@@ -1,393 +1,394 b''
1 """Tests for the IPython tab-completion machinery.
1 """Tests for the IPython tab-completion machinery.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Module imports
4 # Module imports
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6
6
7 # stdlib
7 # stdlib
8 import os
8 import os
9 import sys
9 import sys
10 import unittest
10 import unittest
11
11
12 # third party
12 # third party
13 import nose.tools as nt
13 import nose.tools as nt
14
14
15 # our own packages
15 # our own packages
16 from IPython.config.loader import Config
16 from IPython.config.loader import Config
17 from IPython.core import completer
17 from IPython.core import completer
18 from IPython.external.decorators import knownfailureif
18 from IPython.external.decorators import knownfailureif
19 from IPython.utils.tempdir import TemporaryDirectory
19 from IPython.utils.tempdir import TemporaryDirectory
20 from IPython.utils.generics import complete_object
20 from IPython.utils.generics import complete_object
21 from IPython.utils import py3compat
21 from IPython.utils.py3compat import string_types, unicode_type
22 from IPython.utils.py3compat import string_types, unicode_type
22
23
23 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
24 # Test functions
25 # Test functions
25 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
26 def test_protect_filename():
27 def test_protect_filename():
27 pairs = [ ('abc','abc'),
28 pairs = [ ('abc','abc'),
28 (' abc',r'\ abc'),
29 (' abc',r'\ abc'),
29 ('a bc',r'a\ bc'),
30 ('a bc',r'a\ bc'),
30 ('a bc',r'a\ \ bc'),
31 ('a bc',r'a\ \ bc'),
31 (' bc',r'\ \ bc'),
32 (' bc',r'\ \ bc'),
32 ]
33 ]
33 # On posix, we also protect parens and other special characters
34 # On posix, we also protect parens and other special characters
34 if sys.platform != 'win32':
35 if sys.platform != 'win32':
35 pairs.extend( [('a(bc',r'a\(bc'),
36 pairs.extend( [('a(bc',r'a\(bc'),
36 ('a)bc',r'a\)bc'),
37 ('a)bc',r'a\)bc'),
37 ('a( )bc',r'a\(\ \)bc'),
38 ('a( )bc',r'a\(\ \)bc'),
38 ('a[1]bc', r'a\[1\]bc'),
39 ('a[1]bc', r'a\[1\]bc'),
39 ('a{1}bc', r'a\{1\}bc'),
40 ('a{1}bc', r'a\{1\}bc'),
40 ('a#bc', r'a\#bc'),
41 ('a#bc', r'a\#bc'),
41 ('a?bc', r'a\?bc'),
42 ('a?bc', r'a\?bc'),
42 ('a=bc', r'a\=bc'),
43 ('a=bc', r'a\=bc'),
43 ('a\\bc', r'a\\bc'),
44 ('a\\bc', r'a\\bc'),
44 ('a|bc', r'a\|bc'),
45 ('a|bc', r'a\|bc'),
45 ('a;bc', r'a\;bc'),
46 ('a;bc', r'a\;bc'),
46 ('a:bc', r'a\:bc'),
47 ('a:bc', r'a\:bc'),
47 ("a'bc", r"a\'bc"),
48 ("a'bc", r"a\'bc"),
48 ('a*bc', r'a\*bc'),
49 ('a*bc', r'a\*bc'),
49 ('a"bc', r'a\"bc'),
50 ('a"bc', r'a\"bc'),
50 ('a^bc', r'a\^bc'),
51 ('a^bc', r'a\^bc'),
51 ('a&bc', r'a\&bc'),
52 ('a&bc', r'a\&bc'),
52 ] )
53 ] )
53 # run the actual tests
54 # run the actual tests
54 for s1, s2 in pairs:
55 for s1, s2 in pairs:
55 s1p = completer.protect_filename(s1)
56 s1p = completer.protect_filename(s1)
56 nt.assert_equal(s1p, s2)
57 nt.assert_equal(s1p, s2)
57
58
58
59
59 def check_line_split(splitter, test_specs):
60 def check_line_split(splitter, test_specs):
60 for part1, part2, split in test_specs:
61 for part1, part2, split in test_specs:
61 cursor_pos = len(part1)
62 cursor_pos = len(part1)
62 line = part1+part2
63 line = part1+part2
63 out = splitter.split_line(line, cursor_pos)
64 out = splitter.split_line(line, cursor_pos)
64 nt.assert_equal(out, split)
65 nt.assert_equal(out, split)
65
66
66
67
67 def test_line_split():
68 def test_line_split():
68 """Basic line splitter test with default specs."""
69 """Basic line splitter test with default specs."""
69 sp = completer.CompletionSplitter()
70 sp = completer.CompletionSplitter()
70 # The format of the test specs is: part1, part2, expected answer. Parts 1
71 # The format of the test specs is: part1, part2, expected answer. Parts 1
71 # and 2 are joined into the 'line' sent to the splitter, as if the cursor
72 # and 2 are joined into the 'line' sent to the splitter, as if the cursor
72 # was at the end of part1. So an empty part2 represents someone hitting
73 # was at the end of part1. So an empty part2 represents someone hitting
73 # tab at the end of the line, the most common case.
74 # tab at the end of the line, the most common case.
74 t = [('run some/scrip', '', 'some/scrip'),
75 t = [('run some/scrip', '', 'some/scrip'),
75 ('run scripts/er', 'ror.py foo', 'scripts/er'),
76 ('run scripts/er', 'ror.py foo', 'scripts/er'),
76 ('echo $HOM', '', 'HOM'),
77 ('echo $HOM', '', 'HOM'),
77 ('print sys.pa', '', 'sys.pa'),
78 ('print sys.pa', '', 'sys.pa'),
78 ('print(sys.pa', '', 'sys.pa'),
79 ('print(sys.pa', '', 'sys.pa'),
79 ("execfile('scripts/er", '', 'scripts/er'),
80 ("execfile('scripts/er", '', 'scripts/er'),
80 ('a[x.', '', 'x.'),
81 ('a[x.', '', 'x.'),
81 ('a[x.', 'y', 'x.'),
82 ('a[x.', 'y', 'x.'),
82 ('cd "some_file/', '', 'some_file/'),
83 ('cd "some_file/', '', 'some_file/'),
83 ]
84 ]
84 check_line_split(sp, t)
85 check_line_split(sp, t)
85 # Ensure splitting works OK with unicode by re-running the tests with
86 # Ensure splitting works OK with unicode by re-running the tests with
86 # all inputs turned into unicode
87 # all inputs turned into unicode
87 check_line_split(sp, [ map(unicode_type, p) for p in t] )
88 check_line_split(sp, [ map(unicode_type, p) for p in t] )
88
89
89
90
90 def test_custom_completion_error():
91 def test_custom_completion_error():
91 """Test that errors from custom attribute completers are silenced."""
92 """Test that errors from custom attribute completers are silenced."""
92 ip = get_ipython()
93 ip = get_ipython()
93 class A(object): pass
94 class A(object): pass
94 ip.user_ns['a'] = A()
95 ip.user_ns['a'] = A()
95
96
96 @complete_object.when_type(A)
97 @complete_object.when_type(A)
97 def complete_A(a, existing_completions):
98 def complete_A(a, existing_completions):
98 raise TypeError("this should be silenced")
99 raise TypeError("this should be silenced")
99
100
100 ip.complete("a.")
101 ip.complete("a.")
101
102
102
103
103 def test_unicode_completions():
104 def test_unicode_completions():
104 ip = get_ipython()
105 ip = get_ipython()
105 # Some strings that trigger different types of completion. Check them both
106 # Some strings that trigger different types of completion. Check them both
106 # in str and unicode forms
107 # in str and unicode forms
107 s = ['ru', '%ru', 'cd /', 'floa', 'float(x)/']
108 s = ['ru', '%ru', 'cd /', 'floa', 'float(x)/']
108 for t in s + list(map(unicode_type, s)):
109 for t in s + list(map(unicode_type, s)):
109 # We don't need to check exact completion values (they may change
110 # We don't need to check exact completion values (they may change
110 # depending on the state of the namespace, but at least no exceptions
111 # depending on the state of the namespace, but at least no exceptions
111 # should be thrown and the return value should be a pair of text, list
112 # should be thrown and the return value should be a pair of text, list
112 # values.
113 # values.
113 text, matches = ip.complete(t)
114 text, matches = ip.complete(t)
114 nt.assert_true(isinstance(text, string_types))
115 nt.assert_true(isinstance(text, string_types))
115 nt.assert_true(isinstance(matches, list))
116 nt.assert_true(isinstance(matches, list))
116
117
117
118
118 class CompletionSplitterTestCase(unittest.TestCase):
119 class CompletionSplitterTestCase(unittest.TestCase):
119 def setUp(self):
120 def setUp(self):
120 self.sp = completer.CompletionSplitter()
121 self.sp = completer.CompletionSplitter()
121
122
122 def test_delim_setting(self):
123 def test_delim_setting(self):
123 self.sp.delims = ' '
124 self.sp.delims = ' '
124 nt.assert_equal(self.sp.delims, ' ')
125 nt.assert_equal(self.sp.delims, ' ')
125 nt.assert_equal(self.sp._delim_expr, '[\ ]')
126 nt.assert_equal(self.sp._delim_expr, '[\ ]')
126
127
127 def test_spaces(self):
128 def test_spaces(self):
128 """Test with only spaces as split chars."""
129 """Test with only spaces as split chars."""
129 self.sp.delims = ' '
130 self.sp.delims = ' '
130 t = [('foo', '', 'foo'),
131 t = [('foo', '', 'foo'),
131 ('run foo', '', 'foo'),
132 ('run foo', '', 'foo'),
132 ('run foo', 'bar', 'foo'),
133 ('run foo', 'bar', 'foo'),
133 ]
134 ]
134 check_line_split(self.sp, t)
135 check_line_split(self.sp, t)
135
136
136
137
137 def test_has_open_quotes1():
138 def test_has_open_quotes1():
138 for s in ["'", "'''", "'hi' '"]:
139 for s in ["'", "'''", "'hi' '"]:
139 nt.assert_equal(completer.has_open_quotes(s), "'")
140 nt.assert_equal(completer.has_open_quotes(s), "'")
140
141
141
142
142 def test_has_open_quotes2():
143 def test_has_open_quotes2():
143 for s in ['"', '"""', '"hi" "']:
144 for s in ['"', '"""', '"hi" "']:
144 nt.assert_equal(completer.has_open_quotes(s), '"')
145 nt.assert_equal(completer.has_open_quotes(s), '"')
145
146
146
147
147 def test_has_open_quotes3():
148 def test_has_open_quotes3():
148 for s in ["''", "''' '''", "'hi' 'ipython'"]:
149 for s in ["''", "''' '''", "'hi' 'ipython'"]:
149 nt.assert_false(completer.has_open_quotes(s))
150 nt.assert_false(completer.has_open_quotes(s))
150
151
151
152
152 def test_has_open_quotes4():
153 def test_has_open_quotes4():
153 for s in ['""', '""" """', '"hi" "ipython"']:
154 for s in ['""', '""" """', '"hi" "ipython"']:
154 nt.assert_false(completer.has_open_quotes(s))
155 nt.assert_false(completer.has_open_quotes(s))
155
156
156
157
157 @knownfailureif(sys.platform == 'win32', "abspath completions fail on Windows")
158 @knownfailureif(sys.platform == 'win32', "abspath completions fail on Windows")
158 def test_abspath_file_completions():
159 def test_abspath_file_completions():
159 ip = get_ipython()
160 ip = get_ipython()
160 with TemporaryDirectory() as tmpdir:
161 with TemporaryDirectory() as tmpdir:
161 prefix = os.path.join(tmpdir, 'foo')
162 prefix = os.path.join(tmpdir, 'foo')
162 suffixes = ['1', '2']
163 suffixes = ['1', '2']
163 names = [prefix+s for s in suffixes]
164 names = [prefix+s for s in suffixes]
164 for n in names:
165 for n in names:
165 open(n, 'w').close()
166 open(n, 'w').close()
166
167
167 # Check simple completion
168 # Check simple completion
168 c = ip.complete(prefix)[1]
169 c = ip.complete(prefix)[1]
169 nt.assert_equal(c, names)
170 nt.assert_equal(c, names)
170
171
171 # Now check with a function call
172 # Now check with a function call
172 cmd = 'a = f("%s' % prefix
173 cmd = 'a = f("%s' % prefix
173 c = ip.complete(prefix, cmd)[1]
174 c = ip.complete(prefix, cmd)[1]
174 comp = [prefix+s for s in suffixes]
175 comp = [prefix+s for s in suffixes]
175 nt.assert_equal(c, comp)
176 nt.assert_equal(c, comp)
176
177
177
178
178 def test_local_file_completions():
179 def test_local_file_completions():
179 ip = get_ipython()
180 ip = get_ipython()
180 cwd = os.getcwdu()
181 cwd = py3compat.getcwd()
181 try:
182 try:
182 with TemporaryDirectory() as tmpdir:
183 with TemporaryDirectory() as tmpdir:
183 os.chdir(tmpdir)
184 os.chdir(tmpdir)
184 prefix = './foo'
185 prefix = './foo'
185 suffixes = ['1', '2']
186 suffixes = ['1', '2']
186 names = [prefix+s for s in suffixes]
187 names = [prefix+s for s in suffixes]
187 for n in names:
188 for n in names:
188 open(n, 'w').close()
189 open(n, 'w').close()
189
190
190 # Check simple completion
191 # Check simple completion
191 c = ip.complete(prefix)[1]
192 c = ip.complete(prefix)[1]
192 nt.assert_equal(c, names)
193 nt.assert_equal(c, names)
193
194
194 # Now check with a function call
195 # Now check with a function call
195 cmd = 'a = f("%s' % prefix
196 cmd = 'a = f("%s' % prefix
196 c = ip.complete(prefix, cmd)[1]
197 c = ip.complete(prefix, cmd)[1]
197 comp = [prefix+s for s in suffixes]
198 comp = [prefix+s for s in suffixes]
198 nt.assert_equal(c, comp)
199 nt.assert_equal(c, comp)
199 finally:
200 finally:
200 # prevent failures from making chdir stick
201 # prevent failures from making chdir stick
201 os.chdir(cwd)
202 os.chdir(cwd)
202
203
203
204
204 def test_greedy_completions():
205 def test_greedy_completions():
205 ip = get_ipython()
206 ip = get_ipython()
206 greedy_original = ip.Completer.greedy
207 greedy_original = ip.Completer.greedy
207 try:
208 try:
208 ip.Completer.greedy = False
209 ip.Completer.greedy = False
209 ip.ex('a=list(range(5))')
210 ip.ex('a=list(range(5))')
210 _,c = ip.complete('.',line='a[0].')
211 _,c = ip.complete('.',line='a[0].')
211 nt.assert_false('a[0].real' in c,
212 nt.assert_false('a[0].real' in c,
212 "Shouldn't have completed on a[0]: %s"%c)
213 "Shouldn't have completed on a[0]: %s"%c)
213 ip.Completer.greedy = True
214 ip.Completer.greedy = True
214 _,c = ip.complete('.',line='a[0].')
215 _,c = ip.complete('.',line='a[0].')
215 nt.assert_true('a[0].real' in c, "Should have completed on a[0]: %s"%c)
216 nt.assert_true('a[0].real' in c, "Should have completed on a[0]: %s"%c)
216 finally:
217 finally:
217 ip.Completer.greedy = greedy_original
218 ip.Completer.greedy = greedy_original
218
219
219
220
220 def test_omit__names():
221 def test_omit__names():
221 # also happens to test IPCompleter as a configurable
222 # also happens to test IPCompleter as a configurable
222 ip = get_ipython()
223 ip = get_ipython()
223 ip._hidden_attr = 1
224 ip._hidden_attr = 1
224 c = ip.Completer
225 c = ip.Completer
225 ip.ex('ip=get_ipython()')
226 ip.ex('ip=get_ipython()')
226 cfg = Config()
227 cfg = Config()
227 cfg.IPCompleter.omit__names = 0
228 cfg.IPCompleter.omit__names = 0
228 c.update_config(cfg)
229 c.update_config(cfg)
229 s,matches = c.complete('ip.')
230 s,matches = c.complete('ip.')
230 nt.assert_in('ip.__str__', matches)
231 nt.assert_in('ip.__str__', matches)
231 nt.assert_in('ip._hidden_attr', matches)
232 nt.assert_in('ip._hidden_attr', matches)
232 cfg.IPCompleter.omit__names = 1
233 cfg.IPCompleter.omit__names = 1
233 c.update_config(cfg)
234 c.update_config(cfg)
234 s,matches = c.complete('ip.')
235 s,matches = c.complete('ip.')
235 nt.assert_not_in('ip.__str__', matches)
236 nt.assert_not_in('ip.__str__', matches)
236 nt.assert_in('ip._hidden_attr', matches)
237 nt.assert_in('ip._hidden_attr', matches)
237 cfg.IPCompleter.omit__names = 2
238 cfg.IPCompleter.omit__names = 2
238 c.update_config(cfg)
239 c.update_config(cfg)
239 s,matches = c.complete('ip.')
240 s,matches = c.complete('ip.')
240 nt.assert_not_in('ip.__str__', matches)
241 nt.assert_not_in('ip.__str__', matches)
241 nt.assert_not_in('ip._hidden_attr', matches)
242 nt.assert_not_in('ip._hidden_attr', matches)
242 del ip._hidden_attr
243 del ip._hidden_attr
243
244
244
245
245 def test_limit_to__all__False_ok():
246 def test_limit_to__all__False_ok():
246 ip = get_ipython()
247 ip = get_ipython()
247 c = ip.Completer
248 c = ip.Completer
248 ip.ex('class D: x=24')
249 ip.ex('class D: x=24')
249 ip.ex('d=D()')
250 ip.ex('d=D()')
250 cfg = Config()
251 cfg = Config()
251 cfg.IPCompleter.limit_to__all__ = False
252 cfg.IPCompleter.limit_to__all__ = False
252 c.update_config(cfg)
253 c.update_config(cfg)
253 s, matches = c.complete('d.')
254 s, matches = c.complete('d.')
254 nt.assert_in('d.x', matches)
255 nt.assert_in('d.x', matches)
255
256
256
257
257 def test_limit_to__all__True_ok():
258 def test_limit_to__all__True_ok():
258 ip = get_ipython()
259 ip = get_ipython()
259 c = ip.Completer
260 c = ip.Completer
260 ip.ex('class D: x=24')
261 ip.ex('class D: x=24')
261 ip.ex('d=D()')
262 ip.ex('d=D()')
262 ip.ex("d.__all__=['z']")
263 ip.ex("d.__all__=['z']")
263 cfg = Config()
264 cfg = Config()
264 cfg.IPCompleter.limit_to__all__ = True
265 cfg.IPCompleter.limit_to__all__ = True
265 c.update_config(cfg)
266 c.update_config(cfg)
266 s, matches = c.complete('d.')
267 s, matches = c.complete('d.')
267 nt.assert_in('d.z', matches)
268 nt.assert_in('d.z', matches)
268 nt.assert_not_in('d.x', matches)
269 nt.assert_not_in('d.x', matches)
269
270
270
271
271 def test_get__all__entries_ok():
272 def test_get__all__entries_ok():
272 class A(object):
273 class A(object):
273 __all__ = ['x', 1]
274 __all__ = ['x', 1]
274 words = completer.get__all__entries(A())
275 words = completer.get__all__entries(A())
275 nt.assert_equal(words, ['x'])
276 nt.assert_equal(words, ['x'])
276
277
277
278
278 def test_get__all__entries_no__all__ok():
279 def test_get__all__entries_no__all__ok():
279 class A(object):
280 class A(object):
280 pass
281 pass
281 words = completer.get__all__entries(A())
282 words = completer.get__all__entries(A())
282 nt.assert_equal(words, [])
283 nt.assert_equal(words, [])
283
284
284
285
285 def test_func_kw_completions():
286 def test_func_kw_completions():
286 ip = get_ipython()
287 ip = get_ipython()
287 c = ip.Completer
288 c = ip.Completer
288 ip.ex('def myfunc(a=1,b=2): return a+b')
289 ip.ex('def myfunc(a=1,b=2): return a+b')
289 s, matches = c.complete(None, 'myfunc(1,b')
290 s, matches = c.complete(None, 'myfunc(1,b')
290 nt.assert_in('b=', matches)
291 nt.assert_in('b=', matches)
291 # Simulate completing with cursor right after b (pos==10):
292 # Simulate completing with cursor right after b (pos==10):
292 s, matches = c.complete(None, 'myfunc(1,b)', 10)
293 s, matches = c.complete(None, 'myfunc(1,b)', 10)
293 nt.assert_in('b=', matches)
294 nt.assert_in('b=', matches)
294 s, matches = c.complete(None, 'myfunc(a="escaped\\")string",b')
295 s, matches = c.complete(None, 'myfunc(a="escaped\\")string",b')
295 nt.assert_in('b=', matches)
296 nt.assert_in('b=', matches)
296 #builtin function
297 #builtin function
297 s, matches = c.complete(None, 'min(k, k')
298 s, matches = c.complete(None, 'min(k, k')
298 nt.assert_in('key=', matches)
299 nt.assert_in('key=', matches)
299
300
300
301
301 def test_default_arguments_from_docstring():
302 def test_default_arguments_from_docstring():
302 doc = min.__doc__
303 doc = min.__doc__
303 ip = get_ipython()
304 ip = get_ipython()
304 c = ip.Completer
305 c = ip.Completer
305 kwd = c._default_arguments_from_docstring(
306 kwd = c._default_arguments_from_docstring(
306 'min(iterable[, key=func]) -> value')
307 'min(iterable[, key=func]) -> value')
307 nt.assert_equal(kwd, ['key'])
308 nt.assert_equal(kwd, ['key'])
308 #with cython type etc
309 #with cython type etc
309 kwd = c._default_arguments_from_docstring(
310 kwd = c._default_arguments_from_docstring(
310 'Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n')
311 'Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n')
311 nt.assert_equal(kwd, ['ncall', 'resume', 'nsplit'])
312 nt.assert_equal(kwd, ['ncall', 'resume', 'nsplit'])
312 #white spaces
313 #white spaces
313 kwd = c._default_arguments_from_docstring(
314 kwd = c._default_arguments_from_docstring(
314 '\n Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n')
315 '\n Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n')
315 nt.assert_equal(kwd, ['ncall', 'resume', 'nsplit'])
316 nt.assert_equal(kwd, ['ncall', 'resume', 'nsplit'])
316
317
317 def test_line_magics():
318 def test_line_magics():
318 ip = get_ipython()
319 ip = get_ipython()
319 c = ip.Completer
320 c = ip.Completer
320 s, matches = c.complete(None, 'lsmag')
321 s, matches = c.complete(None, 'lsmag')
321 nt.assert_in('%lsmagic', matches)
322 nt.assert_in('%lsmagic', matches)
322 s, matches = c.complete(None, '%lsmag')
323 s, matches = c.complete(None, '%lsmag')
323 nt.assert_in('%lsmagic', matches)
324 nt.assert_in('%lsmagic', matches)
324
325
325
326
326 def test_cell_magics():
327 def test_cell_magics():
327 from IPython.core.magic import register_cell_magic
328 from IPython.core.magic import register_cell_magic
328
329
329 @register_cell_magic
330 @register_cell_magic
330 def _foo_cellm(line, cell):
331 def _foo_cellm(line, cell):
331 pass
332 pass
332
333
333 ip = get_ipython()
334 ip = get_ipython()
334 c = ip.Completer
335 c = ip.Completer
335
336
336 s, matches = c.complete(None, '_foo_ce')
337 s, matches = c.complete(None, '_foo_ce')
337 nt.assert_in('%%_foo_cellm', matches)
338 nt.assert_in('%%_foo_cellm', matches)
338 s, matches = c.complete(None, '%%_foo_ce')
339 s, matches = c.complete(None, '%%_foo_ce')
339 nt.assert_in('%%_foo_cellm', matches)
340 nt.assert_in('%%_foo_cellm', matches)
340
341
341
342
342 def test_line_cell_magics():
343 def test_line_cell_magics():
343 from IPython.core.magic import register_line_cell_magic
344 from IPython.core.magic import register_line_cell_magic
344
345
345 @register_line_cell_magic
346 @register_line_cell_magic
346 def _bar_cellm(line, cell):
347 def _bar_cellm(line, cell):
347 pass
348 pass
348
349
349 ip = get_ipython()
350 ip = get_ipython()
350 c = ip.Completer
351 c = ip.Completer
351
352
352 # The policy here is trickier, see comments in completion code. The
353 # The policy here is trickier, see comments in completion code. The
353 # returned values depend on whether the user passes %% or not explicitly,
354 # returned values depend on whether the user passes %% or not explicitly,
354 # and this will show a difference if the same name is both a line and cell
355 # and this will show a difference if the same name is both a line and cell
355 # magic.
356 # magic.
356 s, matches = c.complete(None, '_bar_ce')
357 s, matches = c.complete(None, '_bar_ce')
357 nt.assert_in('%_bar_cellm', matches)
358 nt.assert_in('%_bar_cellm', matches)
358 nt.assert_in('%%_bar_cellm', matches)
359 nt.assert_in('%%_bar_cellm', matches)
359 s, matches = c.complete(None, '%_bar_ce')
360 s, matches = c.complete(None, '%_bar_ce')
360 nt.assert_in('%_bar_cellm', matches)
361 nt.assert_in('%_bar_cellm', matches)
361 nt.assert_in('%%_bar_cellm', matches)
362 nt.assert_in('%%_bar_cellm', matches)
362 s, matches = c.complete(None, '%%_bar_ce')
363 s, matches = c.complete(None, '%%_bar_ce')
363 nt.assert_not_in('%_bar_cellm', matches)
364 nt.assert_not_in('%_bar_cellm', matches)
364 nt.assert_in('%%_bar_cellm', matches)
365 nt.assert_in('%%_bar_cellm', matches)
365
366
366
367
367 def test_magic_completion_order():
368 def test_magic_completion_order():
368
369
369 ip = get_ipython()
370 ip = get_ipython()
370 c = ip.Completer
371 c = ip.Completer
371
372
372 # Test ordering of magics and non-magics with the same name
373 # Test ordering of magics and non-magics with the same name
373 # We want the non-magic first
374 # We want the non-magic first
374
375
375 # Before importing matplotlib, there should only be one option:
376 # Before importing matplotlib, there should only be one option:
376
377
377 text, matches = c.complete('mat')
378 text, matches = c.complete('mat')
378 nt.assert_equal(matches, ["%matplotlib"])
379 nt.assert_equal(matches, ["%matplotlib"])
379
380
380
381
381 ip.run_cell("matplotlib = 1") # introduce name into namespace
382 ip.run_cell("matplotlib = 1") # introduce name into namespace
382
383
383 # After the import, there should be two options, ordered like this:
384 # After the import, there should be two options, ordered like this:
384 text, matches = c.complete('mat')
385 text, matches = c.complete('mat')
385 nt.assert_equal(matches, ["matplotlib", "%matplotlib"])
386 nt.assert_equal(matches, ["matplotlib", "%matplotlib"])
386
387
387
388
388 ip.run_cell("timeit = 1") # define a user variable called 'timeit'
389 ip.run_cell("timeit = 1") # define a user variable called 'timeit'
389
390
390 # Order of user variable and line and cell magics with same name:
391 # Order of user variable and line and cell magics with same name:
391 text, matches = c.complete('timeit')
392 text, matches = c.complete('timeit')
392 nt.assert_equal(matches, ["timeit", "%timeit","%%timeit"])
393 nt.assert_equal(matches, ["timeit", "%timeit","%%timeit"])
393
394
@@ -1,120 +1,121 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for completerlib.
2 """Tests for completerlib.
3
3
4 """
4 """
5 from __future__ import absolute_import
5 from __future__ import absolute_import
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Imports
8 # Imports
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 import os
11 import os
12 import shutil
12 import shutil
13 import sys
13 import sys
14 import tempfile
14 import tempfile
15 import unittest
15 import unittest
16 from os.path import join
16 from os.path import join
17
17
18 from IPython.core.completerlib import magic_run_completer, module_completion
18 from IPython.core.completerlib import magic_run_completer, module_completion
19 from IPython.utils import py3compat
19 from IPython.utils.tempdir import TemporaryDirectory
20 from IPython.utils.tempdir import TemporaryDirectory
20 from IPython.testing.decorators import onlyif_unicode_paths
21 from IPython.testing.decorators import onlyif_unicode_paths
21
22
22
23
23 class MockEvent(object):
24 class MockEvent(object):
24 def __init__(self, line):
25 def __init__(self, line):
25 self.line = line
26 self.line = line
26
27
27 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
28 # Test functions begin
29 # Test functions begin
29 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
30 class Test_magic_run_completer(unittest.TestCase):
31 class Test_magic_run_completer(unittest.TestCase):
31 def setUp(self):
32 def setUp(self):
32 self.BASETESTDIR = tempfile.mkdtemp()
33 self.BASETESTDIR = tempfile.mkdtemp()
33 for fil in [u"aao.py", u"a.py", u"b.py"]:
34 for fil in [u"aao.py", u"a.py", u"b.py"]:
34 with open(join(self.BASETESTDIR, fil), "w") as sfile:
35 with open(join(self.BASETESTDIR, fil), "w") as sfile:
35 sfile.write("pass\n")
36 sfile.write("pass\n")
36 self.oldpath = os.getcwdu()
37 self.oldpath = py3compat.getcwd()
37 os.chdir(self.BASETESTDIR)
38 os.chdir(self.BASETESTDIR)
38
39
39 def tearDown(self):
40 def tearDown(self):
40 os.chdir(self.oldpath)
41 os.chdir(self.oldpath)
41 shutil.rmtree(self.BASETESTDIR)
42 shutil.rmtree(self.BASETESTDIR)
42
43
43 def test_1(self):
44 def test_1(self):
44 """Test magic_run_completer, should match two alterntives
45 """Test magic_run_completer, should match two alterntives
45 """
46 """
46 event = MockEvent(u"%run a")
47 event = MockEvent(u"%run a")
47 mockself = None
48 mockself = None
48 match = set(magic_run_completer(mockself, event))
49 match = set(magic_run_completer(mockself, event))
49 self.assertEqual(match, set([u"a.py", u"aao.py"]))
50 self.assertEqual(match, set([u"a.py", u"aao.py"]))
50
51
51 def test_2(self):
52 def test_2(self):
52 """Test magic_run_completer, should match one alterntive
53 """Test magic_run_completer, should match one alterntive
53 """
54 """
54 event = MockEvent(u"%run aa")
55 event = MockEvent(u"%run aa")
55 mockself = None
56 mockself = None
56 match = set(magic_run_completer(mockself, event))
57 match = set(magic_run_completer(mockself, event))
57 self.assertEqual(match, set([u"aao.py"]))
58 self.assertEqual(match, set([u"aao.py"]))
58
59
59 def test_3(self):
60 def test_3(self):
60 """Test magic_run_completer with unterminated " """
61 """Test magic_run_completer with unterminated " """
61 event = MockEvent(u'%run "a')
62 event = MockEvent(u'%run "a')
62 mockself = None
63 mockself = None
63 match = set(magic_run_completer(mockself, event))
64 match = set(magic_run_completer(mockself, event))
64 self.assertEqual(match, set([u"a.py", u"aao.py"]))
65 self.assertEqual(match, set([u"a.py", u"aao.py"]))
65
66
66 def test_import_invalid_module(self):
67 def test_import_invalid_module(self):
67 """Testing of issue https://github.com/ipython/ipython/issues/1107"""
68 """Testing of issue https://github.com/ipython/ipython/issues/1107"""
68 invalid_module_names = set(['foo-bar', 'foo:bar', '10foo'])
69 invalid_module_names = set(['foo-bar', 'foo:bar', '10foo'])
69 valid_module_names = set(['foobar'])
70 valid_module_names = set(['foobar'])
70 with TemporaryDirectory() as tmpdir:
71 with TemporaryDirectory() as tmpdir:
71 sys.path.insert( 0, tmpdir )
72 sys.path.insert( 0, tmpdir )
72 for name in invalid_module_names | valid_module_names:
73 for name in invalid_module_names | valid_module_names:
73 filename = os.path.join(tmpdir, name + '.py')
74 filename = os.path.join(tmpdir, name + '.py')
74 open(filename, 'w').close()
75 open(filename, 'w').close()
75
76
76 s = set( module_completion('import foo') )
77 s = set( module_completion('import foo') )
77 intersection = s.intersection(invalid_module_names)
78 intersection = s.intersection(invalid_module_names)
78 self.assertFalse(intersection, intersection)
79 self.assertFalse(intersection, intersection)
79
80
80 assert valid_module_names.issubset(s), valid_module_names.intersection(s)
81 assert valid_module_names.issubset(s), valid_module_names.intersection(s)
81
82
82 class Test_magic_run_completer_nonascii(unittest.TestCase):
83 class Test_magic_run_completer_nonascii(unittest.TestCase):
83 @onlyif_unicode_paths
84 @onlyif_unicode_paths
84 def setUp(self):
85 def setUp(self):
85 self.BASETESTDIR = tempfile.mkdtemp()
86 self.BASETESTDIR = tempfile.mkdtemp()
86 for fil in [u"aaø.py", u"a.py", u"b.py"]:
87 for fil in [u"aaø.py", u"a.py", u"b.py"]:
87 with open(join(self.BASETESTDIR, fil), "w") as sfile:
88 with open(join(self.BASETESTDIR, fil), "w") as sfile:
88 sfile.write("pass\n")
89 sfile.write("pass\n")
89 self.oldpath = os.getcwdu()
90 self.oldpath = py3compat.getcwd()
90 os.chdir(self.BASETESTDIR)
91 os.chdir(self.BASETESTDIR)
91
92
92 def tearDown(self):
93 def tearDown(self):
93 os.chdir(self.oldpath)
94 os.chdir(self.oldpath)
94 shutil.rmtree(self.BASETESTDIR)
95 shutil.rmtree(self.BASETESTDIR)
95
96
96 @onlyif_unicode_paths
97 @onlyif_unicode_paths
97 def test_1(self):
98 def test_1(self):
98 """Test magic_run_completer, should match two alterntives
99 """Test magic_run_completer, should match two alterntives
99 """
100 """
100 event = MockEvent(u"%run a")
101 event = MockEvent(u"%run a")
101 mockself = None
102 mockself = None
102 match = set(magic_run_completer(mockself, event))
103 match = set(magic_run_completer(mockself, event))
103 self.assertEqual(match, set([u"a.py", u"aaø.py"]))
104 self.assertEqual(match, set([u"a.py", u"aaø.py"]))
104
105
105 @onlyif_unicode_paths
106 @onlyif_unicode_paths
106 def test_2(self):
107 def test_2(self):
107 """Test magic_run_completer, should match one alterntive
108 """Test magic_run_completer, should match one alterntive
108 """
109 """
109 event = MockEvent(u"%run aa")
110 event = MockEvent(u"%run aa")
110 mockself = None
111 mockself = None
111 match = set(magic_run_completer(mockself, event))
112 match = set(magic_run_completer(mockself, event))
112 self.assertEqual(match, set([u"aaø.py"]))
113 self.assertEqual(match, set([u"aaø.py"]))
113
114
114 @onlyif_unicode_paths
115 @onlyif_unicode_paths
115 def test_3(self):
116 def test_3(self):
116 """Test magic_run_completer with unterminated " """
117 """Test magic_run_completer with unterminated " """
117 event = MockEvent(u'%run "a')
118 event = MockEvent(u'%run "a')
118 mockself = None
119 mockself = None
119 match = set(magic_run_completer(mockself, event))
120 match = set(magic_run_completer(mockself, event))
120 self.assertEqual(match, set([u"a.py", u"aaø.py"]))
121 self.assertEqual(match, set([u"a.py", u"aaø.py"]))
@@ -1,676 +1,677 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for the key interactiveshell module.
2 """Tests for the key interactiveshell module.
3
3
4 Historically the main classes in interactiveshell have been under-tested. This
4 Historically the main classes in interactiveshell have been under-tested. This
5 module should grow as many single-method tests as possible to trap many of the
5 module should grow as many single-method tests as possible to trap many of the
6 recurring bugs we seem to encounter with high-level interaction.
6 recurring bugs we seem to encounter with high-level interaction.
7
7
8 Authors
8 Authors
9 -------
9 -------
10 * Fernando Perez
10 * Fernando Perez
11 """
11 """
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2011 The IPython Development Team
13 # Copyright (C) 2011 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # stdlib
22 # stdlib
23 import ast
23 import ast
24 import os
24 import os
25 import signal
25 import signal
26 import shutil
26 import shutil
27 import sys
27 import sys
28 import tempfile
28 import tempfile
29 import unittest
29 import unittest
30 from os.path import join
30 from os.path import join
31
31
32 # third-party
32 # third-party
33 import nose.tools as nt
33 import nose.tools as nt
34
34
35 # Our own
35 # Our own
36 from IPython.testing.decorators import skipif, skip_win32, onlyif_unicode_paths
36 from IPython.testing.decorators import skipif, skip_win32, onlyif_unicode_paths
37 from IPython.testing import tools as tt
37 from IPython.testing import tools as tt
38 from IPython.utils import io
38 from IPython.utils import io
39 from IPython.utils import py3compat
39 from IPython.utils.py3compat import unicode_type, PY3
40 from IPython.utils.py3compat import unicode_type, PY3
40
41
41 if PY3:
42 if PY3:
42 from io import StringIO
43 from io import StringIO
43 else:
44 else:
44 from StringIO import StringIO
45 from StringIO import StringIO
45
46
46 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
47 # Globals
48 # Globals
48 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
49 # This is used by every single test, no point repeating it ad nauseam
50 # This is used by every single test, no point repeating it ad nauseam
50 ip = get_ipython()
51 ip = get_ipython()
51
52
52 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
53 # Tests
54 # Tests
54 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
55
56
56 class InteractiveShellTestCase(unittest.TestCase):
57 class InteractiveShellTestCase(unittest.TestCase):
57 def test_naked_string_cells(self):
58 def test_naked_string_cells(self):
58 """Test that cells with only naked strings are fully executed"""
59 """Test that cells with only naked strings are fully executed"""
59 # First, single-line inputs
60 # First, single-line inputs
60 ip.run_cell('"a"\n')
61 ip.run_cell('"a"\n')
61 self.assertEqual(ip.user_ns['_'], 'a')
62 self.assertEqual(ip.user_ns['_'], 'a')
62 # And also multi-line cells
63 # And also multi-line cells
63 ip.run_cell('"""a\nb"""\n')
64 ip.run_cell('"""a\nb"""\n')
64 self.assertEqual(ip.user_ns['_'], 'a\nb')
65 self.assertEqual(ip.user_ns['_'], 'a\nb')
65
66
66 def test_run_empty_cell(self):
67 def test_run_empty_cell(self):
67 """Just make sure we don't get a horrible error with a blank
68 """Just make sure we don't get a horrible error with a blank
68 cell of input. Yes, I did overlook that."""
69 cell of input. Yes, I did overlook that."""
69 old_xc = ip.execution_count
70 old_xc = ip.execution_count
70 ip.run_cell('')
71 ip.run_cell('')
71 self.assertEqual(ip.execution_count, old_xc)
72 self.assertEqual(ip.execution_count, old_xc)
72
73
73 def test_run_cell_multiline(self):
74 def test_run_cell_multiline(self):
74 """Multi-block, multi-line cells must execute correctly.
75 """Multi-block, multi-line cells must execute correctly.
75 """
76 """
76 src = '\n'.join(["x=1",
77 src = '\n'.join(["x=1",
77 "y=2",
78 "y=2",
78 "if 1:",
79 "if 1:",
79 " x += 1",
80 " x += 1",
80 " y += 1",])
81 " y += 1",])
81 ip.run_cell(src)
82 ip.run_cell(src)
82 self.assertEqual(ip.user_ns['x'], 2)
83 self.assertEqual(ip.user_ns['x'], 2)
83 self.assertEqual(ip.user_ns['y'], 3)
84 self.assertEqual(ip.user_ns['y'], 3)
84
85
85 def test_multiline_string_cells(self):
86 def test_multiline_string_cells(self):
86 "Code sprinkled with multiline strings should execute (GH-306)"
87 "Code sprinkled with multiline strings should execute (GH-306)"
87 ip.run_cell('tmp=0')
88 ip.run_cell('tmp=0')
88 self.assertEqual(ip.user_ns['tmp'], 0)
89 self.assertEqual(ip.user_ns['tmp'], 0)
89 ip.run_cell('tmp=1;"""a\nb"""\n')
90 ip.run_cell('tmp=1;"""a\nb"""\n')
90 self.assertEqual(ip.user_ns['tmp'], 1)
91 self.assertEqual(ip.user_ns['tmp'], 1)
91
92
92 def test_dont_cache_with_semicolon(self):
93 def test_dont_cache_with_semicolon(self):
93 "Ending a line with semicolon should not cache the returned object (GH-307)"
94 "Ending a line with semicolon should not cache the returned object (GH-307)"
94 oldlen = len(ip.user_ns['Out'])
95 oldlen = len(ip.user_ns['Out'])
95 a = ip.run_cell('1;', store_history=True)
96 a = ip.run_cell('1;', store_history=True)
96 newlen = len(ip.user_ns['Out'])
97 newlen = len(ip.user_ns['Out'])
97 self.assertEqual(oldlen, newlen)
98 self.assertEqual(oldlen, newlen)
98 #also test the default caching behavior
99 #also test the default caching behavior
99 ip.run_cell('1', store_history=True)
100 ip.run_cell('1', store_history=True)
100 newlen = len(ip.user_ns['Out'])
101 newlen = len(ip.user_ns['Out'])
101 self.assertEqual(oldlen+1, newlen)
102 self.assertEqual(oldlen+1, newlen)
102
103
103 def test_In_variable(self):
104 def test_In_variable(self):
104 "Verify that In variable grows with user input (GH-284)"
105 "Verify that In variable grows with user input (GH-284)"
105 oldlen = len(ip.user_ns['In'])
106 oldlen = len(ip.user_ns['In'])
106 ip.run_cell('1;', store_history=True)
107 ip.run_cell('1;', store_history=True)
107 newlen = len(ip.user_ns['In'])
108 newlen = len(ip.user_ns['In'])
108 self.assertEqual(oldlen+1, newlen)
109 self.assertEqual(oldlen+1, newlen)
109 self.assertEqual(ip.user_ns['In'][-1],'1;')
110 self.assertEqual(ip.user_ns['In'][-1],'1;')
110
111
111 def test_magic_names_in_string(self):
112 def test_magic_names_in_string(self):
112 ip.run_cell('a = """\n%exit\n"""')
113 ip.run_cell('a = """\n%exit\n"""')
113 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
114 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
114
115
115 def test_trailing_newline(self):
116 def test_trailing_newline(self):
116 """test that running !(command) does not raise a SyntaxError"""
117 """test that running !(command) does not raise a SyntaxError"""
117 ip.run_cell('!(true)\n', False)
118 ip.run_cell('!(true)\n', False)
118 ip.run_cell('!(true)\n\n\n', False)
119 ip.run_cell('!(true)\n\n\n', False)
119
120
120 def test_gh_597(self):
121 def test_gh_597(self):
121 """Pretty-printing lists of objects with non-ascii reprs may cause
122 """Pretty-printing lists of objects with non-ascii reprs may cause
122 problems."""
123 problems."""
123 class Spam(object):
124 class Spam(object):
124 def __repr__(self):
125 def __repr__(self):
125 return "\xe9"*50
126 return "\xe9"*50
126 import IPython.core.formatters
127 import IPython.core.formatters
127 f = IPython.core.formatters.PlainTextFormatter()
128 f = IPython.core.formatters.PlainTextFormatter()
128 f([Spam(),Spam()])
129 f([Spam(),Spam()])
129
130
130
131
131 def test_future_flags(self):
132 def test_future_flags(self):
132 """Check that future flags are used for parsing code (gh-777)"""
133 """Check that future flags are used for parsing code (gh-777)"""
133 ip.run_cell('from __future__ import print_function')
134 ip.run_cell('from __future__ import print_function')
134 try:
135 try:
135 ip.run_cell('prfunc_return_val = print(1,2, sep=" ")')
136 ip.run_cell('prfunc_return_val = print(1,2, sep=" ")')
136 assert 'prfunc_return_val' in ip.user_ns
137 assert 'prfunc_return_val' in ip.user_ns
137 finally:
138 finally:
138 # Reset compiler flags so we don't mess up other tests.
139 # Reset compiler flags so we don't mess up other tests.
139 ip.compile.reset_compiler_flags()
140 ip.compile.reset_compiler_flags()
140
141
141 def test_future_unicode(self):
142 def test_future_unicode(self):
142 """Check that unicode_literals is imported from __future__ (gh #786)"""
143 """Check that unicode_literals is imported from __future__ (gh #786)"""
143 try:
144 try:
144 ip.run_cell(u'byte_str = "a"')
145 ip.run_cell(u'byte_str = "a"')
145 assert isinstance(ip.user_ns['byte_str'], str) # string literals are byte strings by default
146 assert isinstance(ip.user_ns['byte_str'], str) # string literals are byte strings by default
146 ip.run_cell('from __future__ import unicode_literals')
147 ip.run_cell('from __future__ import unicode_literals')
147 ip.run_cell(u'unicode_str = "a"')
148 ip.run_cell(u'unicode_str = "a"')
148 assert isinstance(ip.user_ns['unicode_str'], unicode_type) # strings literals are now unicode
149 assert isinstance(ip.user_ns['unicode_str'], unicode_type) # strings literals are now unicode
149 finally:
150 finally:
150 # Reset compiler flags so we don't mess up other tests.
151 # Reset compiler flags so we don't mess up other tests.
151 ip.compile.reset_compiler_flags()
152 ip.compile.reset_compiler_flags()
152
153
153 def test_can_pickle(self):
154 def test_can_pickle(self):
154 "Can we pickle objects defined interactively (GH-29)"
155 "Can we pickle objects defined interactively (GH-29)"
155 ip = get_ipython()
156 ip = get_ipython()
156 ip.reset()
157 ip.reset()
157 ip.run_cell(("class Mylist(list):\n"
158 ip.run_cell(("class Mylist(list):\n"
158 " def __init__(self,x=[]):\n"
159 " def __init__(self,x=[]):\n"
159 " list.__init__(self,x)"))
160 " list.__init__(self,x)"))
160 ip.run_cell("w=Mylist([1,2,3])")
161 ip.run_cell("w=Mylist([1,2,3])")
161
162
162 from pickle import dumps
163 from pickle import dumps
163
164
164 # We need to swap in our main module - this is only necessary
165 # We need to swap in our main module - this is only necessary
165 # inside the test framework, because IPython puts the interactive module
166 # inside the test framework, because IPython puts the interactive module
166 # in place (but the test framework undoes this).
167 # in place (but the test framework undoes this).
167 _main = sys.modules['__main__']
168 _main = sys.modules['__main__']
168 sys.modules['__main__'] = ip.user_module
169 sys.modules['__main__'] = ip.user_module
169 try:
170 try:
170 res = dumps(ip.user_ns["w"])
171 res = dumps(ip.user_ns["w"])
171 finally:
172 finally:
172 sys.modules['__main__'] = _main
173 sys.modules['__main__'] = _main
173 self.assertTrue(isinstance(res, bytes))
174 self.assertTrue(isinstance(res, bytes))
174
175
175 def test_global_ns(self):
176 def test_global_ns(self):
176 "Code in functions must be able to access variables outside them."
177 "Code in functions must be able to access variables outside them."
177 ip = get_ipython()
178 ip = get_ipython()
178 ip.run_cell("a = 10")
179 ip.run_cell("a = 10")
179 ip.run_cell(("def f(x):\n"
180 ip.run_cell(("def f(x):\n"
180 " return x + a"))
181 " return x + a"))
181 ip.run_cell("b = f(12)")
182 ip.run_cell("b = f(12)")
182 self.assertEqual(ip.user_ns["b"], 22)
183 self.assertEqual(ip.user_ns["b"], 22)
183
184
184 def test_bad_custom_tb(self):
185 def test_bad_custom_tb(self):
185 """Check that InteractiveShell is protected from bad custom exception handlers"""
186 """Check that InteractiveShell is protected from bad custom exception handlers"""
186 from IPython.utils import io
187 from IPython.utils import io
187 save_stderr = io.stderr
188 save_stderr = io.stderr
188 try:
189 try:
189 # capture stderr
190 # capture stderr
190 io.stderr = StringIO()
191 io.stderr = StringIO()
191 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
192 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
192 self.assertEqual(ip.custom_exceptions, (IOError,))
193 self.assertEqual(ip.custom_exceptions, (IOError,))
193 ip.run_cell(u'raise IOError("foo")')
194 ip.run_cell(u'raise IOError("foo")')
194 self.assertEqual(ip.custom_exceptions, ())
195 self.assertEqual(ip.custom_exceptions, ())
195 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
196 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
196 finally:
197 finally:
197 io.stderr = save_stderr
198 io.stderr = save_stderr
198
199
199 def test_bad_custom_tb_return(self):
200 def test_bad_custom_tb_return(self):
200 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
201 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
201 from IPython.utils import io
202 from IPython.utils import io
202 save_stderr = io.stderr
203 save_stderr = io.stderr
203 try:
204 try:
204 # capture stderr
205 # capture stderr
205 io.stderr = StringIO()
206 io.stderr = StringIO()
206 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
207 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
207 self.assertEqual(ip.custom_exceptions, (NameError,))
208 self.assertEqual(ip.custom_exceptions, (NameError,))
208 ip.run_cell(u'a=abracadabra')
209 ip.run_cell(u'a=abracadabra')
209 self.assertEqual(ip.custom_exceptions, ())
210 self.assertEqual(ip.custom_exceptions, ())
210 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
211 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
211 finally:
212 finally:
212 io.stderr = save_stderr
213 io.stderr = save_stderr
213
214
214 def test_drop_by_id(self):
215 def test_drop_by_id(self):
215 myvars = {"a":object(), "b":object(), "c": object()}
216 myvars = {"a":object(), "b":object(), "c": object()}
216 ip.push(myvars, interactive=False)
217 ip.push(myvars, interactive=False)
217 for name in myvars:
218 for name in myvars:
218 assert name in ip.user_ns, name
219 assert name in ip.user_ns, name
219 assert name in ip.user_ns_hidden, name
220 assert name in ip.user_ns_hidden, name
220 ip.user_ns['b'] = 12
221 ip.user_ns['b'] = 12
221 ip.drop_by_id(myvars)
222 ip.drop_by_id(myvars)
222 for name in ["a", "c"]:
223 for name in ["a", "c"]:
223 assert name not in ip.user_ns, name
224 assert name not in ip.user_ns, name
224 assert name not in ip.user_ns_hidden, name
225 assert name not in ip.user_ns_hidden, name
225 assert ip.user_ns['b'] == 12
226 assert ip.user_ns['b'] == 12
226 ip.reset()
227 ip.reset()
227
228
228 def test_var_expand(self):
229 def test_var_expand(self):
229 ip.user_ns['f'] = u'Ca\xf1o'
230 ip.user_ns['f'] = u'Ca\xf1o'
230 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
231 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
231 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
232 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
232 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
233 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
233 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
234 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
234
235
235 ip.user_ns['f'] = b'Ca\xc3\xb1o'
236 ip.user_ns['f'] = b'Ca\xc3\xb1o'
236 # This should not raise any exception:
237 # This should not raise any exception:
237 ip.var_expand(u'echo $f')
238 ip.var_expand(u'echo $f')
238
239
239 def test_var_expand_local(self):
240 def test_var_expand_local(self):
240 """Test local variable expansion in !system and %magic calls"""
241 """Test local variable expansion in !system and %magic calls"""
241 # !system
242 # !system
242 ip.run_cell('def test():\n'
243 ip.run_cell('def test():\n'
243 ' lvar = "ttt"\n'
244 ' lvar = "ttt"\n'
244 ' ret = !echo {lvar}\n'
245 ' ret = !echo {lvar}\n'
245 ' return ret[0]\n')
246 ' return ret[0]\n')
246 res = ip.user_ns['test']()
247 res = ip.user_ns['test']()
247 nt.assert_in('ttt', res)
248 nt.assert_in('ttt', res)
248
249
249 # %magic
250 # %magic
250 ip.run_cell('def makemacro():\n'
251 ip.run_cell('def makemacro():\n'
251 ' macroname = "macro_var_expand_locals"\n'
252 ' macroname = "macro_var_expand_locals"\n'
252 ' %macro {macroname} codestr\n')
253 ' %macro {macroname} codestr\n')
253 ip.user_ns['codestr'] = "str(12)"
254 ip.user_ns['codestr'] = "str(12)"
254 ip.run_cell('makemacro()')
255 ip.run_cell('makemacro()')
255 nt.assert_in('macro_var_expand_locals', ip.user_ns)
256 nt.assert_in('macro_var_expand_locals', ip.user_ns)
256
257
257 def test_var_expand_self(self):
258 def test_var_expand_self(self):
258 """Test variable expansion with the name 'self', which was failing.
259 """Test variable expansion with the name 'self', which was failing.
259
260
260 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
261 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
261 """
262 """
262 ip.run_cell('class cTest:\n'
263 ip.run_cell('class cTest:\n'
263 ' classvar="see me"\n'
264 ' classvar="see me"\n'
264 ' def test(self):\n'
265 ' def test(self):\n'
265 ' res = !echo Variable: {self.classvar}\n'
266 ' res = !echo Variable: {self.classvar}\n'
266 ' return res[0]\n')
267 ' return res[0]\n')
267 nt.assert_in('see me', ip.user_ns['cTest']().test())
268 nt.assert_in('see me', ip.user_ns['cTest']().test())
268
269
269 def test_bad_var_expand(self):
270 def test_bad_var_expand(self):
270 """var_expand on invalid formats shouldn't raise"""
271 """var_expand on invalid formats shouldn't raise"""
271 # SyntaxError
272 # SyntaxError
272 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
273 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
273 # NameError
274 # NameError
274 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
275 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
275 # ZeroDivisionError
276 # ZeroDivisionError
276 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
277 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
277
278
278 def test_silent_nopostexec(self):
279 def test_silent_nopostexec(self):
279 """run_cell(silent=True) doesn't invoke post-exec funcs"""
280 """run_cell(silent=True) doesn't invoke post-exec funcs"""
280 d = dict(called=False)
281 d = dict(called=False)
281 def set_called():
282 def set_called():
282 d['called'] = True
283 d['called'] = True
283
284
284 ip.register_post_execute(set_called)
285 ip.register_post_execute(set_called)
285 ip.run_cell("1", silent=True)
286 ip.run_cell("1", silent=True)
286 self.assertFalse(d['called'])
287 self.assertFalse(d['called'])
287 # double-check that non-silent exec did what we expected
288 # double-check that non-silent exec did what we expected
288 # silent to avoid
289 # silent to avoid
289 ip.run_cell("1")
290 ip.run_cell("1")
290 self.assertTrue(d['called'])
291 self.assertTrue(d['called'])
291 # remove post-exec
292 # remove post-exec
292 ip._post_execute.pop(set_called)
293 ip._post_execute.pop(set_called)
293
294
294 def test_silent_noadvance(self):
295 def test_silent_noadvance(self):
295 """run_cell(silent=True) doesn't advance execution_count"""
296 """run_cell(silent=True) doesn't advance execution_count"""
296 ec = ip.execution_count
297 ec = ip.execution_count
297 # silent should force store_history=False
298 # silent should force store_history=False
298 ip.run_cell("1", store_history=True, silent=True)
299 ip.run_cell("1", store_history=True, silent=True)
299
300
300 self.assertEqual(ec, ip.execution_count)
301 self.assertEqual(ec, ip.execution_count)
301 # double-check that non-silent exec did what we expected
302 # double-check that non-silent exec did what we expected
302 # silent to avoid
303 # silent to avoid
303 ip.run_cell("1", store_history=True)
304 ip.run_cell("1", store_history=True)
304 self.assertEqual(ec+1, ip.execution_count)
305 self.assertEqual(ec+1, ip.execution_count)
305
306
306 def test_silent_nodisplayhook(self):
307 def test_silent_nodisplayhook(self):
307 """run_cell(silent=True) doesn't trigger displayhook"""
308 """run_cell(silent=True) doesn't trigger displayhook"""
308 d = dict(called=False)
309 d = dict(called=False)
309
310
310 trap = ip.display_trap
311 trap = ip.display_trap
311 save_hook = trap.hook
312 save_hook = trap.hook
312
313
313 def failing_hook(*args, **kwargs):
314 def failing_hook(*args, **kwargs):
314 d['called'] = True
315 d['called'] = True
315
316
316 try:
317 try:
317 trap.hook = failing_hook
318 trap.hook = failing_hook
318 ip.run_cell("1", silent=True)
319 ip.run_cell("1", silent=True)
319 self.assertFalse(d['called'])
320 self.assertFalse(d['called'])
320 # double-check that non-silent exec did what we expected
321 # double-check that non-silent exec did what we expected
321 # silent to avoid
322 # silent to avoid
322 ip.run_cell("1")
323 ip.run_cell("1")
323 self.assertTrue(d['called'])
324 self.assertTrue(d['called'])
324 finally:
325 finally:
325 trap.hook = save_hook
326 trap.hook = save_hook
326
327
327 @skipif(sys.version_info[0] >= 3, "softspace removed in py3")
328 @skipif(sys.version_info[0] >= 3, "softspace removed in py3")
328 def test_print_softspace(self):
329 def test_print_softspace(self):
329 """Verify that softspace is handled correctly when executing multiple
330 """Verify that softspace is handled correctly when executing multiple
330 statements.
331 statements.
331
332
332 In [1]: print 1; print 2
333 In [1]: print 1; print 2
333 1
334 1
334 2
335 2
335
336
336 In [2]: print 1,; print 2
337 In [2]: print 1,; print 2
337 1 2
338 1 2
338 """
339 """
339
340
340 def test_ofind_line_magic(self):
341 def test_ofind_line_magic(self):
341 from IPython.core.magic import register_line_magic
342 from IPython.core.magic import register_line_magic
342
343
343 @register_line_magic
344 @register_line_magic
344 def lmagic(line):
345 def lmagic(line):
345 "A line magic"
346 "A line magic"
346
347
347 # Get info on line magic
348 # Get info on line magic
348 lfind = ip._ofind('lmagic')
349 lfind = ip._ofind('lmagic')
349 info = dict(found=True, isalias=False, ismagic=True,
350 info = dict(found=True, isalias=False, ismagic=True,
350 namespace = 'IPython internal', obj= lmagic.__wrapped__,
351 namespace = 'IPython internal', obj= lmagic.__wrapped__,
351 parent = None)
352 parent = None)
352 nt.assert_equal(lfind, info)
353 nt.assert_equal(lfind, info)
353
354
354 def test_ofind_cell_magic(self):
355 def test_ofind_cell_magic(self):
355 from IPython.core.magic import register_cell_magic
356 from IPython.core.magic import register_cell_magic
356
357
357 @register_cell_magic
358 @register_cell_magic
358 def cmagic(line, cell):
359 def cmagic(line, cell):
359 "A cell magic"
360 "A cell magic"
360
361
361 # Get info on cell magic
362 # Get info on cell magic
362 find = ip._ofind('cmagic')
363 find = ip._ofind('cmagic')
363 info = dict(found=True, isalias=False, ismagic=True,
364 info = dict(found=True, isalias=False, ismagic=True,
364 namespace = 'IPython internal', obj= cmagic.__wrapped__,
365 namespace = 'IPython internal', obj= cmagic.__wrapped__,
365 parent = None)
366 parent = None)
366 nt.assert_equal(find, info)
367 nt.assert_equal(find, info)
367
368
368 def test_custom_exception(self):
369 def test_custom_exception(self):
369 called = []
370 called = []
370 def my_handler(shell, etype, value, tb, tb_offset=None):
371 def my_handler(shell, etype, value, tb, tb_offset=None):
371 called.append(etype)
372 called.append(etype)
372 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
373 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
373
374
374 ip.set_custom_exc((ValueError,), my_handler)
375 ip.set_custom_exc((ValueError,), my_handler)
375 try:
376 try:
376 ip.run_cell("raise ValueError('test')")
377 ip.run_cell("raise ValueError('test')")
377 # Check that this was called, and only once.
378 # Check that this was called, and only once.
378 self.assertEqual(called, [ValueError])
379 self.assertEqual(called, [ValueError])
379 finally:
380 finally:
380 # Reset the custom exception hook
381 # Reset the custom exception hook
381 ip.set_custom_exc((), None)
382 ip.set_custom_exc((), None)
382
383
383 @skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
384 @skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
384 def test_future_environment(self):
385 def test_future_environment(self):
385 "Can we run code with & without the shell's __future__ imports?"
386 "Can we run code with & without the shell's __future__ imports?"
386 ip.run_cell("from __future__ import division")
387 ip.run_cell("from __future__ import division")
387 ip.run_cell("a = 1/2", shell_futures=True)
388 ip.run_cell("a = 1/2", shell_futures=True)
388 self.assertEqual(ip.user_ns['a'], 0.5)
389 self.assertEqual(ip.user_ns['a'], 0.5)
389 ip.run_cell("b = 1/2", shell_futures=False)
390 ip.run_cell("b = 1/2", shell_futures=False)
390 self.assertEqual(ip.user_ns['b'], 0)
391 self.assertEqual(ip.user_ns['b'], 0)
391
392
392 ip.compile.reset_compiler_flags()
393 ip.compile.reset_compiler_flags()
393 # This shouldn't leak to the shell's compiler
394 # This shouldn't leak to the shell's compiler
394 ip.run_cell("from __future__ import division \nc=1/2", shell_futures=False)
395 ip.run_cell("from __future__ import division \nc=1/2", shell_futures=False)
395 self.assertEqual(ip.user_ns['c'], 0.5)
396 self.assertEqual(ip.user_ns['c'], 0.5)
396 ip.run_cell("d = 1/2", shell_futures=True)
397 ip.run_cell("d = 1/2", shell_futures=True)
397 self.assertEqual(ip.user_ns['d'], 0)
398 self.assertEqual(ip.user_ns['d'], 0)
398
399
399
400
400 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
401 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
401
402
402 @onlyif_unicode_paths
403 @onlyif_unicode_paths
403 def setUp(self):
404 def setUp(self):
404 self.BASETESTDIR = tempfile.mkdtemp()
405 self.BASETESTDIR = tempfile.mkdtemp()
405 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
406 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
406 os.mkdir(self.TESTDIR)
407 os.mkdir(self.TESTDIR)
407 with open(join(self.TESTDIR, u"åäötestscript.py"), "w") as sfile:
408 with open(join(self.TESTDIR, u"åäötestscript.py"), "w") as sfile:
408 sfile.write("pass\n")
409 sfile.write("pass\n")
409 self.oldpath = os.getcwdu()
410 self.oldpath = py3compat.getcwd()
410 os.chdir(self.TESTDIR)
411 os.chdir(self.TESTDIR)
411 self.fname = u"åäötestscript.py"
412 self.fname = u"åäötestscript.py"
412
413
413 def tearDown(self):
414 def tearDown(self):
414 os.chdir(self.oldpath)
415 os.chdir(self.oldpath)
415 shutil.rmtree(self.BASETESTDIR)
416 shutil.rmtree(self.BASETESTDIR)
416
417
417 @onlyif_unicode_paths
418 @onlyif_unicode_paths
418 def test_1(self):
419 def test_1(self):
419 """Test safe_execfile with non-ascii path
420 """Test safe_execfile with non-ascii path
420 """
421 """
421 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
422 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
422
423
423 class ExitCodeChecks(tt.TempFileMixin):
424 class ExitCodeChecks(tt.TempFileMixin):
424 def test_exit_code_ok(self):
425 def test_exit_code_ok(self):
425 self.system('exit 0')
426 self.system('exit 0')
426 self.assertEqual(ip.user_ns['_exit_code'], 0)
427 self.assertEqual(ip.user_ns['_exit_code'], 0)
427
428
428 def test_exit_code_error(self):
429 def test_exit_code_error(self):
429 self.system('exit 1')
430 self.system('exit 1')
430 self.assertEqual(ip.user_ns['_exit_code'], 1)
431 self.assertEqual(ip.user_ns['_exit_code'], 1)
431
432
432 @skipif(not hasattr(signal, 'SIGALRM'))
433 @skipif(not hasattr(signal, 'SIGALRM'))
433 def test_exit_code_signal(self):
434 def test_exit_code_signal(self):
434 self.mktmp("import signal, time\n"
435 self.mktmp("import signal, time\n"
435 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
436 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
436 "time.sleep(1)\n")
437 "time.sleep(1)\n")
437 self.system("%s %s" % (sys.executable, self.fname))
438 self.system("%s %s" % (sys.executable, self.fname))
438 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
439 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
439
440
440 class TestSystemRaw(unittest.TestCase, ExitCodeChecks):
441 class TestSystemRaw(unittest.TestCase, ExitCodeChecks):
441 system = ip.system_raw
442 system = ip.system_raw
442
443
443 @onlyif_unicode_paths
444 @onlyif_unicode_paths
444 def test_1(self):
445 def test_1(self):
445 """Test system_raw with non-ascii cmd
446 """Test system_raw with non-ascii cmd
446 """
447 """
447 cmd = u'''python -c "'åäö'" '''
448 cmd = u'''python -c "'åäö'" '''
448 ip.system_raw(cmd)
449 ip.system_raw(cmd)
449
450
450 # TODO: Exit codes are currently ignored on Windows.
451 # TODO: Exit codes are currently ignored on Windows.
451 class TestSystemPipedExitCode(unittest.TestCase, ExitCodeChecks):
452 class TestSystemPipedExitCode(unittest.TestCase, ExitCodeChecks):
452 system = ip.system_piped
453 system = ip.system_piped
453
454
454 @skip_win32
455 @skip_win32
455 def test_exit_code_ok(self):
456 def test_exit_code_ok(self):
456 ExitCodeChecks.test_exit_code_ok(self)
457 ExitCodeChecks.test_exit_code_ok(self)
457
458
458 @skip_win32
459 @skip_win32
459 def test_exit_code_error(self):
460 def test_exit_code_error(self):
460 ExitCodeChecks.test_exit_code_error(self)
461 ExitCodeChecks.test_exit_code_error(self)
461
462
462 @skip_win32
463 @skip_win32
463 def test_exit_code_signal(self):
464 def test_exit_code_signal(self):
464 ExitCodeChecks.test_exit_code_signal(self)
465 ExitCodeChecks.test_exit_code_signal(self)
465
466
466 class TestModules(unittest.TestCase, tt.TempFileMixin):
467 class TestModules(unittest.TestCase, tt.TempFileMixin):
467 def test_extraneous_loads(self):
468 def test_extraneous_loads(self):
468 """Test we're not loading modules on startup that we shouldn't.
469 """Test we're not loading modules on startup that we shouldn't.
469 """
470 """
470 self.mktmp("import sys\n"
471 self.mktmp("import sys\n"
471 "print('numpy' in sys.modules)\n"
472 "print('numpy' in sys.modules)\n"
472 "print('IPython.parallel' in sys.modules)\n"
473 "print('IPython.parallel' in sys.modules)\n"
473 "print('IPython.kernel.zmq' in sys.modules)\n"
474 "print('IPython.kernel.zmq' in sys.modules)\n"
474 )
475 )
475 out = "False\nFalse\nFalse\n"
476 out = "False\nFalse\nFalse\n"
476 tt.ipexec_validate(self.fname, out)
477 tt.ipexec_validate(self.fname, out)
477
478
478 class Negator(ast.NodeTransformer):
479 class Negator(ast.NodeTransformer):
479 """Negates all number literals in an AST."""
480 """Negates all number literals in an AST."""
480 def visit_Num(self, node):
481 def visit_Num(self, node):
481 node.n = -node.n
482 node.n = -node.n
482 return node
483 return node
483
484
484 class TestAstTransform(unittest.TestCase):
485 class TestAstTransform(unittest.TestCase):
485 def setUp(self):
486 def setUp(self):
486 self.negator = Negator()
487 self.negator = Negator()
487 ip.ast_transformers.append(self.negator)
488 ip.ast_transformers.append(self.negator)
488
489
489 def tearDown(self):
490 def tearDown(self):
490 ip.ast_transformers.remove(self.negator)
491 ip.ast_transformers.remove(self.negator)
491
492
492 def test_run_cell(self):
493 def test_run_cell(self):
493 with tt.AssertPrints('-34'):
494 with tt.AssertPrints('-34'):
494 ip.run_cell('print (12 + 22)')
495 ip.run_cell('print (12 + 22)')
495
496
496 # A named reference to a number shouldn't be transformed.
497 # A named reference to a number shouldn't be transformed.
497 ip.user_ns['n'] = 55
498 ip.user_ns['n'] = 55
498 with tt.AssertNotPrints('-55'):
499 with tt.AssertNotPrints('-55'):
499 ip.run_cell('print (n)')
500 ip.run_cell('print (n)')
500
501
501 def test_timeit(self):
502 def test_timeit(self):
502 called = set()
503 called = set()
503 def f(x):
504 def f(x):
504 called.add(x)
505 called.add(x)
505 ip.push({'f':f})
506 ip.push({'f':f})
506
507
507 with tt.AssertPrints("best of "):
508 with tt.AssertPrints("best of "):
508 ip.run_line_magic("timeit", "-n1 f(1)")
509 ip.run_line_magic("timeit", "-n1 f(1)")
509 self.assertEqual(called, set([-1]))
510 self.assertEqual(called, set([-1]))
510 called.clear()
511 called.clear()
511
512
512 with tt.AssertPrints("best of "):
513 with tt.AssertPrints("best of "):
513 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
514 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
514 self.assertEqual(called, set([-2, -3]))
515 self.assertEqual(called, set([-2, -3]))
515
516
516 def test_time(self):
517 def test_time(self):
517 called = []
518 called = []
518 def f(x):
519 def f(x):
519 called.append(x)
520 called.append(x)
520 ip.push({'f':f})
521 ip.push({'f':f})
521
522
522 # Test with an expression
523 # Test with an expression
523 with tt.AssertPrints("Wall time: "):
524 with tt.AssertPrints("Wall time: "):
524 ip.run_line_magic("time", "f(5+9)")
525 ip.run_line_magic("time", "f(5+9)")
525 self.assertEqual(called, [-14])
526 self.assertEqual(called, [-14])
526 called[:] = []
527 called[:] = []
527
528
528 # Test with a statement (different code path)
529 # Test with a statement (different code path)
529 with tt.AssertPrints("Wall time: "):
530 with tt.AssertPrints("Wall time: "):
530 ip.run_line_magic("time", "a = f(-3 + -2)")
531 ip.run_line_magic("time", "a = f(-3 + -2)")
531 self.assertEqual(called, [5])
532 self.assertEqual(called, [5])
532
533
533 def test_macro(self):
534 def test_macro(self):
534 ip.push({'a':10})
535 ip.push({'a':10})
535 # The AST transformation makes this do a+=-1
536 # The AST transformation makes this do a+=-1
536 ip.define_macro("amacro", "a+=1\nprint(a)")
537 ip.define_macro("amacro", "a+=1\nprint(a)")
537
538
538 with tt.AssertPrints("9"):
539 with tt.AssertPrints("9"):
539 ip.run_cell("amacro")
540 ip.run_cell("amacro")
540 with tt.AssertPrints("8"):
541 with tt.AssertPrints("8"):
541 ip.run_cell("amacro")
542 ip.run_cell("amacro")
542
543
543 class IntegerWrapper(ast.NodeTransformer):
544 class IntegerWrapper(ast.NodeTransformer):
544 """Wraps all integers in a call to Integer()"""
545 """Wraps all integers in a call to Integer()"""
545 def visit_Num(self, node):
546 def visit_Num(self, node):
546 if isinstance(node.n, int):
547 if isinstance(node.n, int):
547 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
548 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
548 args=[node], keywords=[])
549 args=[node], keywords=[])
549 return node
550 return node
550
551
551 class TestAstTransform2(unittest.TestCase):
552 class TestAstTransform2(unittest.TestCase):
552 def setUp(self):
553 def setUp(self):
553 self.intwrapper = IntegerWrapper()
554 self.intwrapper = IntegerWrapper()
554 ip.ast_transformers.append(self.intwrapper)
555 ip.ast_transformers.append(self.intwrapper)
555
556
556 self.calls = []
557 self.calls = []
557 def Integer(*args):
558 def Integer(*args):
558 self.calls.append(args)
559 self.calls.append(args)
559 return args
560 return args
560 ip.push({"Integer": Integer})
561 ip.push({"Integer": Integer})
561
562
562 def tearDown(self):
563 def tearDown(self):
563 ip.ast_transformers.remove(self.intwrapper)
564 ip.ast_transformers.remove(self.intwrapper)
564 del ip.user_ns['Integer']
565 del ip.user_ns['Integer']
565
566
566 def test_run_cell(self):
567 def test_run_cell(self):
567 ip.run_cell("n = 2")
568 ip.run_cell("n = 2")
568 self.assertEqual(self.calls, [(2,)])
569 self.assertEqual(self.calls, [(2,)])
569
570
570 # This shouldn't throw an error
571 # This shouldn't throw an error
571 ip.run_cell("o = 2.0")
572 ip.run_cell("o = 2.0")
572 self.assertEqual(ip.user_ns['o'], 2.0)
573 self.assertEqual(ip.user_ns['o'], 2.0)
573
574
574 def test_timeit(self):
575 def test_timeit(self):
575 called = set()
576 called = set()
576 def f(x):
577 def f(x):
577 called.add(x)
578 called.add(x)
578 ip.push({'f':f})
579 ip.push({'f':f})
579
580
580 with tt.AssertPrints("best of "):
581 with tt.AssertPrints("best of "):
581 ip.run_line_magic("timeit", "-n1 f(1)")
582 ip.run_line_magic("timeit", "-n1 f(1)")
582 self.assertEqual(called, set([(1,)]))
583 self.assertEqual(called, set([(1,)]))
583 called.clear()
584 called.clear()
584
585
585 with tt.AssertPrints("best of "):
586 with tt.AssertPrints("best of "):
586 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
587 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
587 self.assertEqual(called, set([(2,), (3,)]))
588 self.assertEqual(called, set([(2,), (3,)]))
588
589
589 class ErrorTransformer(ast.NodeTransformer):
590 class ErrorTransformer(ast.NodeTransformer):
590 """Throws an error when it sees a number."""
591 """Throws an error when it sees a number."""
591 def visit_Num(self):
592 def visit_Num(self):
592 raise ValueError("test")
593 raise ValueError("test")
593
594
594 class TestAstTransformError(unittest.TestCase):
595 class TestAstTransformError(unittest.TestCase):
595 def test_unregistering(self):
596 def test_unregistering(self):
596 err_transformer = ErrorTransformer()
597 err_transformer = ErrorTransformer()
597 ip.ast_transformers.append(err_transformer)
598 ip.ast_transformers.append(err_transformer)
598
599
599 with tt.AssertPrints("unregister", channel='stderr'):
600 with tt.AssertPrints("unregister", channel='stderr'):
600 ip.run_cell("1 + 2")
601 ip.run_cell("1 + 2")
601
602
602 # This should have been removed.
603 # This should have been removed.
603 nt.assert_not_in(err_transformer, ip.ast_transformers)
604 nt.assert_not_in(err_transformer, ip.ast_transformers)
604
605
605 def test__IPYTHON__():
606 def test__IPYTHON__():
606 # This shouldn't raise a NameError, that's all
607 # This shouldn't raise a NameError, that's all
607 __IPYTHON__
608 __IPYTHON__
608
609
609
610
610 class DummyRepr(object):
611 class DummyRepr(object):
611 def __repr__(self):
612 def __repr__(self):
612 return "DummyRepr"
613 return "DummyRepr"
613
614
614 def _repr_html_(self):
615 def _repr_html_(self):
615 return "<b>dummy</b>"
616 return "<b>dummy</b>"
616
617
617 def _repr_javascript_(self):
618 def _repr_javascript_(self):
618 return "console.log('hi');", {'key': 'value'}
619 return "console.log('hi');", {'key': 'value'}
619
620
620
621
621 def test_user_variables():
622 def test_user_variables():
622 # enable all formatters
623 # enable all formatters
623 ip.display_formatter.active_types = ip.display_formatter.format_types
624 ip.display_formatter.active_types = ip.display_formatter.format_types
624
625
625 ip.user_ns['dummy'] = d = DummyRepr()
626 ip.user_ns['dummy'] = d = DummyRepr()
626 keys = set(['dummy', 'doesnotexist'])
627 keys = set(['dummy', 'doesnotexist'])
627 r = ip.user_variables(keys)
628 r = ip.user_variables(keys)
628
629
629 nt.assert_equal(keys, set(r.keys()))
630 nt.assert_equal(keys, set(r.keys()))
630 dummy = r['dummy']
631 dummy = r['dummy']
631 nt.assert_equal(set(['status', 'data', 'metadata']), set(dummy.keys()))
632 nt.assert_equal(set(['status', 'data', 'metadata']), set(dummy.keys()))
632 nt.assert_equal(dummy['status'], 'ok')
633 nt.assert_equal(dummy['status'], 'ok')
633 data = dummy['data']
634 data = dummy['data']
634 metadata = dummy['metadata']
635 metadata = dummy['metadata']
635 nt.assert_equal(data.get('text/html'), d._repr_html_())
636 nt.assert_equal(data.get('text/html'), d._repr_html_())
636 js, jsmd = d._repr_javascript_()
637 js, jsmd = d._repr_javascript_()
637 nt.assert_equal(data.get('application/javascript'), js)
638 nt.assert_equal(data.get('application/javascript'), js)
638 nt.assert_equal(metadata.get('application/javascript'), jsmd)
639 nt.assert_equal(metadata.get('application/javascript'), jsmd)
639
640
640 dne = r['doesnotexist']
641 dne = r['doesnotexist']
641 nt.assert_equal(dne['status'], 'error')
642 nt.assert_equal(dne['status'], 'error')
642 nt.assert_equal(dne['ename'], 'KeyError')
643 nt.assert_equal(dne['ename'], 'KeyError')
643
644
644 # back to text only
645 # back to text only
645 ip.display_formatter.active_types = ['text/plain']
646 ip.display_formatter.active_types = ['text/plain']
646
647
647 def test_user_expression():
648 def test_user_expression():
648 # enable all formatters
649 # enable all formatters
649 ip.display_formatter.active_types = ip.display_formatter.format_types
650 ip.display_formatter.active_types = ip.display_formatter.format_types
650 query = {
651 query = {
651 'a' : '1 + 2',
652 'a' : '1 + 2',
652 'b' : '1/0',
653 'b' : '1/0',
653 }
654 }
654 r = ip.user_expressions(query)
655 r = ip.user_expressions(query)
655 import pprint
656 import pprint
656 pprint.pprint(r)
657 pprint.pprint(r)
657 nt.assert_equal(r.keys(), query.keys())
658 nt.assert_equal(r.keys(), query.keys())
658 a = r['a']
659 a = r['a']
659 nt.assert_equal(set(['status', 'data', 'metadata']), set(a.keys()))
660 nt.assert_equal(set(['status', 'data', 'metadata']), set(a.keys()))
660 nt.assert_equal(a['status'], 'ok')
661 nt.assert_equal(a['status'], 'ok')
661 data = a['data']
662 data = a['data']
662 metadata = a['metadata']
663 metadata = a['metadata']
663 nt.assert_equal(data.get('text/plain'), '3')
664 nt.assert_equal(data.get('text/plain'), '3')
664
665
665 b = r['b']
666 b = r['b']
666 nt.assert_equal(b['status'], 'error')
667 nt.assert_equal(b['status'], 'error')
667 nt.assert_equal(b['ename'], 'ZeroDivisionError')
668 nt.assert_equal(b['ename'], 'ZeroDivisionError')
668
669
669 # back to text only
670 # back to text only
670 ip.display_formatter.active_types = ['text/plain']
671 ip.display_formatter.active_types = ['text/plain']
671
672
672
673
673
674
674
675
675
676
676
677
@@ -1,944 +1,944 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for various magic functions.
2 """Tests for various magic functions.
3
3
4 Needs to be run by nose (to make ipython session available).
4 Needs to be run by nose (to make ipython session available).
5 """
5 """
6 from __future__ import absolute_import
6 from __future__ import absolute_import
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Imports
9 # Imports
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 import io
12 import io
13 import os
13 import os
14 import sys
14 import sys
15 from unittest import TestCase
15 from unittest import TestCase
16
16
17 try:
17 try:
18 from importlib import invalidate_caches # Required from Python 3.3
18 from importlib import invalidate_caches # Required from Python 3.3
19 except ImportError:
19 except ImportError:
20 def invalidate_caches():
20 def invalidate_caches():
21 pass
21 pass
22
22
23 import nose.tools as nt
23 import nose.tools as nt
24
24
25 from IPython.core import magic
25 from IPython.core import magic
26 from IPython.core.magic import (Magics, magics_class, line_magic,
26 from IPython.core.magic import (Magics, magics_class, line_magic,
27 cell_magic, line_cell_magic,
27 cell_magic, line_cell_magic,
28 register_line_magic, register_cell_magic,
28 register_line_magic, register_cell_magic,
29 register_line_cell_magic)
29 register_line_cell_magic)
30 from IPython.core.magics import execution, script, code
30 from IPython.core.magics import execution, script, code
31 from IPython.nbformat.v3.tests.nbexamples import nb0
31 from IPython.nbformat.v3.tests.nbexamples import nb0
32 from IPython.nbformat import current
32 from IPython.nbformat import current
33 from IPython.testing import decorators as dec
33 from IPython.testing import decorators as dec
34 from IPython.testing import tools as tt
34 from IPython.testing import tools as tt
35 from IPython.utils import py3compat
35 from IPython.utils import py3compat
36 from IPython.utils.io import capture_output
36 from IPython.utils.io import capture_output
37 from IPython.utils.tempdir import TemporaryDirectory
37 from IPython.utils.tempdir import TemporaryDirectory
38 from IPython.utils.process import find_cmd
38 from IPython.utils.process import find_cmd
39
39
40 if py3compat.PY3:
40 if py3compat.PY3:
41 from io import StringIO
41 from io import StringIO
42 else:
42 else:
43 from StringIO import StringIO
43 from StringIO import StringIO
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # Test functions begin
46 # Test functions begin
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 @magic.magics_class
49 @magic.magics_class
50 class DummyMagics(magic.Magics): pass
50 class DummyMagics(magic.Magics): pass
51
51
52 def test_extract_code_ranges():
52 def test_extract_code_ranges():
53 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
53 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
54 expected = [(0, 1),
54 expected = [(0, 1),
55 (2, 3),
55 (2, 3),
56 (4, 6),
56 (4, 6),
57 (6, 9),
57 (6, 9),
58 (9, 14),
58 (9, 14),
59 (16, None),
59 (16, None),
60 (None, 9),
60 (None, 9),
61 (9, None),
61 (9, None),
62 (None, 13),
62 (None, 13),
63 (None, None)]
63 (None, None)]
64 actual = list(code.extract_code_ranges(instr))
64 actual = list(code.extract_code_ranges(instr))
65 nt.assert_equal(actual, expected)
65 nt.assert_equal(actual, expected)
66
66
67 def test_extract_symbols():
67 def test_extract_symbols():
68 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
68 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
69 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
69 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
70 expected = [([], ['a']),
70 expected = [([], ['a']),
71 (["def b():\n return 42\n"], []),
71 (["def b():\n return 42\n"], []),
72 (["class A: pass\n"], []),
72 (["class A: pass\n"], []),
73 (["class A: pass\n", "def b():\n return 42\n"], []),
73 (["class A: pass\n", "def b():\n return 42\n"], []),
74 (["class A: pass\n"], ['a']),
74 (["class A: pass\n"], ['a']),
75 ([], ['z'])]
75 ([], ['z'])]
76 for symbols, exp in zip(symbols_args, expected):
76 for symbols, exp in zip(symbols_args, expected):
77 nt.assert_equal(code.extract_symbols(source, symbols), exp)
77 nt.assert_equal(code.extract_symbols(source, symbols), exp)
78
78
79
79
80 def test_extract_symbols_raises_exception_with_non_python_code():
80 def test_extract_symbols_raises_exception_with_non_python_code():
81 source = ("=begin A Ruby program :)=end\n"
81 source = ("=begin A Ruby program :)=end\n"
82 "def hello\n"
82 "def hello\n"
83 "puts 'Hello world'\n"
83 "puts 'Hello world'\n"
84 "end")
84 "end")
85 with nt.assert_raises(SyntaxError):
85 with nt.assert_raises(SyntaxError):
86 code.extract_symbols(source, "hello")
86 code.extract_symbols(source, "hello")
87
87
88 def test_config():
88 def test_config():
89 """ test that config magic does not raise
89 """ test that config magic does not raise
90 can happen if Configurable init is moved too early into
90 can happen if Configurable init is moved too early into
91 Magics.__init__ as then a Config object will be registerd as a
91 Magics.__init__ as then a Config object will be registerd as a
92 magic.
92 magic.
93 """
93 """
94 ## should not raise.
94 ## should not raise.
95 _ip.magic('config')
95 _ip.magic('config')
96
96
97 def test_rehashx():
97 def test_rehashx():
98 # clear up everything
98 # clear up everything
99 _ip = get_ipython()
99 _ip = get_ipython()
100 _ip.alias_manager.clear_aliases()
100 _ip.alias_manager.clear_aliases()
101 del _ip.db['syscmdlist']
101 del _ip.db['syscmdlist']
102
102
103 _ip.magic('rehashx')
103 _ip.magic('rehashx')
104 # Practically ALL ipython development systems will have more than 10 aliases
104 # Practically ALL ipython development systems will have more than 10 aliases
105
105
106 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
106 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
107 for name, cmd in _ip.alias_manager.aliases:
107 for name, cmd in _ip.alias_manager.aliases:
108 # we must strip dots from alias names
108 # we must strip dots from alias names
109 nt.assert_not_in('.', name)
109 nt.assert_not_in('.', name)
110
110
111 # rehashx must fill up syscmdlist
111 # rehashx must fill up syscmdlist
112 scoms = _ip.db['syscmdlist']
112 scoms = _ip.db['syscmdlist']
113 nt.assert_true(len(scoms) > 10)
113 nt.assert_true(len(scoms) > 10)
114
114
115
115
116 def test_magic_parse_options():
116 def test_magic_parse_options():
117 """Test that we don't mangle paths when parsing magic options."""
117 """Test that we don't mangle paths when parsing magic options."""
118 ip = get_ipython()
118 ip = get_ipython()
119 path = 'c:\\x'
119 path = 'c:\\x'
120 m = DummyMagics(ip)
120 m = DummyMagics(ip)
121 opts = m.parse_options('-f %s' % path,'f:')[0]
121 opts = m.parse_options('-f %s' % path,'f:')[0]
122 # argv splitting is os-dependent
122 # argv splitting is os-dependent
123 if os.name == 'posix':
123 if os.name == 'posix':
124 expected = 'c:x'
124 expected = 'c:x'
125 else:
125 else:
126 expected = path
126 expected = path
127 nt.assert_equal(opts['f'], expected)
127 nt.assert_equal(opts['f'], expected)
128
128
129 def test_magic_parse_long_options():
129 def test_magic_parse_long_options():
130 """Magic.parse_options can handle --foo=bar long options"""
130 """Magic.parse_options can handle --foo=bar long options"""
131 ip = get_ipython()
131 ip = get_ipython()
132 m = DummyMagics(ip)
132 m = DummyMagics(ip)
133 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
133 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
134 nt.assert_in('foo', opts)
134 nt.assert_in('foo', opts)
135 nt.assert_in('bar', opts)
135 nt.assert_in('bar', opts)
136 nt.assert_equal(opts['bar'], "bubble")
136 nt.assert_equal(opts['bar'], "bubble")
137
137
138
138
139 @dec.skip_without('sqlite3')
139 @dec.skip_without('sqlite3')
140 def doctest_hist_f():
140 def doctest_hist_f():
141 """Test %hist -f with temporary filename.
141 """Test %hist -f with temporary filename.
142
142
143 In [9]: import tempfile
143 In [9]: import tempfile
144
144
145 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
145 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
146
146
147 In [11]: %hist -nl -f $tfile 3
147 In [11]: %hist -nl -f $tfile 3
148
148
149 In [13]: import os; os.unlink(tfile)
149 In [13]: import os; os.unlink(tfile)
150 """
150 """
151
151
152
152
153 @dec.skip_without('sqlite3')
153 @dec.skip_without('sqlite3')
154 def doctest_hist_r():
154 def doctest_hist_r():
155 """Test %hist -r
155 """Test %hist -r
156
156
157 XXX - This test is not recording the output correctly. For some reason, in
157 XXX - This test is not recording the output correctly. For some reason, in
158 testing mode the raw history isn't getting populated. No idea why.
158 testing mode the raw history isn't getting populated. No idea why.
159 Disabling the output checking for now, though at least we do run it.
159 Disabling the output checking for now, though at least we do run it.
160
160
161 In [1]: 'hist' in _ip.lsmagic()
161 In [1]: 'hist' in _ip.lsmagic()
162 Out[1]: True
162 Out[1]: True
163
163
164 In [2]: x=1
164 In [2]: x=1
165
165
166 In [3]: %hist -rl 2
166 In [3]: %hist -rl 2
167 x=1 # random
167 x=1 # random
168 %hist -r 2
168 %hist -r 2
169 """
169 """
170
170
171
171
172 @dec.skip_without('sqlite3')
172 @dec.skip_without('sqlite3')
173 def doctest_hist_op():
173 def doctest_hist_op():
174 """Test %hist -op
174 """Test %hist -op
175
175
176 In [1]: class b(float):
176 In [1]: class b(float):
177 ...: pass
177 ...: pass
178 ...:
178 ...:
179
179
180 In [2]: class s(object):
180 In [2]: class s(object):
181 ...: def __str__(self):
181 ...: def __str__(self):
182 ...: return 's'
182 ...: return 's'
183 ...:
183 ...:
184
184
185 In [3]:
185 In [3]:
186
186
187 In [4]: class r(b):
187 In [4]: class r(b):
188 ...: def __repr__(self):
188 ...: def __repr__(self):
189 ...: return 'r'
189 ...: return 'r'
190 ...:
190 ...:
191
191
192 In [5]: class sr(s,r): pass
192 In [5]: class sr(s,r): pass
193 ...:
193 ...:
194
194
195 In [6]:
195 In [6]:
196
196
197 In [7]: bb=b()
197 In [7]: bb=b()
198
198
199 In [8]: ss=s()
199 In [8]: ss=s()
200
200
201 In [9]: rr=r()
201 In [9]: rr=r()
202
202
203 In [10]: ssrr=sr()
203 In [10]: ssrr=sr()
204
204
205 In [11]: 4.5
205 In [11]: 4.5
206 Out[11]: 4.5
206 Out[11]: 4.5
207
207
208 In [12]: str(ss)
208 In [12]: str(ss)
209 Out[12]: 's'
209 Out[12]: 's'
210
210
211 In [13]:
211 In [13]:
212
212
213 In [14]: %hist -op
213 In [14]: %hist -op
214 >>> class b:
214 >>> class b:
215 ... pass
215 ... pass
216 ...
216 ...
217 >>> class s(b):
217 >>> class s(b):
218 ... def __str__(self):
218 ... def __str__(self):
219 ... return 's'
219 ... return 's'
220 ...
220 ...
221 >>>
221 >>>
222 >>> class r(b):
222 >>> class r(b):
223 ... def __repr__(self):
223 ... def __repr__(self):
224 ... return 'r'
224 ... return 'r'
225 ...
225 ...
226 >>> class sr(s,r): pass
226 >>> class sr(s,r): pass
227 >>>
227 >>>
228 >>> bb=b()
228 >>> bb=b()
229 >>> ss=s()
229 >>> ss=s()
230 >>> rr=r()
230 >>> rr=r()
231 >>> ssrr=sr()
231 >>> ssrr=sr()
232 >>> 4.5
232 >>> 4.5
233 4.5
233 4.5
234 >>> str(ss)
234 >>> str(ss)
235 's'
235 's'
236 >>>
236 >>>
237 """
237 """
238
238
239
239
240 @dec.skip_without('sqlite3')
240 @dec.skip_without('sqlite3')
241 def test_macro():
241 def test_macro():
242 ip = get_ipython()
242 ip = get_ipython()
243 ip.history_manager.reset() # Clear any existing history.
243 ip.history_manager.reset() # Clear any existing history.
244 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
244 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
245 for i, cmd in enumerate(cmds, start=1):
245 for i, cmd in enumerate(cmds, start=1):
246 ip.history_manager.store_inputs(i, cmd)
246 ip.history_manager.store_inputs(i, cmd)
247 ip.magic("macro test 1-3")
247 ip.magic("macro test 1-3")
248 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
248 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
249
249
250 # List macros
250 # List macros
251 nt.assert_in("test", ip.magic("macro"))
251 nt.assert_in("test", ip.magic("macro"))
252
252
253
253
254 @dec.skip_without('sqlite3')
254 @dec.skip_without('sqlite3')
255 def test_macro_run():
255 def test_macro_run():
256 """Test that we can run a multi-line macro successfully."""
256 """Test that we can run a multi-line macro successfully."""
257 ip = get_ipython()
257 ip = get_ipython()
258 ip.history_manager.reset()
258 ip.history_manager.reset()
259 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
259 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
260 "%macro test 2-3"]
260 "%macro test 2-3"]
261 for cmd in cmds:
261 for cmd in cmds:
262 ip.run_cell(cmd, store_history=True)
262 ip.run_cell(cmd, store_history=True)
263 nt.assert_equal(ip.user_ns["test"].value,
263 nt.assert_equal(ip.user_ns["test"].value,
264 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
264 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
265 with tt.AssertPrints("12"):
265 with tt.AssertPrints("12"):
266 ip.run_cell("test")
266 ip.run_cell("test")
267 with tt.AssertPrints("13"):
267 with tt.AssertPrints("13"):
268 ip.run_cell("test")
268 ip.run_cell("test")
269
269
270
270
271 def test_magic_magic():
271 def test_magic_magic():
272 """Test %magic"""
272 """Test %magic"""
273 ip = get_ipython()
273 ip = get_ipython()
274 with capture_output() as captured:
274 with capture_output() as captured:
275 ip.magic("magic")
275 ip.magic("magic")
276
276
277 stdout = captured.stdout
277 stdout = captured.stdout
278 nt.assert_in('%magic', stdout)
278 nt.assert_in('%magic', stdout)
279 nt.assert_in('IPython', stdout)
279 nt.assert_in('IPython', stdout)
280 nt.assert_in('Available', stdout)
280 nt.assert_in('Available', stdout)
281
281
282
282
283 @dec.skipif_not_numpy
283 @dec.skipif_not_numpy
284 def test_numpy_reset_array_undec():
284 def test_numpy_reset_array_undec():
285 "Test '%reset array' functionality"
285 "Test '%reset array' functionality"
286 _ip.ex('import numpy as np')
286 _ip.ex('import numpy as np')
287 _ip.ex('a = np.empty(2)')
287 _ip.ex('a = np.empty(2)')
288 nt.assert_in('a', _ip.user_ns)
288 nt.assert_in('a', _ip.user_ns)
289 _ip.magic('reset -f array')
289 _ip.magic('reset -f array')
290 nt.assert_not_in('a', _ip.user_ns)
290 nt.assert_not_in('a', _ip.user_ns)
291
291
292 def test_reset_out():
292 def test_reset_out():
293 "Test '%reset out' magic"
293 "Test '%reset out' magic"
294 _ip.run_cell("parrot = 'dead'", store_history=True)
294 _ip.run_cell("parrot = 'dead'", store_history=True)
295 # test '%reset -f out', make an Out prompt
295 # test '%reset -f out', make an Out prompt
296 _ip.run_cell("parrot", store_history=True)
296 _ip.run_cell("parrot", store_history=True)
297 nt.assert_true('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
297 nt.assert_true('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
298 _ip.magic('reset -f out')
298 _ip.magic('reset -f out')
299 nt.assert_false('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
299 nt.assert_false('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
300 nt.assert_equal(len(_ip.user_ns['Out']), 0)
300 nt.assert_equal(len(_ip.user_ns['Out']), 0)
301
301
302 def test_reset_in():
302 def test_reset_in():
303 "Test '%reset in' magic"
303 "Test '%reset in' magic"
304 # test '%reset -f in'
304 # test '%reset -f in'
305 _ip.run_cell("parrot", store_history=True)
305 _ip.run_cell("parrot", store_history=True)
306 nt.assert_true('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
306 nt.assert_true('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
307 _ip.magic('%reset -f in')
307 _ip.magic('%reset -f in')
308 nt.assert_false('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
308 nt.assert_false('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
309 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
309 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
310
310
311 def test_reset_dhist():
311 def test_reset_dhist():
312 "Test '%reset dhist' magic"
312 "Test '%reset dhist' magic"
313 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
313 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
314 _ip.magic('cd ' + os.path.dirname(nt.__file__))
314 _ip.magic('cd ' + os.path.dirname(nt.__file__))
315 _ip.magic('cd -')
315 _ip.magic('cd -')
316 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
316 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
317 _ip.magic('reset -f dhist')
317 _ip.magic('reset -f dhist')
318 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
318 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
319 _ip.run_cell("_dh = [d for d in tmp]") #restore
319 _ip.run_cell("_dh = [d for d in tmp]") #restore
320
320
321 def test_reset_in_length():
321 def test_reset_in_length():
322 "Test that '%reset in' preserves In[] length"
322 "Test that '%reset in' preserves In[] length"
323 _ip.run_cell("print 'foo'")
323 _ip.run_cell("print 'foo'")
324 _ip.run_cell("reset -f in")
324 _ip.run_cell("reset -f in")
325 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
325 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
326
326
327 def test_tb_syntaxerror():
327 def test_tb_syntaxerror():
328 """test %tb after a SyntaxError"""
328 """test %tb after a SyntaxError"""
329 ip = get_ipython()
329 ip = get_ipython()
330 ip.run_cell("for")
330 ip.run_cell("for")
331
331
332 # trap and validate stdout
332 # trap and validate stdout
333 save_stdout = sys.stdout
333 save_stdout = sys.stdout
334 try:
334 try:
335 sys.stdout = StringIO()
335 sys.stdout = StringIO()
336 ip.run_cell("%tb")
336 ip.run_cell("%tb")
337 out = sys.stdout.getvalue()
337 out = sys.stdout.getvalue()
338 finally:
338 finally:
339 sys.stdout = save_stdout
339 sys.stdout = save_stdout
340 # trim output, and only check the last line
340 # trim output, and only check the last line
341 last_line = out.rstrip().splitlines()[-1].strip()
341 last_line = out.rstrip().splitlines()[-1].strip()
342 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
342 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
343
343
344
344
345 def test_time():
345 def test_time():
346 ip = get_ipython()
346 ip = get_ipython()
347
347
348 with tt.AssertPrints("Wall time: "):
348 with tt.AssertPrints("Wall time: "):
349 ip.run_cell("%time None")
349 ip.run_cell("%time None")
350
350
351 ip.run_cell("def f(kmjy):\n"
351 ip.run_cell("def f(kmjy):\n"
352 " %time print (2*kmjy)")
352 " %time print (2*kmjy)")
353
353
354 with tt.AssertPrints("Wall time: "):
354 with tt.AssertPrints("Wall time: "):
355 with tt.AssertPrints("hihi", suppress=False):
355 with tt.AssertPrints("hihi", suppress=False):
356 ip.run_cell("f('hi')")
356 ip.run_cell("f('hi')")
357
357
358
358
359 @dec.skip_win32
359 @dec.skip_win32
360 def test_time2():
360 def test_time2():
361 ip = get_ipython()
361 ip = get_ipython()
362
362
363 with tt.AssertPrints("CPU times: user "):
363 with tt.AssertPrints("CPU times: user "):
364 ip.run_cell("%time None")
364 ip.run_cell("%time None")
365
365
366 def test_time3():
366 def test_time3():
367 """Erroneous magic function calls, issue gh-3334"""
367 """Erroneous magic function calls, issue gh-3334"""
368 ip = get_ipython()
368 ip = get_ipython()
369 ip.user_ns.pop('run', None)
369 ip.user_ns.pop('run', None)
370
370
371 with tt.AssertNotPrints("not found", channel='stderr'):
371 with tt.AssertNotPrints("not found", channel='stderr'):
372 ip.run_cell("%%time\n"
372 ip.run_cell("%%time\n"
373 "run = 0\n"
373 "run = 0\n"
374 "run += 1")
374 "run += 1")
375
375
376 def test_doctest_mode():
376 def test_doctest_mode():
377 "Toggle doctest_mode twice, it should be a no-op and run without error"
377 "Toggle doctest_mode twice, it should be a no-op and run without error"
378 _ip.magic('doctest_mode')
378 _ip.magic('doctest_mode')
379 _ip.magic('doctest_mode')
379 _ip.magic('doctest_mode')
380
380
381
381
382 def test_parse_options():
382 def test_parse_options():
383 """Tests for basic options parsing in magics."""
383 """Tests for basic options parsing in magics."""
384 # These are only the most minimal of tests, more should be added later. At
384 # These are only the most minimal of tests, more should be added later. At
385 # the very least we check that basic text/unicode calls work OK.
385 # the very least we check that basic text/unicode calls work OK.
386 m = DummyMagics(_ip)
386 m = DummyMagics(_ip)
387 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
387 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
388 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
388 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
389
389
390
390
391 def test_dirops():
391 def test_dirops():
392 """Test various directory handling operations."""
392 """Test various directory handling operations."""
393 # curpath = lambda :os.path.splitdrive(os.getcwdu())[1].replace('\\','/')
393 # curpath = lambda :os.path.splitdrive(py3compat.getcwd())[1].replace('\\','/')
394 curpath = os.getcwdu
394 curpath = py3compat.getcwd
395 startdir = os.getcwdu()
395 startdir = py3compat.getcwd()
396 ipdir = os.path.realpath(_ip.ipython_dir)
396 ipdir = os.path.realpath(_ip.ipython_dir)
397 try:
397 try:
398 _ip.magic('cd "%s"' % ipdir)
398 _ip.magic('cd "%s"' % ipdir)
399 nt.assert_equal(curpath(), ipdir)
399 nt.assert_equal(curpath(), ipdir)
400 _ip.magic('cd -')
400 _ip.magic('cd -')
401 nt.assert_equal(curpath(), startdir)
401 nt.assert_equal(curpath(), startdir)
402 _ip.magic('pushd "%s"' % ipdir)
402 _ip.magic('pushd "%s"' % ipdir)
403 nt.assert_equal(curpath(), ipdir)
403 nt.assert_equal(curpath(), ipdir)
404 _ip.magic('popd')
404 _ip.magic('popd')
405 nt.assert_equal(curpath(), startdir)
405 nt.assert_equal(curpath(), startdir)
406 finally:
406 finally:
407 os.chdir(startdir)
407 os.chdir(startdir)
408
408
409
409
410 def test_xmode():
410 def test_xmode():
411 # Calling xmode three times should be a no-op
411 # Calling xmode three times should be a no-op
412 xmode = _ip.InteractiveTB.mode
412 xmode = _ip.InteractiveTB.mode
413 for i in range(3):
413 for i in range(3):
414 _ip.magic("xmode")
414 _ip.magic("xmode")
415 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
415 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
416
416
417 def test_reset_hard():
417 def test_reset_hard():
418 monitor = []
418 monitor = []
419 class A(object):
419 class A(object):
420 def __del__(self):
420 def __del__(self):
421 monitor.append(1)
421 monitor.append(1)
422 def __repr__(self):
422 def __repr__(self):
423 return "<A instance>"
423 return "<A instance>"
424
424
425 _ip.user_ns["a"] = A()
425 _ip.user_ns["a"] = A()
426 _ip.run_cell("a")
426 _ip.run_cell("a")
427
427
428 nt.assert_equal(monitor, [])
428 nt.assert_equal(monitor, [])
429 _ip.magic("reset -f")
429 _ip.magic("reset -f")
430 nt.assert_equal(monitor, [1])
430 nt.assert_equal(monitor, [1])
431
431
432 class TestXdel(tt.TempFileMixin):
432 class TestXdel(tt.TempFileMixin):
433 def test_xdel(self):
433 def test_xdel(self):
434 """Test that references from %run are cleared by xdel."""
434 """Test that references from %run are cleared by xdel."""
435 src = ("class A(object):\n"
435 src = ("class A(object):\n"
436 " monitor = []\n"
436 " monitor = []\n"
437 " def __del__(self):\n"
437 " def __del__(self):\n"
438 " self.monitor.append(1)\n"
438 " self.monitor.append(1)\n"
439 "a = A()\n")
439 "a = A()\n")
440 self.mktmp(src)
440 self.mktmp(src)
441 # %run creates some hidden references...
441 # %run creates some hidden references...
442 _ip.magic("run %s" % self.fname)
442 _ip.magic("run %s" % self.fname)
443 # ... as does the displayhook.
443 # ... as does the displayhook.
444 _ip.run_cell("a")
444 _ip.run_cell("a")
445
445
446 monitor = _ip.user_ns["A"].monitor
446 monitor = _ip.user_ns["A"].monitor
447 nt.assert_equal(monitor, [])
447 nt.assert_equal(monitor, [])
448
448
449 _ip.magic("xdel a")
449 _ip.magic("xdel a")
450
450
451 # Check that a's __del__ method has been called.
451 # Check that a's __del__ method has been called.
452 nt.assert_equal(monitor, [1])
452 nt.assert_equal(monitor, [1])
453
453
454 def doctest_who():
454 def doctest_who():
455 """doctest for %who
455 """doctest for %who
456
456
457 In [1]: %reset -f
457 In [1]: %reset -f
458
458
459 In [2]: alpha = 123
459 In [2]: alpha = 123
460
460
461 In [3]: beta = 'beta'
461 In [3]: beta = 'beta'
462
462
463 In [4]: %who int
463 In [4]: %who int
464 alpha
464 alpha
465
465
466 In [5]: %who str
466 In [5]: %who str
467 beta
467 beta
468
468
469 In [6]: %whos
469 In [6]: %whos
470 Variable Type Data/Info
470 Variable Type Data/Info
471 ----------------------------
471 ----------------------------
472 alpha int 123
472 alpha int 123
473 beta str beta
473 beta str beta
474
474
475 In [7]: %who_ls
475 In [7]: %who_ls
476 Out[7]: ['alpha', 'beta']
476 Out[7]: ['alpha', 'beta']
477 """
477 """
478
478
479 def test_whos():
479 def test_whos():
480 """Check that whos is protected against objects where repr() fails."""
480 """Check that whos is protected against objects where repr() fails."""
481 class A(object):
481 class A(object):
482 def __repr__(self):
482 def __repr__(self):
483 raise Exception()
483 raise Exception()
484 _ip.user_ns['a'] = A()
484 _ip.user_ns['a'] = A()
485 _ip.magic("whos")
485 _ip.magic("whos")
486
486
487 @py3compat.u_format
487 @py3compat.u_format
488 def doctest_precision():
488 def doctest_precision():
489 """doctest for %precision
489 """doctest for %precision
490
490
491 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
491 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
492
492
493 In [2]: %precision 5
493 In [2]: %precision 5
494 Out[2]: {u}'%.5f'
494 Out[2]: {u}'%.5f'
495
495
496 In [3]: f.float_format
496 In [3]: f.float_format
497 Out[3]: {u}'%.5f'
497 Out[3]: {u}'%.5f'
498
498
499 In [4]: %precision %e
499 In [4]: %precision %e
500 Out[4]: {u}'%e'
500 Out[4]: {u}'%e'
501
501
502 In [5]: f(3.1415927)
502 In [5]: f(3.1415927)
503 Out[5]: {u}'3.141593e+00'
503 Out[5]: {u}'3.141593e+00'
504 """
504 """
505
505
506 def test_psearch():
506 def test_psearch():
507 with tt.AssertPrints("dict.fromkeys"):
507 with tt.AssertPrints("dict.fromkeys"):
508 _ip.run_cell("dict.fr*?")
508 _ip.run_cell("dict.fr*?")
509
509
510 def test_timeit_shlex():
510 def test_timeit_shlex():
511 """test shlex issues with timeit (#1109)"""
511 """test shlex issues with timeit (#1109)"""
512 _ip.ex("def f(*a,**kw): pass")
512 _ip.ex("def f(*a,**kw): pass")
513 _ip.magic('timeit -n1 "this is a bug".count(" ")')
513 _ip.magic('timeit -n1 "this is a bug".count(" ")')
514 _ip.magic('timeit -r1 -n1 f(" ", 1)')
514 _ip.magic('timeit -r1 -n1 f(" ", 1)')
515 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
515 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
516 _ip.magic('timeit -r1 -n1 ("a " + "b")')
516 _ip.magic('timeit -r1 -n1 ("a " + "b")')
517 _ip.magic('timeit -r1 -n1 f("a " + "b")')
517 _ip.magic('timeit -r1 -n1 f("a " + "b")')
518 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
518 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
519
519
520
520
521 def test_timeit_arguments():
521 def test_timeit_arguments():
522 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
522 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
523 _ip.magic("timeit ('#')")
523 _ip.magic("timeit ('#')")
524
524
525
525
526 def test_timeit_special_syntax():
526 def test_timeit_special_syntax():
527 "Test %%timeit with IPython special syntax"
527 "Test %%timeit with IPython special syntax"
528 @register_line_magic
528 @register_line_magic
529 def lmagic(line):
529 def lmagic(line):
530 ip = get_ipython()
530 ip = get_ipython()
531 ip.user_ns['lmagic_out'] = line
531 ip.user_ns['lmagic_out'] = line
532
532
533 # line mode test
533 # line mode test
534 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
534 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
535 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
535 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
536 # cell mode test
536 # cell mode test
537 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
537 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
538 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
538 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
539
539
540 def test_timeit_return():
540 def test_timeit_return():
541 """
541 """
542 test wether timeit -o return object
542 test wether timeit -o return object
543 """
543 """
544
544
545 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
545 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
546 assert(res is not None)
546 assert(res is not None)
547
547
548 def test_timeit_quiet():
548 def test_timeit_quiet():
549 """
549 """
550 test quiet option of timeit magic
550 test quiet option of timeit magic
551 """
551 """
552 with tt.AssertNotPrints("loops"):
552 with tt.AssertNotPrints("loops"):
553 _ip.run_cell("%timeit -n1 -r1 -q 1")
553 _ip.run_cell("%timeit -n1 -r1 -q 1")
554
554
555 @dec.skipif(execution.profile is None)
555 @dec.skipif(execution.profile is None)
556 def test_prun_special_syntax():
556 def test_prun_special_syntax():
557 "Test %%prun with IPython special syntax"
557 "Test %%prun with IPython special syntax"
558 @register_line_magic
558 @register_line_magic
559 def lmagic(line):
559 def lmagic(line):
560 ip = get_ipython()
560 ip = get_ipython()
561 ip.user_ns['lmagic_out'] = line
561 ip.user_ns['lmagic_out'] = line
562
562
563 # line mode test
563 # line mode test
564 _ip.run_line_magic('prun', '-q %lmagic my line')
564 _ip.run_line_magic('prun', '-q %lmagic my line')
565 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
565 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
566 # cell mode test
566 # cell mode test
567 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
567 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
568 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
568 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
569
569
570 @dec.skipif(execution.profile is None)
570 @dec.skipif(execution.profile is None)
571 def test_prun_quotes():
571 def test_prun_quotes():
572 "Test that prun does not clobber string escapes (GH #1302)"
572 "Test that prun does not clobber string escapes (GH #1302)"
573 _ip.magic(r"prun -q x = '\t'")
573 _ip.magic(r"prun -q x = '\t'")
574 nt.assert_equal(_ip.user_ns['x'], '\t')
574 nt.assert_equal(_ip.user_ns['x'], '\t')
575
575
576 def test_extension():
576 def test_extension():
577 tmpdir = TemporaryDirectory()
577 tmpdir = TemporaryDirectory()
578 orig_ipython_dir = _ip.ipython_dir
578 orig_ipython_dir = _ip.ipython_dir
579 try:
579 try:
580 _ip.ipython_dir = tmpdir.name
580 _ip.ipython_dir = tmpdir.name
581 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
581 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
582 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
582 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
583 _ip.magic("install_ext %s" % url)
583 _ip.magic("install_ext %s" % url)
584 _ip.user_ns.pop('arq', None)
584 _ip.user_ns.pop('arq', None)
585 invalidate_caches() # Clear import caches
585 invalidate_caches() # Clear import caches
586 _ip.magic("load_ext daft_extension")
586 _ip.magic("load_ext daft_extension")
587 nt.assert_equal(_ip.user_ns['arq'], 185)
587 nt.assert_equal(_ip.user_ns['arq'], 185)
588 _ip.magic("unload_ext daft_extension")
588 _ip.magic("unload_ext daft_extension")
589 assert 'arq' not in _ip.user_ns
589 assert 'arq' not in _ip.user_ns
590 finally:
590 finally:
591 _ip.ipython_dir = orig_ipython_dir
591 _ip.ipython_dir = orig_ipython_dir
592 tmpdir.cleanup()
592 tmpdir.cleanup()
593
593
594 def test_notebook_export_json():
594 def test_notebook_export_json():
595 with TemporaryDirectory() as td:
595 with TemporaryDirectory() as td:
596 outfile = os.path.join(td, "nb.ipynb")
596 outfile = os.path.join(td, "nb.ipynb")
597 _ip.ex(py3compat.u_format(u"u = {u}'héllo'"))
597 _ip.ex(py3compat.u_format(u"u = {u}'héllo'"))
598 _ip.magic("notebook -e %s" % outfile)
598 _ip.magic("notebook -e %s" % outfile)
599
599
600 def test_notebook_export_py():
600 def test_notebook_export_py():
601 with TemporaryDirectory() as td:
601 with TemporaryDirectory() as td:
602 outfile = os.path.join(td, "nb.py")
602 outfile = os.path.join(td, "nb.py")
603 _ip.ex(py3compat.u_format(u"u = {u}'héllo'"))
603 _ip.ex(py3compat.u_format(u"u = {u}'héllo'"))
604 _ip.magic("notebook -e %s" % outfile)
604 _ip.magic("notebook -e %s" % outfile)
605
605
606 def test_notebook_reformat_py():
606 def test_notebook_reformat_py():
607 with TemporaryDirectory() as td:
607 with TemporaryDirectory() as td:
608 infile = os.path.join(td, "nb.ipynb")
608 infile = os.path.join(td, "nb.ipynb")
609 with io.open(infile, 'w', encoding='utf-8') as f:
609 with io.open(infile, 'w', encoding='utf-8') as f:
610 current.write(nb0, f, 'json')
610 current.write(nb0, f, 'json')
611
611
612 _ip.ex(py3compat.u_format(u"u = {u}'héllo'"))
612 _ip.ex(py3compat.u_format(u"u = {u}'héllo'"))
613 _ip.magic("notebook -f py %s" % infile)
613 _ip.magic("notebook -f py %s" % infile)
614
614
615 def test_notebook_reformat_json():
615 def test_notebook_reformat_json():
616 with TemporaryDirectory() as td:
616 with TemporaryDirectory() as td:
617 infile = os.path.join(td, "nb.py")
617 infile = os.path.join(td, "nb.py")
618 with io.open(infile, 'w', encoding='utf-8') as f:
618 with io.open(infile, 'w', encoding='utf-8') as f:
619 current.write(nb0, f, 'py')
619 current.write(nb0, f, 'py')
620
620
621 _ip.ex(py3compat.u_format(u"u = {u}'héllo'"))
621 _ip.ex(py3compat.u_format(u"u = {u}'héllo'"))
622 _ip.magic("notebook -f ipynb %s" % infile)
622 _ip.magic("notebook -f ipynb %s" % infile)
623 _ip.magic("notebook -f json %s" % infile)
623 _ip.magic("notebook -f json %s" % infile)
624
624
625 def test_env():
625 def test_env():
626 env = _ip.magic("env")
626 env = _ip.magic("env")
627 assert isinstance(env, dict), type(env)
627 assert isinstance(env, dict), type(env)
628
628
629
629
630 class CellMagicTestCase(TestCase):
630 class CellMagicTestCase(TestCase):
631
631
632 def check_ident(self, magic):
632 def check_ident(self, magic):
633 # Manually called, we get the result
633 # Manually called, we get the result
634 out = _ip.run_cell_magic(magic, 'a', 'b')
634 out = _ip.run_cell_magic(magic, 'a', 'b')
635 nt.assert_equal(out, ('a','b'))
635 nt.assert_equal(out, ('a','b'))
636 # Via run_cell, it goes into the user's namespace via displayhook
636 # Via run_cell, it goes into the user's namespace via displayhook
637 _ip.run_cell('%%' + magic +' c\nd')
637 _ip.run_cell('%%' + magic +' c\nd')
638 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
638 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
639
639
640 def test_cell_magic_func_deco(self):
640 def test_cell_magic_func_deco(self):
641 "Cell magic using simple decorator"
641 "Cell magic using simple decorator"
642 @register_cell_magic
642 @register_cell_magic
643 def cellm(line, cell):
643 def cellm(line, cell):
644 return line, cell
644 return line, cell
645
645
646 self.check_ident('cellm')
646 self.check_ident('cellm')
647
647
648 def test_cell_magic_reg(self):
648 def test_cell_magic_reg(self):
649 "Cell magic manually registered"
649 "Cell magic manually registered"
650 def cellm(line, cell):
650 def cellm(line, cell):
651 return line, cell
651 return line, cell
652
652
653 _ip.register_magic_function(cellm, 'cell', 'cellm2')
653 _ip.register_magic_function(cellm, 'cell', 'cellm2')
654 self.check_ident('cellm2')
654 self.check_ident('cellm2')
655
655
656 def test_cell_magic_class(self):
656 def test_cell_magic_class(self):
657 "Cell magics declared via a class"
657 "Cell magics declared via a class"
658 @magics_class
658 @magics_class
659 class MyMagics(Magics):
659 class MyMagics(Magics):
660
660
661 @cell_magic
661 @cell_magic
662 def cellm3(self, line, cell):
662 def cellm3(self, line, cell):
663 return line, cell
663 return line, cell
664
664
665 _ip.register_magics(MyMagics)
665 _ip.register_magics(MyMagics)
666 self.check_ident('cellm3')
666 self.check_ident('cellm3')
667
667
668 def test_cell_magic_class2(self):
668 def test_cell_magic_class2(self):
669 "Cell magics declared via a class, #2"
669 "Cell magics declared via a class, #2"
670 @magics_class
670 @magics_class
671 class MyMagics2(Magics):
671 class MyMagics2(Magics):
672
672
673 @cell_magic('cellm4')
673 @cell_magic('cellm4')
674 def cellm33(self, line, cell):
674 def cellm33(self, line, cell):
675 return line, cell
675 return line, cell
676
676
677 _ip.register_magics(MyMagics2)
677 _ip.register_magics(MyMagics2)
678 self.check_ident('cellm4')
678 self.check_ident('cellm4')
679 # Check that nothing is registered as 'cellm33'
679 # Check that nothing is registered as 'cellm33'
680 c33 = _ip.find_cell_magic('cellm33')
680 c33 = _ip.find_cell_magic('cellm33')
681 nt.assert_equal(c33, None)
681 nt.assert_equal(c33, None)
682
682
683 def test_file():
683 def test_file():
684 """Basic %%file"""
684 """Basic %%file"""
685 ip = get_ipython()
685 ip = get_ipython()
686 with TemporaryDirectory() as td:
686 with TemporaryDirectory() as td:
687 fname = os.path.join(td, 'file1')
687 fname = os.path.join(td, 'file1')
688 ip.run_cell_magic("file", fname, u'\n'.join([
688 ip.run_cell_magic("file", fname, u'\n'.join([
689 'line1',
689 'line1',
690 'line2',
690 'line2',
691 ]))
691 ]))
692 with open(fname) as f:
692 with open(fname) as f:
693 s = f.read()
693 s = f.read()
694 nt.assert_in('line1\n', s)
694 nt.assert_in('line1\n', s)
695 nt.assert_in('line2', s)
695 nt.assert_in('line2', s)
696
696
697 def test_file_var_expand():
697 def test_file_var_expand():
698 """%%file $filename"""
698 """%%file $filename"""
699 ip = get_ipython()
699 ip = get_ipython()
700 with TemporaryDirectory() as td:
700 with TemporaryDirectory() as td:
701 fname = os.path.join(td, 'file1')
701 fname = os.path.join(td, 'file1')
702 ip.user_ns['filename'] = fname
702 ip.user_ns['filename'] = fname
703 ip.run_cell_magic("file", '$filename', u'\n'.join([
703 ip.run_cell_magic("file", '$filename', u'\n'.join([
704 'line1',
704 'line1',
705 'line2',
705 'line2',
706 ]))
706 ]))
707 with open(fname) as f:
707 with open(fname) as f:
708 s = f.read()
708 s = f.read()
709 nt.assert_in('line1\n', s)
709 nt.assert_in('line1\n', s)
710 nt.assert_in('line2', s)
710 nt.assert_in('line2', s)
711
711
712 def test_file_unicode():
712 def test_file_unicode():
713 """%%file with unicode cell"""
713 """%%file with unicode cell"""
714 ip = get_ipython()
714 ip = get_ipython()
715 with TemporaryDirectory() as td:
715 with TemporaryDirectory() as td:
716 fname = os.path.join(td, 'file1')
716 fname = os.path.join(td, 'file1')
717 ip.run_cell_magic("file", fname, u'\n'.join([
717 ip.run_cell_magic("file", fname, u'\n'.join([
718 u'liné1',
718 u'liné1',
719 u'liné2',
719 u'liné2',
720 ]))
720 ]))
721 with io.open(fname, encoding='utf-8') as f:
721 with io.open(fname, encoding='utf-8') as f:
722 s = f.read()
722 s = f.read()
723 nt.assert_in(u'liné1\n', s)
723 nt.assert_in(u'liné1\n', s)
724 nt.assert_in(u'liné2', s)
724 nt.assert_in(u'liné2', s)
725
725
726 def test_file_amend():
726 def test_file_amend():
727 """%%file -a amends files"""
727 """%%file -a amends files"""
728 ip = get_ipython()
728 ip = get_ipython()
729 with TemporaryDirectory() as td:
729 with TemporaryDirectory() as td:
730 fname = os.path.join(td, 'file2')
730 fname = os.path.join(td, 'file2')
731 ip.run_cell_magic("file", fname, u'\n'.join([
731 ip.run_cell_magic("file", fname, u'\n'.join([
732 'line1',
732 'line1',
733 'line2',
733 'line2',
734 ]))
734 ]))
735 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
735 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
736 'line3',
736 'line3',
737 'line4',
737 'line4',
738 ]))
738 ]))
739 with open(fname) as f:
739 with open(fname) as f:
740 s = f.read()
740 s = f.read()
741 nt.assert_in('line1\n', s)
741 nt.assert_in('line1\n', s)
742 nt.assert_in('line3\n', s)
742 nt.assert_in('line3\n', s)
743
743
744
744
745 def test_script_config():
745 def test_script_config():
746 ip = get_ipython()
746 ip = get_ipython()
747 ip.config.ScriptMagics.script_magics = ['whoda']
747 ip.config.ScriptMagics.script_magics = ['whoda']
748 sm = script.ScriptMagics(shell=ip)
748 sm = script.ScriptMagics(shell=ip)
749 nt.assert_in('whoda', sm.magics['cell'])
749 nt.assert_in('whoda', sm.magics['cell'])
750
750
751 @dec.skip_win32
751 @dec.skip_win32
752 def test_script_out():
752 def test_script_out():
753 ip = get_ipython()
753 ip = get_ipython()
754 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
754 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
755 nt.assert_equal(ip.user_ns['output'], 'hi\n')
755 nt.assert_equal(ip.user_ns['output'], 'hi\n')
756
756
757 @dec.skip_win32
757 @dec.skip_win32
758 def test_script_err():
758 def test_script_err():
759 ip = get_ipython()
759 ip = get_ipython()
760 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
760 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
761 nt.assert_equal(ip.user_ns['error'], 'hello\n')
761 nt.assert_equal(ip.user_ns['error'], 'hello\n')
762
762
763 @dec.skip_win32
763 @dec.skip_win32
764 def test_script_out_err():
764 def test_script_out_err():
765 ip = get_ipython()
765 ip = get_ipython()
766 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
766 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
767 nt.assert_equal(ip.user_ns['output'], 'hi\n')
767 nt.assert_equal(ip.user_ns['output'], 'hi\n')
768 nt.assert_equal(ip.user_ns['error'], 'hello\n')
768 nt.assert_equal(ip.user_ns['error'], 'hello\n')
769
769
770 @dec.skip_win32
770 @dec.skip_win32
771 def test_script_bg_out():
771 def test_script_bg_out():
772 ip = get_ipython()
772 ip = get_ipython()
773 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
773 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
774 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
774 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
775
775
776 @dec.skip_win32
776 @dec.skip_win32
777 def test_script_bg_err():
777 def test_script_bg_err():
778 ip = get_ipython()
778 ip = get_ipython()
779 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
779 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
780 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
780 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
781
781
782 @dec.skip_win32
782 @dec.skip_win32
783 def test_script_bg_out_err():
783 def test_script_bg_out_err():
784 ip = get_ipython()
784 ip = get_ipython()
785 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
785 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
786 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
786 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
787 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
787 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
788
788
789 def test_script_defaults():
789 def test_script_defaults():
790 ip = get_ipython()
790 ip = get_ipython()
791 for cmd in ['sh', 'bash', 'perl', 'ruby']:
791 for cmd in ['sh', 'bash', 'perl', 'ruby']:
792 try:
792 try:
793 find_cmd(cmd)
793 find_cmd(cmd)
794 except Exception:
794 except Exception:
795 pass
795 pass
796 else:
796 else:
797 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
797 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
798
798
799
799
800 @magics_class
800 @magics_class
801 class FooFoo(Magics):
801 class FooFoo(Magics):
802 """class with both %foo and %%foo magics"""
802 """class with both %foo and %%foo magics"""
803 @line_magic('foo')
803 @line_magic('foo')
804 def line_foo(self, line):
804 def line_foo(self, line):
805 "I am line foo"
805 "I am line foo"
806 pass
806 pass
807
807
808 @cell_magic("foo")
808 @cell_magic("foo")
809 def cell_foo(self, line, cell):
809 def cell_foo(self, line, cell):
810 "I am cell foo, not line foo"
810 "I am cell foo, not line foo"
811 pass
811 pass
812
812
813 def test_line_cell_info():
813 def test_line_cell_info():
814 """%%foo and %foo magics are distinguishable to inspect"""
814 """%%foo and %foo magics are distinguishable to inspect"""
815 ip = get_ipython()
815 ip = get_ipython()
816 ip.magics_manager.register(FooFoo)
816 ip.magics_manager.register(FooFoo)
817 oinfo = ip.object_inspect('foo')
817 oinfo = ip.object_inspect('foo')
818 nt.assert_true(oinfo['found'])
818 nt.assert_true(oinfo['found'])
819 nt.assert_true(oinfo['ismagic'])
819 nt.assert_true(oinfo['ismagic'])
820
820
821 oinfo = ip.object_inspect('%%foo')
821 oinfo = ip.object_inspect('%%foo')
822 nt.assert_true(oinfo['found'])
822 nt.assert_true(oinfo['found'])
823 nt.assert_true(oinfo['ismagic'])
823 nt.assert_true(oinfo['ismagic'])
824 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
824 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
825
825
826 oinfo = ip.object_inspect('%foo')
826 oinfo = ip.object_inspect('%foo')
827 nt.assert_true(oinfo['found'])
827 nt.assert_true(oinfo['found'])
828 nt.assert_true(oinfo['ismagic'])
828 nt.assert_true(oinfo['ismagic'])
829 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
829 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
830
830
831 def test_multiple_magics():
831 def test_multiple_magics():
832 ip = get_ipython()
832 ip = get_ipython()
833 foo1 = FooFoo(ip)
833 foo1 = FooFoo(ip)
834 foo2 = FooFoo(ip)
834 foo2 = FooFoo(ip)
835 mm = ip.magics_manager
835 mm = ip.magics_manager
836 mm.register(foo1)
836 mm.register(foo1)
837 nt.assert_true(mm.magics['line']['foo'].__self__ is foo1)
837 nt.assert_true(mm.magics['line']['foo'].__self__ is foo1)
838 mm.register(foo2)
838 mm.register(foo2)
839 nt.assert_true(mm.magics['line']['foo'].__self__ is foo2)
839 nt.assert_true(mm.magics['line']['foo'].__self__ is foo2)
840
840
841 def test_alias_magic():
841 def test_alias_magic():
842 """Test %alias_magic."""
842 """Test %alias_magic."""
843 ip = get_ipython()
843 ip = get_ipython()
844 mm = ip.magics_manager
844 mm = ip.magics_manager
845
845
846 # Basic operation: both cell and line magics are created, if possible.
846 # Basic operation: both cell and line magics are created, if possible.
847 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
847 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
848 nt.assert_in('timeit_alias', mm.magics['line'])
848 nt.assert_in('timeit_alias', mm.magics['line'])
849 nt.assert_in('timeit_alias', mm.magics['cell'])
849 nt.assert_in('timeit_alias', mm.magics['cell'])
850
850
851 # --cell is specified, line magic not created.
851 # --cell is specified, line magic not created.
852 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
852 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
853 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
853 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
854 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
854 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
855
855
856 # Test that line alias is created successfully.
856 # Test that line alias is created successfully.
857 ip.run_line_magic('alias_magic', '--line env_alias env')
857 ip.run_line_magic('alias_magic', '--line env_alias env')
858 nt.assert_equal(ip.run_line_magic('env', ''),
858 nt.assert_equal(ip.run_line_magic('env', ''),
859 ip.run_line_magic('env_alias', ''))
859 ip.run_line_magic('env_alias', ''))
860
860
861 def test_save():
861 def test_save():
862 """Test %save."""
862 """Test %save."""
863 ip = get_ipython()
863 ip = get_ipython()
864 ip.history_manager.reset() # Clear any existing history.
864 ip.history_manager.reset() # Clear any existing history.
865 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
865 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
866 for i, cmd in enumerate(cmds, start=1):
866 for i, cmd in enumerate(cmds, start=1):
867 ip.history_manager.store_inputs(i, cmd)
867 ip.history_manager.store_inputs(i, cmd)
868 with TemporaryDirectory() as tmpdir:
868 with TemporaryDirectory() as tmpdir:
869 file = os.path.join(tmpdir, "testsave.py")
869 file = os.path.join(tmpdir, "testsave.py")
870 ip.run_line_magic("save", "%s 1-10" % file)
870 ip.run_line_magic("save", "%s 1-10" % file)
871 with open(file) as f:
871 with open(file) as f:
872 content = f.read()
872 content = f.read()
873 nt.assert_equal(content.count(cmds[0]), 1)
873 nt.assert_equal(content.count(cmds[0]), 1)
874 nt.assert_in('coding: utf-8', content)
874 nt.assert_in('coding: utf-8', content)
875 ip.run_line_magic("save", "-a %s 1-10" % file)
875 ip.run_line_magic("save", "-a %s 1-10" % file)
876 with open(file) as f:
876 with open(file) as f:
877 content = f.read()
877 content = f.read()
878 nt.assert_equal(content.count(cmds[0]), 2)
878 nt.assert_equal(content.count(cmds[0]), 2)
879 nt.assert_in('coding: utf-8', content)
879 nt.assert_in('coding: utf-8', content)
880
880
881
881
882 def test_store():
882 def test_store():
883 """Test %store."""
883 """Test %store."""
884 ip = get_ipython()
884 ip = get_ipython()
885 ip.run_line_magic('load_ext', 'storemagic')
885 ip.run_line_magic('load_ext', 'storemagic')
886
886
887 # make sure the storage is empty
887 # make sure the storage is empty
888 ip.run_line_magic('store', '-z')
888 ip.run_line_magic('store', '-z')
889 ip.user_ns['var'] = 42
889 ip.user_ns['var'] = 42
890 ip.run_line_magic('store', 'var')
890 ip.run_line_magic('store', 'var')
891 ip.user_ns['var'] = 39
891 ip.user_ns['var'] = 39
892 ip.run_line_magic('store', '-r')
892 ip.run_line_magic('store', '-r')
893 nt.assert_equal(ip.user_ns['var'], 42)
893 nt.assert_equal(ip.user_ns['var'], 42)
894
894
895 ip.run_line_magic('store', '-d var')
895 ip.run_line_magic('store', '-d var')
896 ip.user_ns['var'] = 39
896 ip.user_ns['var'] = 39
897 ip.run_line_magic('store' , '-r')
897 ip.run_line_magic('store' , '-r')
898 nt.assert_equal(ip.user_ns['var'], 39)
898 nt.assert_equal(ip.user_ns['var'], 39)
899
899
900
900
901 def _run_edit_test(arg_s, exp_filename=None,
901 def _run_edit_test(arg_s, exp_filename=None,
902 exp_lineno=-1,
902 exp_lineno=-1,
903 exp_contents=None,
903 exp_contents=None,
904 exp_is_temp=None):
904 exp_is_temp=None):
905 ip = get_ipython()
905 ip = get_ipython()
906 M = code.CodeMagics(ip)
906 M = code.CodeMagics(ip)
907 last_call = ['','']
907 last_call = ['','']
908 opts,args = M.parse_options(arg_s,'prxn:')
908 opts,args = M.parse_options(arg_s,'prxn:')
909 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
909 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
910
910
911 if exp_filename is not None:
911 if exp_filename is not None:
912 nt.assert_equal(exp_filename, filename)
912 nt.assert_equal(exp_filename, filename)
913 if exp_contents is not None:
913 if exp_contents is not None:
914 with io.open(filename, 'r') as f:
914 with io.open(filename, 'r') as f:
915 contents = f.read()
915 contents = f.read()
916 nt.assert_equal(exp_contents, contents)
916 nt.assert_equal(exp_contents, contents)
917 if exp_lineno != -1:
917 if exp_lineno != -1:
918 nt.assert_equal(exp_lineno, lineno)
918 nt.assert_equal(exp_lineno, lineno)
919 if exp_is_temp is not None:
919 if exp_is_temp is not None:
920 nt.assert_equal(exp_is_temp, is_temp)
920 nt.assert_equal(exp_is_temp, is_temp)
921
921
922
922
923 def test_edit_interactive():
923 def test_edit_interactive():
924 """%edit on interactively defined objects"""
924 """%edit on interactively defined objects"""
925 ip = get_ipython()
925 ip = get_ipython()
926 n = ip.execution_count
926 n = ip.execution_count
927 ip.run_cell(u"def foo(): return 1", store_history=True)
927 ip.run_cell(u"def foo(): return 1", store_history=True)
928
928
929 try:
929 try:
930 _run_edit_test("foo")
930 _run_edit_test("foo")
931 except code.InteractivelyDefined as e:
931 except code.InteractivelyDefined as e:
932 nt.assert_equal(e.index, n)
932 nt.assert_equal(e.index, n)
933 else:
933 else:
934 raise AssertionError("Should have raised InteractivelyDefined")
934 raise AssertionError("Should have raised InteractivelyDefined")
935
935
936
936
937 def test_edit_cell():
937 def test_edit_cell():
938 """%edit [cell id]"""
938 """%edit [cell id]"""
939 ip = get_ipython()
939 ip = get_ipython()
940
940
941 ip.run_cell(u"def foo(): return 1", store_history=True)
941 ip.run_cell(u"def foo(): return 1", store_history=True)
942
942
943 # test
943 # test
944 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
944 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
@@ -1,111 +1,112 b''
1 # -*- coding: utf-8
1 # -*- coding: utf-8
2 """Tests for prompt generation."""
2 """Tests for prompt generation."""
3
3
4 import unittest
4 import unittest
5
5
6 import os
6 import os
7
7
8 from IPython.testing import tools as tt, decorators as dec
8 from IPython.testing import tools as tt, decorators as dec
9 from IPython.core.prompts import PromptManager, LazyEvaluate
9 from IPython.core.prompts import PromptManager, LazyEvaluate
10 from IPython.testing.globalipapp import get_ipython
10 from IPython.testing.globalipapp import get_ipython
11 from IPython.utils.tempdir import TemporaryDirectory
11 from IPython.utils.tempdir import TemporaryDirectory
12 from IPython.utils import py3compat
12 from IPython.utils.py3compat import unicode_type
13 from IPython.utils.py3compat import unicode_type
13
14
14 ip = get_ipython()
15 ip = get_ipython()
15
16
16
17
17 class PromptTests(unittest.TestCase):
18 class PromptTests(unittest.TestCase):
18 def setUp(self):
19 def setUp(self):
19 self.pm = PromptManager(shell=ip, config=ip.config)
20 self.pm = PromptManager(shell=ip, config=ip.config)
20
21
21 def test_multiline_prompt(self):
22 def test_multiline_prompt(self):
22 self.pm.in_template = "[In]\n>>>"
23 self.pm.in_template = "[In]\n>>>"
23 self.pm.render('in')
24 self.pm.render('in')
24 self.assertEqual(self.pm.width, 3)
25 self.assertEqual(self.pm.width, 3)
25 self.assertEqual(self.pm.txtwidth, 3)
26 self.assertEqual(self.pm.txtwidth, 3)
26
27
27 self.pm.in_template = '[In]\n'
28 self.pm.in_template = '[In]\n'
28 self.pm.render('in')
29 self.pm.render('in')
29 self.assertEqual(self.pm.width, 0)
30 self.assertEqual(self.pm.width, 0)
30 self.assertEqual(self.pm.txtwidth, 0)
31 self.assertEqual(self.pm.txtwidth, 0)
31
32
32 def test_translate_abbreviations(self):
33 def test_translate_abbreviations(self):
33 def do_translate(template):
34 def do_translate(template):
34 self.pm.in_template = template
35 self.pm.in_template = template
35 return self.pm.templates['in']
36 return self.pm.templates['in']
36
37
37 pairs = [(r'%n>', '{color.number}{count}{color.prompt}>'),
38 pairs = [(r'%n>', '{color.number}{count}{color.prompt}>'),
38 (r'\T', '{time}'),
39 (r'\T', '{time}'),
39 (r'\n', '\n')
40 (r'\n', '\n')
40 ]
41 ]
41
42
42 tt.check_pairs(do_translate, pairs)
43 tt.check_pairs(do_translate, pairs)
43
44
44 def test_user_ns(self):
45 def test_user_ns(self):
45 self.pm.color_scheme = 'NoColor'
46 self.pm.color_scheme = 'NoColor'
46 ip.ex("foo='bar'")
47 ip.ex("foo='bar'")
47 self.pm.in_template = "In [{foo}]"
48 self.pm.in_template = "In [{foo}]"
48 prompt = self.pm.render('in')
49 prompt = self.pm.render('in')
49 self.assertEqual(prompt, u'In [bar]')
50 self.assertEqual(prompt, u'In [bar]')
50
51
51 def test_builtins(self):
52 def test_builtins(self):
52 self.pm.color_scheme = 'NoColor'
53 self.pm.color_scheme = 'NoColor'
53 self.pm.in_template = "In [{int}]"
54 self.pm.in_template = "In [{int}]"
54 prompt = self.pm.render('in')
55 prompt = self.pm.render('in')
55 self.assertEqual(prompt, u"In [%r]" % int)
56 self.assertEqual(prompt, u"In [%r]" % int)
56
57
57 def test_undefined(self):
58 def test_undefined(self):
58 self.pm.color_scheme = 'NoColor'
59 self.pm.color_scheme = 'NoColor'
59 self.pm.in_template = "In [{foo_dne}]"
60 self.pm.in_template = "In [{foo_dne}]"
60 prompt = self.pm.render('in')
61 prompt = self.pm.render('in')
61 self.assertEqual(prompt, u"In [<ERROR: 'foo_dne' not found>]")
62 self.assertEqual(prompt, u"In [<ERROR: 'foo_dne' not found>]")
62
63
63 def test_render(self):
64 def test_render(self):
64 self.pm.in_template = r'\#>'
65 self.pm.in_template = r'\#>'
65 self.assertEqual(self.pm.render('in',color=False), '%d>' % ip.execution_count)
66 self.assertEqual(self.pm.render('in',color=False), '%d>' % ip.execution_count)
66
67
67 @dec.onlyif_unicode_paths
68 @dec.onlyif_unicode_paths
68 def test_render_unicode_cwd(self):
69 def test_render_unicode_cwd(self):
69 save = os.getcwdu()
70 save = py3compat.getcwd()
70 with TemporaryDirectory(u'ünicødé') as td:
71 with TemporaryDirectory(u'ünicødé') as td:
71 os.chdir(td)
72 os.chdir(td)
72 self.pm.in_template = r'\w [\#]'
73 self.pm.in_template = r'\w [\#]'
73 p = self.pm.render('in', color=False)
74 p = self.pm.render('in', color=False)
74 self.assertEqual(p, u"%s [%i]" % (os.getcwdu(), ip.execution_count))
75 self.assertEqual(p, u"%s [%i]" % (py3compat.getcwd(), ip.execution_count))
75 os.chdir(save)
76 os.chdir(save)
76
77
77 def test_lazy_eval_unicode(self):
78 def test_lazy_eval_unicode(self):
78 u = u'ünicødé'
79 u = u'ünicødé'
79 lz = LazyEvaluate(lambda : u)
80 lz = LazyEvaluate(lambda : u)
80 # str(lz) would fail
81 # str(lz) would fail
81 self.assertEqual(unicode_type(lz), u)
82 self.assertEqual(unicode_type(lz), u)
82 self.assertEqual(format(lz), u)
83 self.assertEqual(format(lz), u)
83
84
84 def test_lazy_eval_nonascii_bytes(self):
85 def test_lazy_eval_nonascii_bytes(self):
85 u = u'ünicødé'
86 u = u'ünicødé'
86 b = u.encode('utf8')
87 b = u.encode('utf8')
87 lz = LazyEvaluate(lambda : b)
88 lz = LazyEvaluate(lambda : b)
88 # unicode(lz) would fail
89 # unicode(lz) would fail
89 self.assertEqual(str(lz), str(b))
90 self.assertEqual(str(lz), str(b))
90 self.assertEqual(format(lz), str(b))
91 self.assertEqual(format(lz), str(b))
91
92
92 def test_lazy_eval_float(self):
93 def test_lazy_eval_float(self):
93 f = 0.503
94 f = 0.503
94 lz = LazyEvaluate(lambda : f)
95 lz = LazyEvaluate(lambda : f)
95
96
96 self.assertEqual(str(lz), str(f))
97 self.assertEqual(str(lz), str(f))
97 self.assertEqual(unicode_type(lz), unicode_type(f))
98 self.assertEqual(unicode_type(lz), unicode_type(f))
98 self.assertEqual(format(lz), str(f))
99 self.assertEqual(format(lz), str(f))
99 self.assertEqual(format(lz, '.1'), '0.5')
100 self.assertEqual(format(lz, '.1'), '0.5')
100
101
101 @dec.skip_win32
102 @dec.skip_win32
102 def test_cwd_x(self):
103 def test_cwd_x(self):
103 self.pm.in_template = r"\X0"
104 self.pm.in_template = r"\X0"
104 save = os.getcwdu()
105 save = py3compat.getcwd()
105 os.chdir(os.path.expanduser('~'))
106 os.chdir(os.path.expanduser('~'))
106 p = self.pm.render('in', color=False)
107 p = self.pm.render('in', color=False)
107 try:
108 try:
108 self.assertEqual(p, '~')
109 self.assertEqual(p, '~')
109 finally:
110 finally:
110 os.chdir(save)
111 os.chdir(save)
111
112
@@ -1,458 +1,458 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for code execution (%run and related), which is particularly tricky.
2 """Tests for code execution (%run and related), which is particularly tricky.
3
3
4 Because of how %run manages namespaces, and the fact that we are trying here to
4 Because of how %run manages namespaces, and the fact that we are trying here to
5 verify subtle object deletion and reference counting issues, the %run tests
5 verify subtle object deletion and reference counting issues, the %run tests
6 will be kept in this separate file. This makes it easier to aggregate in one
6 will be kept in this separate file. This makes it easier to aggregate in one
7 place the tricks needed to handle it; most other magics are much easier to test
7 place the tricks needed to handle it; most other magics are much easier to test
8 and we do so in a common test_magic file.
8 and we do so in a common test_magic file.
9 """
9 """
10 from __future__ import absolute_import
10 from __future__ import absolute_import
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 import functools
16 import functools
17 import os
17 import os
18 from os.path import join as pjoin
18 from os.path import join as pjoin
19 import random
19 import random
20 import sys
20 import sys
21 import tempfile
21 import tempfile
22 import textwrap
22 import textwrap
23 import unittest
23 import unittest
24
24
25 import nose.tools as nt
25 import nose.tools as nt
26 from nose import SkipTest
26 from nose import SkipTest
27
27
28 from IPython.testing import decorators as dec
28 from IPython.testing import decorators as dec
29 from IPython.testing import tools as tt
29 from IPython.testing import tools as tt
30 from IPython.utils import py3compat
30 from IPython.utils import py3compat
31 from IPython.utils.tempdir import TemporaryDirectory
31 from IPython.utils.tempdir import TemporaryDirectory
32 from IPython.core import debugger
32 from IPython.core import debugger
33
33
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35 # Test functions begin
35 # Test functions begin
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37
37
38 def doctest_refbug():
38 def doctest_refbug():
39 """Very nasty problem with references held by multiple runs of a script.
39 """Very nasty problem with references held by multiple runs of a script.
40 See: https://github.com/ipython/ipython/issues/141
40 See: https://github.com/ipython/ipython/issues/141
41
41
42 In [1]: _ip.clear_main_mod_cache()
42 In [1]: _ip.clear_main_mod_cache()
43 # random
43 # random
44
44
45 In [2]: %run refbug
45 In [2]: %run refbug
46
46
47 In [3]: call_f()
47 In [3]: call_f()
48 lowercased: hello
48 lowercased: hello
49
49
50 In [4]: %run refbug
50 In [4]: %run refbug
51
51
52 In [5]: call_f()
52 In [5]: call_f()
53 lowercased: hello
53 lowercased: hello
54 lowercased: hello
54 lowercased: hello
55 """
55 """
56
56
57
57
58 def doctest_run_builtins():
58 def doctest_run_builtins():
59 r"""Check that %run doesn't damage __builtins__.
59 r"""Check that %run doesn't damage __builtins__.
60
60
61 In [1]: import tempfile
61 In [1]: import tempfile
62
62
63 In [2]: bid1 = id(__builtins__)
63 In [2]: bid1 = id(__builtins__)
64
64
65 In [3]: fname = tempfile.mkstemp('.py')[1]
65 In [3]: fname = tempfile.mkstemp('.py')[1]
66
66
67 In [3]: f = open(fname,'w')
67 In [3]: f = open(fname,'w')
68
68
69 In [4]: dummy= f.write('pass\n')
69 In [4]: dummy= f.write('pass\n')
70
70
71 In [5]: f.flush()
71 In [5]: f.flush()
72
72
73 In [6]: t1 = type(__builtins__)
73 In [6]: t1 = type(__builtins__)
74
74
75 In [7]: %run $fname
75 In [7]: %run $fname
76
76
77 In [7]: f.close()
77 In [7]: f.close()
78
78
79 In [8]: bid2 = id(__builtins__)
79 In [8]: bid2 = id(__builtins__)
80
80
81 In [9]: t2 = type(__builtins__)
81 In [9]: t2 = type(__builtins__)
82
82
83 In [10]: t1 == t2
83 In [10]: t1 == t2
84 Out[10]: True
84 Out[10]: True
85
85
86 In [10]: bid1 == bid2
86 In [10]: bid1 == bid2
87 Out[10]: True
87 Out[10]: True
88
88
89 In [12]: try:
89 In [12]: try:
90 ....: os.unlink(fname)
90 ....: os.unlink(fname)
91 ....: except:
91 ....: except:
92 ....: pass
92 ....: pass
93 ....:
93 ....:
94 """
94 """
95
95
96
96
97 def doctest_run_option_parser():
97 def doctest_run_option_parser():
98 r"""Test option parser in %run.
98 r"""Test option parser in %run.
99
99
100 In [1]: %run print_argv.py
100 In [1]: %run print_argv.py
101 []
101 []
102
102
103 In [2]: %run print_argv.py print*.py
103 In [2]: %run print_argv.py print*.py
104 ['print_argv.py']
104 ['print_argv.py']
105
105
106 In [3]: %run -G print_argv.py print*.py
106 In [3]: %run -G print_argv.py print*.py
107 ['print*.py']
107 ['print*.py']
108
108
109 """
109 """
110
110
111
111
112 @dec.skip_win32
112 @dec.skip_win32
113 def doctest_run_option_parser_for_posix():
113 def doctest_run_option_parser_for_posix():
114 r"""Test option parser in %run (Linux/OSX specific).
114 r"""Test option parser in %run (Linux/OSX specific).
115
115
116 You need double quote to escape glob in POSIX systems:
116 You need double quote to escape glob in POSIX systems:
117
117
118 In [1]: %run print_argv.py print\\*.py
118 In [1]: %run print_argv.py print\\*.py
119 ['print*.py']
119 ['print*.py']
120
120
121 You can't use quote to escape glob in POSIX systems:
121 You can't use quote to escape glob in POSIX systems:
122
122
123 In [2]: %run print_argv.py 'print*.py'
123 In [2]: %run print_argv.py 'print*.py'
124 ['print_argv.py']
124 ['print_argv.py']
125
125
126 """
126 """
127
127
128
128
129 @dec.skip_if_not_win32
129 @dec.skip_if_not_win32
130 def doctest_run_option_parser_for_windows():
130 def doctest_run_option_parser_for_windows():
131 r"""Test option parser in %run (Windows specific).
131 r"""Test option parser in %run (Windows specific).
132
132
133 In Windows, you can't escape ``*` `by backslash:
133 In Windows, you can't escape ``*` `by backslash:
134
134
135 In [1]: %run print_argv.py print\\*.py
135 In [1]: %run print_argv.py print\\*.py
136 ['print\\*.py']
136 ['print\\*.py']
137
137
138 You can use quote to escape glob:
138 You can use quote to escape glob:
139
139
140 In [2]: %run print_argv.py 'print*.py'
140 In [2]: %run print_argv.py 'print*.py'
141 ['print*.py']
141 ['print*.py']
142
142
143 """
143 """
144
144
145
145
146 @py3compat.doctest_refactor_print
146 @py3compat.doctest_refactor_print
147 def doctest_reset_del():
147 def doctest_reset_del():
148 """Test that resetting doesn't cause errors in __del__ methods.
148 """Test that resetting doesn't cause errors in __del__ methods.
149
149
150 In [2]: class A(object):
150 In [2]: class A(object):
151 ...: def __del__(self):
151 ...: def __del__(self):
152 ...: print str("Hi")
152 ...: print str("Hi")
153 ...:
153 ...:
154
154
155 In [3]: a = A()
155 In [3]: a = A()
156
156
157 In [4]: get_ipython().reset()
157 In [4]: get_ipython().reset()
158 Hi
158 Hi
159
159
160 In [5]: 1+1
160 In [5]: 1+1
161 Out[5]: 2
161 Out[5]: 2
162 """
162 """
163
163
164 # For some tests, it will be handy to organize them in a class with a common
164 # For some tests, it will be handy to organize them in a class with a common
165 # setup that makes a temp file
165 # setup that makes a temp file
166
166
167 class TestMagicRunPass(tt.TempFileMixin):
167 class TestMagicRunPass(tt.TempFileMixin):
168
168
169 def setup(self):
169 def setup(self):
170 """Make a valid python temp file."""
170 """Make a valid python temp file."""
171 self.mktmp('pass\n')
171 self.mktmp('pass\n')
172
172
173 def run_tmpfile(self):
173 def run_tmpfile(self):
174 _ip = get_ipython()
174 _ip = get_ipython()
175 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
175 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
176 # See below and ticket https://bugs.launchpad.net/bugs/366353
176 # See below and ticket https://bugs.launchpad.net/bugs/366353
177 _ip.magic('run %s' % self.fname)
177 _ip.magic('run %s' % self.fname)
178
178
179 def run_tmpfile_p(self):
179 def run_tmpfile_p(self):
180 _ip = get_ipython()
180 _ip = get_ipython()
181 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
181 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
182 # See below and ticket https://bugs.launchpad.net/bugs/366353
182 # See below and ticket https://bugs.launchpad.net/bugs/366353
183 _ip.magic('run -p %s' % self.fname)
183 _ip.magic('run -p %s' % self.fname)
184
184
185 def test_builtins_id(self):
185 def test_builtins_id(self):
186 """Check that %run doesn't damage __builtins__ """
186 """Check that %run doesn't damage __builtins__ """
187 _ip = get_ipython()
187 _ip = get_ipython()
188 # Test that the id of __builtins__ is not modified by %run
188 # Test that the id of __builtins__ is not modified by %run
189 bid1 = id(_ip.user_ns['__builtins__'])
189 bid1 = id(_ip.user_ns['__builtins__'])
190 self.run_tmpfile()
190 self.run_tmpfile()
191 bid2 = id(_ip.user_ns['__builtins__'])
191 bid2 = id(_ip.user_ns['__builtins__'])
192 nt.assert_equal(bid1, bid2)
192 nt.assert_equal(bid1, bid2)
193
193
194 def test_builtins_type(self):
194 def test_builtins_type(self):
195 """Check that the type of __builtins__ doesn't change with %run.
195 """Check that the type of __builtins__ doesn't change with %run.
196
196
197 However, the above could pass if __builtins__ was already modified to
197 However, the above could pass if __builtins__ was already modified to
198 be a dict (it should be a module) by a previous use of %run. So we
198 be a dict (it should be a module) by a previous use of %run. So we
199 also check explicitly that it really is a module:
199 also check explicitly that it really is a module:
200 """
200 """
201 _ip = get_ipython()
201 _ip = get_ipython()
202 self.run_tmpfile()
202 self.run_tmpfile()
203 nt.assert_equal(type(_ip.user_ns['__builtins__']),type(sys))
203 nt.assert_equal(type(_ip.user_ns['__builtins__']),type(sys))
204
204
205 def test_prompts(self):
205 def test_prompts(self):
206 """Test that prompts correctly generate after %run"""
206 """Test that prompts correctly generate after %run"""
207 self.run_tmpfile()
207 self.run_tmpfile()
208 _ip = get_ipython()
208 _ip = get_ipython()
209 p2 = _ip.prompt_manager.render('in2').strip()
209 p2 = _ip.prompt_manager.render('in2').strip()
210 nt.assert_equal(p2[:3], '...')
210 nt.assert_equal(p2[:3], '...')
211
211
212 def test_run_profile( self ):
212 def test_run_profile( self ):
213 """Test that the option -p, which invokes the profiler, do not
213 """Test that the option -p, which invokes the profiler, do not
214 crash by invoking execfile"""
214 crash by invoking execfile"""
215 _ip = get_ipython()
215 _ip = get_ipython()
216 self.run_tmpfile_p()
216 self.run_tmpfile_p()
217
217
218
218
219 class TestMagicRunSimple(tt.TempFileMixin):
219 class TestMagicRunSimple(tt.TempFileMixin):
220
220
221 def test_simpledef(self):
221 def test_simpledef(self):
222 """Test that simple class definitions work."""
222 """Test that simple class definitions work."""
223 src = ("class foo: pass\n"
223 src = ("class foo: pass\n"
224 "def f(): return foo()")
224 "def f(): return foo()")
225 self.mktmp(src)
225 self.mktmp(src)
226 _ip.magic('run %s' % self.fname)
226 _ip.magic('run %s' % self.fname)
227 _ip.run_cell('t = isinstance(f(), foo)')
227 _ip.run_cell('t = isinstance(f(), foo)')
228 nt.assert_true(_ip.user_ns['t'])
228 nt.assert_true(_ip.user_ns['t'])
229
229
230 def test_obj_del(self):
230 def test_obj_del(self):
231 """Test that object's __del__ methods are called on exit."""
231 """Test that object's __del__ methods are called on exit."""
232 if sys.platform == 'win32':
232 if sys.platform == 'win32':
233 try:
233 try:
234 import win32api
234 import win32api
235 except ImportError:
235 except ImportError:
236 raise SkipTest("Test requires pywin32")
236 raise SkipTest("Test requires pywin32")
237 src = ("class A(object):\n"
237 src = ("class A(object):\n"
238 " def __del__(self):\n"
238 " def __del__(self):\n"
239 " print 'object A deleted'\n"
239 " print 'object A deleted'\n"
240 "a = A()\n")
240 "a = A()\n")
241 self.mktmp(py3compat.doctest_refactor_print(src))
241 self.mktmp(py3compat.doctest_refactor_print(src))
242 if dec.module_not_available('sqlite3'):
242 if dec.module_not_available('sqlite3'):
243 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
243 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
244 else:
244 else:
245 err = None
245 err = None
246 tt.ipexec_validate(self.fname, 'object A deleted', err)
246 tt.ipexec_validate(self.fname, 'object A deleted', err)
247
247
248 def test_aggressive_namespace_cleanup(self):
248 def test_aggressive_namespace_cleanup(self):
249 """Test that namespace cleanup is not too aggressive GH-238
249 """Test that namespace cleanup is not too aggressive GH-238
250
250
251 Returning from another run magic deletes the namespace"""
251 Returning from another run magic deletes the namespace"""
252 # see ticket https://github.com/ipython/ipython/issues/238
252 # see ticket https://github.com/ipython/ipython/issues/238
253 class secondtmp(tt.TempFileMixin): pass
253 class secondtmp(tt.TempFileMixin): pass
254 empty = secondtmp()
254 empty = secondtmp()
255 empty.mktmp('')
255 empty.mktmp('')
256 # On Windows, the filename will have \users in it, so we need to use the
256 # On Windows, the filename will have \users in it, so we need to use the
257 # repr so that the \u becomes \\u.
257 # repr so that the \u becomes \\u.
258 src = ("ip = get_ipython()\n"
258 src = ("ip = get_ipython()\n"
259 "for i in range(5):\n"
259 "for i in range(5):\n"
260 " try:\n"
260 " try:\n"
261 " ip.magic(%r)\n"
261 " ip.magic(%r)\n"
262 " except NameError as e:\n"
262 " except NameError as e:\n"
263 " print(i)\n"
263 " print(i)\n"
264 " break\n" % ('run ' + empty.fname))
264 " break\n" % ('run ' + empty.fname))
265 self.mktmp(src)
265 self.mktmp(src)
266 _ip.magic('run %s' % self.fname)
266 _ip.magic('run %s' % self.fname)
267 _ip.run_cell('ip == get_ipython()')
267 _ip.run_cell('ip == get_ipython()')
268 nt.assert_equal(_ip.user_ns['i'], 4)
268 nt.assert_equal(_ip.user_ns['i'], 4)
269
269
270 def test_run_second(self):
270 def test_run_second(self):
271 """Test that running a second file doesn't clobber the first, gh-3547
271 """Test that running a second file doesn't clobber the first, gh-3547
272 """
272 """
273 self.mktmp("avar = 1\n"
273 self.mktmp("avar = 1\n"
274 "def afunc():\n"
274 "def afunc():\n"
275 " return avar\n")
275 " return avar\n")
276
276
277 empty = tt.TempFileMixin()
277 empty = tt.TempFileMixin()
278 empty.mktmp("")
278 empty.mktmp("")
279
279
280 _ip.magic('run %s' % self.fname)
280 _ip.magic('run %s' % self.fname)
281 _ip.magic('run %s' % empty.fname)
281 _ip.magic('run %s' % empty.fname)
282 nt.assert_equal(_ip.user_ns['afunc'](), 1)
282 nt.assert_equal(_ip.user_ns['afunc'](), 1)
283
283
284 @dec.skip_win32
284 @dec.skip_win32
285 def test_tclass(self):
285 def test_tclass(self):
286 mydir = os.path.dirname(__file__)
286 mydir = os.path.dirname(__file__)
287 tc = os.path.join(mydir, 'tclass')
287 tc = os.path.join(mydir, 'tclass')
288 src = ("%%run '%s' C-first\n"
288 src = ("%%run '%s' C-first\n"
289 "%%run '%s' C-second\n"
289 "%%run '%s' C-second\n"
290 "%%run '%s' C-third\n") % (tc, tc, tc)
290 "%%run '%s' C-third\n") % (tc, tc, tc)
291 self.mktmp(src, '.ipy')
291 self.mktmp(src, '.ipy')
292 out = """\
292 out = """\
293 ARGV 1-: ['C-first']
293 ARGV 1-: ['C-first']
294 ARGV 1-: ['C-second']
294 ARGV 1-: ['C-second']
295 tclass.py: deleting object: C-first
295 tclass.py: deleting object: C-first
296 ARGV 1-: ['C-third']
296 ARGV 1-: ['C-third']
297 tclass.py: deleting object: C-second
297 tclass.py: deleting object: C-second
298 tclass.py: deleting object: C-third
298 tclass.py: deleting object: C-third
299 """
299 """
300 if dec.module_not_available('sqlite3'):
300 if dec.module_not_available('sqlite3'):
301 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
301 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
302 else:
302 else:
303 err = None
303 err = None
304 tt.ipexec_validate(self.fname, out, err)
304 tt.ipexec_validate(self.fname, out, err)
305
305
306 def test_run_i_after_reset(self):
306 def test_run_i_after_reset(self):
307 """Check that %run -i still works after %reset (gh-693)"""
307 """Check that %run -i still works after %reset (gh-693)"""
308 src = "yy = zz\n"
308 src = "yy = zz\n"
309 self.mktmp(src)
309 self.mktmp(src)
310 _ip.run_cell("zz = 23")
310 _ip.run_cell("zz = 23")
311 _ip.magic('run -i %s' % self.fname)
311 _ip.magic('run -i %s' % self.fname)
312 nt.assert_equal(_ip.user_ns['yy'], 23)
312 nt.assert_equal(_ip.user_ns['yy'], 23)
313 _ip.magic('reset -f')
313 _ip.magic('reset -f')
314 _ip.run_cell("zz = 23")
314 _ip.run_cell("zz = 23")
315 _ip.magic('run -i %s' % self.fname)
315 _ip.magic('run -i %s' % self.fname)
316 nt.assert_equal(_ip.user_ns['yy'], 23)
316 nt.assert_equal(_ip.user_ns['yy'], 23)
317
317
318 def test_unicode(self):
318 def test_unicode(self):
319 """Check that files in odd encodings are accepted."""
319 """Check that files in odd encodings are accepted."""
320 mydir = os.path.dirname(__file__)
320 mydir = os.path.dirname(__file__)
321 na = os.path.join(mydir, 'nonascii.py')
321 na = os.path.join(mydir, 'nonascii.py')
322 _ip.magic('run "%s"' % na)
322 _ip.magic('run "%s"' % na)
323 nt.assert_equal(_ip.user_ns['u'], u'Ўт№Ф')
323 nt.assert_equal(_ip.user_ns['u'], u'Ўт№Ф')
324
324
325 def test_run_py_file_attribute(self):
325 def test_run_py_file_attribute(self):
326 """Test handling of `__file__` attribute in `%run <file>.py`."""
326 """Test handling of `__file__` attribute in `%run <file>.py`."""
327 src = "t = __file__\n"
327 src = "t = __file__\n"
328 self.mktmp(src)
328 self.mktmp(src)
329 _missing = object()
329 _missing = object()
330 file1 = _ip.user_ns.get('__file__', _missing)
330 file1 = _ip.user_ns.get('__file__', _missing)
331 _ip.magic('run %s' % self.fname)
331 _ip.magic('run %s' % self.fname)
332 file2 = _ip.user_ns.get('__file__', _missing)
332 file2 = _ip.user_ns.get('__file__', _missing)
333
333
334 # Check that __file__ was equal to the filename in the script's
334 # Check that __file__ was equal to the filename in the script's
335 # namespace.
335 # namespace.
336 nt.assert_equal(_ip.user_ns['t'], self.fname)
336 nt.assert_equal(_ip.user_ns['t'], self.fname)
337
337
338 # Check that __file__ was not leaked back into user_ns.
338 # Check that __file__ was not leaked back into user_ns.
339 nt.assert_equal(file1, file2)
339 nt.assert_equal(file1, file2)
340
340
341 def test_run_ipy_file_attribute(self):
341 def test_run_ipy_file_attribute(self):
342 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
342 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
343 src = "t = __file__\n"
343 src = "t = __file__\n"
344 self.mktmp(src, ext='.ipy')
344 self.mktmp(src, ext='.ipy')
345 _missing = object()
345 _missing = object()
346 file1 = _ip.user_ns.get('__file__', _missing)
346 file1 = _ip.user_ns.get('__file__', _missing)
347 _ip.magic('run %s' % self.fname)
347 _ip.magic('run %s' % self.fname)
348 file2 = _ip.user_ns.get('__file__', _missing)
348 file2 = _ip.user_ns.get('__file__', _missing)
349
349
350 # Check that __file__ was equal to the filename in the script's
350 # Check that __file__ was equal to the filename in the script's
351 # namespace.
351 # namespace.
352 nt.assert_equal(_ip.user_ns['t'], self.fname)
352 nt.assert_equal(_ip.user_ns['t'], self.fname)
353
353
354 # Check that __file__ was not leaked back into user_ns.
354 # Check that __file__ was not leaked back into user_ns.
355 nt.assert_equal(file1, file2)
355 nt.assert_equal(file1, file2)
356
356
357 def test_run_formatting(self):
357 def test_run_formatting(self):
358 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
358 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
359 src = "pass"
359 src = "pass"
360 self.mktmp(src)
360 self.mktmp(src)
361 _ip.magic('run -t -N 1 %s' % self.fname)
361 _ip.magic('run -t -N 1 %s' % self.fname)
362 _ip.magic('run -t -N 10 %s' % self.fname)
362 _ip.magic('run -t -N 10 %s' % self.fname)
363
363
364 def test_ignore_sys_exit(self):
364 def test_ignore_sys_exit(self):
365 """Test the -e option to ignore sys.exit()"""
365 """Test the -e option to ignore sys.exit()"""
366 src = "import sys; sys.exit(1)"
366 src = "import sys; sys.exit(1)"
367 self.mktmp(src)
367 self.mktmp(src)
368 with tt.AssertPrints('SystemExit'):
368 with tt.AssertPrints('SystemExit'):
369 _ip.magic('run %s' % self.fname)
369 _ip.magic('run %s' % self.fname)
370
370
371 with tt.AssertNotPrints('SystemExit'):
371 with tt.AssertNotPrints('SystemExit'):
372 _ip.magic('run -e %s' % self.fname)
372 _ip.magic('run -e %s' % self.fname)
373
373
374
374
375
375
376 class TestMagicRunWithPackage(unittest.TestCase):
376 class TestMagicRunWithPackage(unittest.TestCase):
377
377
378 def writefile(self, name, content):
378 def writefile(self, name, content):
379 path = os.path.join(self.tempdir.name, name)
379 path = os.path.join(self.tempdir.name, name)
380 d = os.path.dirname(path)
380 d = os.path.dirname(path)
381 if not os.path.isdir(d):
381 if not os.path.isdir(d):
382 os.makedirs(d)
382 os.makedirs(d)
383 with open(path, 'w') as f:
383 with open(path, 'w') as f:
384 f.write(textwrap.dedent(content))
384 f.write(textwrap.dedent(content))
385
385
386 def setUp(self):
386 def setUp(self):
387 self.package = package = 'tmp{0}'.format(repr(random.random())[2:])
387 self.package = package = 'tmp{0}'.format(repr(random.random())[2:])
388 """Temporary valid python package name."""
388 """Temporary valid python package name."""
389
389
390 self.value = int(random.random() * 10000)
390 self.value = int(random.random() * 10000)
391
391
392 self.tempdir = TemporaryDirectory()
392 self.tempdir = TemporaryDirectory()
393 self.__orig_cwd = os.getcwdu()
393 self.__orig_cwd = py3compat.getcwd()
394 sys.path.insert(0, self.tempdir.name)
394 sys.path.insert(0, self.tempdir.name)
395
395
396 self.writefile(os.path.join(package, '__init__.py'), '')
396 self.writefile(os.path.join(package, '__init__.py'), '')
397 self.writefile(os.path.join(package, 'sub.py'), """
397 self.writefile(os.path.join(package, 'sub.py'), """
398 x = {0!r}
398 x = {0!r}
399 """.format(self.value))
399 """.format(self.value))
400 self.writefile(os.path.join(package, 'relative.py'), """
400 self.writefile(os.path.join(package, 'relative.py'), """
401 from .sub import x
401 from .sub import x
402 """)
402 """)
403 self.writefile(os.path.join(package, 'absolute.py'), """
403 self.writefile(os.path.join(package, 'absolute.py'), """
404 from {0}.sub import x
404 from {0}.sub import x
405 """.format(package))
405 """.format(package))
406
406
407 def tearDown(self):
407 def tearDown(self):
408 os.chdir(self.__orig_cwd)
408 os.chdir(self.__orig_cwd)
409 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
409 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
410 self.tempdir.cleanup()
410 self.tempdir.cleanup()
411
411
412 def check_run_submodule(self, submodule, opts=''):
412 def check_run_submodule(self, submodule, opts=''):
413 _ip.user_ns.pop('x', None)
413 _ip.user_ns.pop('x', None)
414 _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
414 _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
415 self.assertEqual(_ip.user_ns['x'], self.value,
415 self.assertEqual(_ip.user_ns['x'], self.value,
416 'Variable `x` is not loaded from module `{0}`.'
416 'Variable `x` is not loaded from module `{0}`.'
417 .format(submodule))
417 .format(submodule))
418
418
419 def test_run_submodule_with_absolute_import(self):
419 def test_run_submodule_with_absolute_import(self):
420 self.check_run_submodule('absolute')
420 self.check_run_submodule('absolute')
421
421
422 def test_run_submodule_with_relative_import(self):
422 def test_run_submodule_with_relative_import(self):
423 """Run submodule that has a relative import statement (#2727)."""
423 """Run submodule that has a relative import statement (#2727)."""
424 self.check_run_submodule('relative')
424 self.check_run_submodule('relative')
425
425
426 def test_prun_submodule_with_absolute_import(self):
426 def test_prun_submodule_with_absolute_import(self):
427 self.check_run_submodule('absolute', '-p')
427 self.check_run_submodule('absolute', '-p')
428
428
429 def test_prun_submodule_with_relative_import(self):
429 def test_prun_submodule_with_relative_import(self):
430 self.check_run_submodule('relative', '-p')
430 self.check_run_submodule('relative', '-p')
431
431
432 def with_fake_debugger(func):
432 def with_fake_debugger(func):
433 @functools.wraps(func)
433 @functools.wraps(func)
434 def wrapper(*args, **kwds):
434 def wrapper(*args, **kwds):
435 with tt.monkeypatch(debugger.Pdb, 'run', staticmethod(eval)):
435 with tt.monkeypatch(debugger.Pdb, 'run', staticmethod(eval)):
436 return func(*args, **kwds)
436 return func(*args, **kwds)
437 return wrapper
437 return wrapper
438
438
439 @with_fake_debugger
439 @with_fake_debugger
440 def test_debug_run_submodule_with_absolute_import(self):
440 def test_debug_run_submodule_with_absolute_import(self):
441 self.check_run_submodule('absolute', '-d')
441 self.check_run_submodule('absolute', '-d')
442
442
443 @with_fake_debugger
443 @with_fake_debugger
444 def test_debug_run_submodule_with_relative_import(self):
444 def test_debug_run_submodule_with_relative_import(self):
445 self.check_run_submodule('relative', '-d')
445 self.check_run_submodule('relative', '-d')
446
446
447 def test_run__name__():
447 def test_run__name__():
448 with TemporaryDirectory() as td:
448 with TemporaryDirectory() as td:
449 path = pjoin(td, 'foo.py')
449 path = pjoin(td, 'foo.py')
450 with open(path, 'w') as f:
450 with open(path, 'w') as f:
451 f.write("q = __name__")
451 f.write("q = __name__")
452
452
453 _ip.user_ns.pop('q', None)
453 _ip.user_ns.pop('q', None)
454 _ip.magic('run {}'.format(path))
454 _ip.magic('run {}'.format(path))
455 nt.assert_equal(_ip.user_ns.pop('q'), '__main__')
455 nt.assert_equal(_ip.user_ns.pop('q'), '__main__')
456
456
457 _ip.magic('run -n {}'.format(path))
457 _ip.magic('run -n {}'.format(path))
458 nt.assert_equal(_ip.user_ns.pop('q'), 'foo')
458 nt.assert_equal(_ip.user_ns.pop('q'), 'foo')
@@ -1,1267 +1,1267 b''
1 #
1 #
2 # Copyright (c) 2010 Mikhail Gusarov
2 # Copyright (c) 2010 Mikhail Gusarov
3 #
3 #
4 # Permission is hereby granted, free of charge, to any person obtaining a copy
4 # Permission is hereby granted, free of charge, to any person obtaining a copy
5 # of this software and associated documentation files (the "Software"), to deal
5 # of this software and associated documentation files (the "Software"), to deal
6 # in the Software without restriction, including without limitation the rights
6 # in the Software without restriction, including without limitation the rights
7 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 # copies of the Software, and to permit persons to whom the Software is
8 # copies of the Software, and to permit persons to whom the Software is
9 # furnished to do so, subject to the following conditions:
9 # furnished to do so, subject to the following conditions:
10 #
10 #
11 # The above copyright notice and this permission notice shall be included in
11 # The above copyright notice and this permission notice shall be included in
12 # all copies or substantial portions of the Software.
12 # all copies or substantial portions of the Software.
13 #
13 #
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 # SOFTWARE.
20 # SOFTWARE.
21 #
21 #
22
22
23 """ path.py - An object representing a path to a file or directory.
23 """ path.py - An object representing a path to a file or directory.
24
24
25 Original author:
25 Original author:
26 Jason Orendorff <jason.orendorff\x40gmail\x2ecom>
26 Jason Orendorff <jason.orendorff\x40gmail\x2ecom>
27
27
28 Current maintainer:
28 Current maintainer:
29 Jason R. Coombs <jaraco@jaraco.com>
29 Jason R. Coombs <jaraco@jaraco.com>
30
30
31 Contributors:
31 Contributors:
32 Mikhail Gusarov <dottedmag@dottedmag.net>
32 Mikhail Gusarov <dottedmag@dottedmag.net>
33 Marc Abramowitz <marc@marc-abramowitz.com>
33 Marc Abramowitz <marc@marc-abramowitz.com>
34 Jason R. Coombs <jaraco@jaraco.com>
34 Jason R. Coombs <jaraco@jaraco.com>
35 Jason Chu <jchu@xentac.net>
35 Jason Chu <jchu@xentac.net>
36 Vojislav Stojkovic <vstojkovic@syntertainment.com>
36 Vojislav Stojkovic <vstojkovic@syntertainment.com>
37
37
38 Example::
38 Example::
39
39
40 from path import path
40 from path import path
41 d = path('/home/guido/bin')
41 d = path('/home/guido/bin')
42 for f in d.files('*.py'):
42 for f in d.files('*.py'):
43 f.chmod(0755)
43 f.chmod(0755)
44
44
45 path.py requires Python 2.5 or later.
45 path.py requires Python 2.5 or later.
46 """
46 """
47
47
48 from __future__ import with_statement
48 from __future__ import with_statement
49
49
50 import sys
50 import sys
51 import warnings
51 import warnings
52 import os
52 import os
53 import fnmatch
53 import fnmatch
54 import glob
54 import glob
55 import shutil
55 import shutil
56 import codecs
56 import codecs
57 import hashlib
57 import hashlib
58 import errno
58 import errno
59 import tempfile
59 import tempfile
60 import functools
60 import functools
61 import operator
61 import operator
62 import re
62 import re
63
63
64 try:
64 try:
65 import win32security
65 import win32security
66 except ImportError:
66 except ImportError:
67 pass
67 pass
68
68
69 try:
69 try:
70 import pwd
70 import pwd
71 except ImportError:
71 except ImportError:
72 pass
72 pass
73
73
74 ################################
74 ################################
75 # Monkey patchy python 3 support
75 # Monkey patchy python 3 support
76 try:
76 try:
77 basestring
77 basestring
78 except NameError:
78 except NameError:
79 basestring = str
79 basestring = str
80
80
81 try:
81 try:
82 unicode
82 unicode
83 except NameError:
83 except NameError:
84 unicode = str
84 unicode = str
85
85
86 try:
86 try:
87 os.getcwdu
87 getcwdu = os.getcwdu
88 except AttributeError:
88 except AttributeError:
89 os.getcwdu = os.getcwd
89 getcwdu = os.getcwd
90
90
91 if sys.version < '3':
91 if sys.version < '3':
92 def u(x):
92 def u(x):
93 return codecs.unicode_escape_decode(x)[0]
93 return codecs.unicode_escape_decode(x)[0]
94 else:
94 else:
95 def u(x):
95 def u(x):
96 return x
96 return x
97
97
98 o777 = 511
98 o777 = 511
99 o766 = 502
99 o766 = 502
100 o666 = 438
100 o666 = 438
101 o554 = 364
101 o554 = 364
102 ################################
102 ################################
103
103
104 __version__ = '4.3'
104 __version__ = '4.3'
105 __all__ = ['path']
105 __all__ = ['path']
106
106
107
107
108 class TreeWalkWarning(Warning):
108 class TreeWalkWarning(Warning):
109 pass
109 pass
110
110
111
111
112 def simple_cache(func):
112 def simple_cache(func):
113 """
113 """
114 Save results for the 'using_module' classmethod.
114 Save results for the 'using_module' classmethod.
115 When Python 3.2 is available, use functools.lru_cache instead.
115 When Python 3.2 is available, use functools.lru_cache instead.
116 """
116 """
117 saved_results = {}
117 saved_results = {}
118
118
119 def wrapper(cls, module):
119 def wrapper(cls, module):
120 if module in saved_results:
120 if module in saved_results:
121 return saved_results[module]
121 return saved_results[module]
122 saved_results[module] = func(cls, module)
122 saved_results[module] = func(cls, module)
123 return saved_results[module]
123 return saved_results[module]
124 return wrapper
124 return wrapper
125
125
126
126
127 class ClassProperty(property):
127 class ClassProperty(property):
128 def __get__(self, cls, owner):
128 def __get__(self, cls, owner):
129 return self.fget.__get__(None, owner)()
129 return self.fget.__get__(None, owner)()
130
130
131
131
132 class multimethod(object):
132 class multimethod(object):
133 """
133 """
134 Acts like a classmethod when invoked from the class and like an
134 Acts like a classmethod when invoked from the class and like an
135 instancemethod when invoked from the instance.
135 instancemethod when invoked from the instance.
136 """
136 """
137 def __init__(self, func):
137 def __init__(self, func):
138 self.func = func
138 self.func = func
139
139
140 def __get__(self, instance, owner):
140 def __get__(self, instance, owner):
141 return (
141 return (
142 functools.partial(self.func, owner) if instance is None
142 functools.partial(self.func, owner) if instance is None
143 else functools.partial(self.func, owner, instance)
143 else functools.partial(self.func, owner, instance)
144 )
144 )
145
145
146
146
147 class path(unicode):
147 class path(unicode):
148 """ Represents a filesystem path.
148 """ Represents a filesystem path.
149
149
150 For documentation on individual methods, consult their
150 For documentation on individual methods, consult their
151 counterparts in os.path.
151 counterparts in os.path.
152 """
152 """
153
153
154 module = os.path
154 module = os.path
155 "The path module to use for path operations."
155 "The path module to use for path operations."
156
156
157 def __init__(self, other=''):
157 def __init__(self, other=''):
158 if other is None:
158 if other is None:
159 raise TypeError("Invalid initial value for path: None")
159 raise TypeError("Invalid initial value for path: None")
160
160
161 @classmethod
161 @classmethod
162 @simple_cache
162 @simple_cache
163 def using_module(cls, module):
163 def using_module(cls, module):
164 subclass_name = cls.__name__ + '_' + module.__name__
164 subclass_name = cls.__name__ + '_' + module.__name__
165 bases = (cls,)
165 bases = (cls,)
166 ns = {'module': module}
166 ns = {'module': module}
167 return type(subclass_name, bases, ns)
167 return type(subclass_name, bases, ns)
168
168
169 @ClassProperty
169 @ClassProperty
170 @classmethod
170 @classmethod
171 def _next_class(cls):
171 def _next_class(cls):
172 """
172 """
173 What class should be used to construct new instances from this class
173 What class should be used to construct new instances from this class
174 """
174 """
175 return cls
175 return cls
176
176
177 # --- Special Python methods.
177 # --- Special Python methods.
178
178
179 def __repr__(self):
179 def __repr__(self):
180 return '%s(%s)' % (type(self).__name__, super(path, self).__repr__())
180 return '%s(%s)' % (type(self).__name__, super(path, self).__repr__())
181
181
182 # Adding a path and a string yields a path.
182 # Adding a path and a string yields a path.
183 def __add__(self, more):
183 def __add__(self, more):
184 try:
184 try:
185 return self._next_class(super(path, self).__add__(more))
185 return self._next_class(super(path, self).__add__(more))
186 except TypeError: # Python bug
186 except TypeError: # Python bug
187 return NotImplemented
187 return NotImplemented
188
188
189 def __radd__(self, other):
189 def __radd__(self, other):
190 if not isinstance(other, basestring):
190 if not isinstance(other, basestring):
191 return NotImplemented
191 return NotImplemented
192 return self._next_class(other.__add__(self))
192 return self._next_class(other.__add__(self))
193
193
194 # The / operator joins paths.
194 # The / operator joins paths.
195 def __div__(self, rel):
195 def __div__(self, rel):
196 """ fp.__div__(rel) == fp / rel == fp.joinpath(rel)
196 """ fp.__div__(rel) == fp / rel == fp.joinpath(rel)
197
197
198 Join two path components, adding a separator character if
198 Join two path components, adding a separator character if
199 needed.
199 needed.
200 """
200 """
201 return self._next_class(self.module.join(self, rel))
201 return self._next_class(self.module.join(self, rel))
202
202
203 # Make the / operator work even when true division is enabled.
203 # Make the / operator work even when true division is enabled.
204 __truediv__ = __div__
204 __truediv__ = __div__
205
205
206 def __enter__(self):
206 def __enter__(self):
207 self._old_dir = self.getcwd()
207 self._old_dir = self.getcwd()
208 os.chdir(self)
208 os.chdir(self)
209 return self
209 return self
210
210
211 def __exit__(self, *_):
211 def __exit__(self, *_):
212 os.chdir(self._old_dir)
212 os.chdir(self._old_dir)
213
213
214 @classmethod
214 @classmethod
215 def getcwd(cls):
215 def getcwd(cls):
216 """ Return the current working directory as a path object. """
216 """ Return the current working directory as a path object. """
217 return cls(os.getcwdu())
217 return cls(getcwdu())
218
218
219 #
219 #
220 # --- Operations on path strings.
220 # --- Operations on path strings.
221
221
222 def abspath(self):
222 def abspath(self):
223 return self._next_class(self.module.abspath(self))
223 return self._next_class(self.module.abspath(self))
224
224
225 def normcase(self):
225 def normcase(self):
226 return self._next_class(self.module.normcase(self))
226 return self._next_class(self.module.normcase(self))
227
227
228 def normpath(self):
228 def normpath(self):
229 return self._next_class(self.module.normpath(self))
229 return self._next_class(self.module.normpath(self))
230
230
231 def realpath(self):
231 def realpath(self):
232 return self._next_class(self.module.realpath(self))
232 return self._next_class(self.module.realpath(self))
233
233
234 def expanduser(self):
234 def expanduser(self):
235 return self._next_class(self.module.expanduser(self))
235 return self._next_class(self.module.expanduser(self))
236
236
237 def expandvars(self):
237 def expandvars(self):
238 return self._next_class(self.module.expandvars(self))
238 return self._next_class(self.module.expandvars(self))
239
239
240 def dirname(self):
240 def dirname(self):
241 return self._next_class(self.module.dirname(self))
241 return self._next_class(self.module.dirname(self))
242
242
243 def basename(self):
243 def basename(self):
244 return self._next_class(self.module.basename(self))
244 return self._next_class(self.module.basename(self))
245
245
246 def expand(self):
246 def expand(self):
247 """ Clean up a filename by calling expandvars(),
247 """ Clean up a filename by calling expandvars(),
248 expanduser(), and normpath() on it.
248 expanduser(), and normpath() on it.
249
249
250 This is commonly everything needed to clean up a filename
250 This is commonly everything needed to clean up a filename
251 read from a configuration file, for example.
251 read from a configuration file, for example.
252 """
252 """
253 return self.expandvars().expanduser().normpath()
253 return self.expandvars().expanduser().normpath()
254
254
255 @property
255 @property
256 def namebase(self):
256 def namebase(self):
257 """ The same as path.name, but with one file extension stripped off.
257 """ The same as path.name, but with one file extension stripped off.
258
258
259 For example, path('/home/guido/python.tar.gz').name == 'python.tar.gz',
259 For example, path('/home/guido/python.tar.gz').name == 'python.tar.gz',
260 but path('/home/guido/python.tar.gz').namebase == 'python.tar'
260 but path('/home/guido/python.tar.gz').namebase == 'python.tar'
261 """
261 """
262 base, ext = self.module.splitext(self.name)
262 base, ext = self.module.splitext(self.name)
263 return base
263 return base
264
264
265 @property
265 @property
266 def ext(self):
266 def ext(self):
267 """ The file extension, for example '.py'. """
267 """ The file extension, for example '.py'. """
268 f, ext = self.module.splitext(self)
268 f, ext = self.module.splitext(self)
269 return ext
269 return ext
270
270
271 @property
271 @property
272 def drive(self):
272 def drive(self):
273 """ The drive specifier, for example 'C:'.
273 """ The drive specifier, for example 'C:'.
274 This is always empty on systems that don't use drive specifiers.
274 This is always empty on systems that don't use drive specifiers.
275 """
275 """
276 drive, r = self.module.splitdrive(self)
276 drive, r = self.module.splitdrive(self)
277 return self._next_class(drive)
277 return self._next_class(drive)
278
278
279 parent = property(
279 parent = property(
280 dirname, None, None,
280 dirname, None, None,
281 """ This path's parent directory, as a new path object.
281 """ This path's parent directory, as a new path object.
282
282
283 For example,
283 For example,
284 path('/usr/local/lib/libpython.so').parent == path('/usr/local/lib')
284 path('/usr/local/lib/libpython.so').parent == path('/usr/local/lib')
285 """)
285 """)
286
286
287 name = property(
287 name = property(
288 basename, None, None,
288 basename, None, None,
289 """ The name of this file or directory without the full path.
289 """ The name of this file or directory without the full path.
290
290
291 For example, path('/usr/local/lib/libpython.so').name == 'libpython.so'
291 For example, path('/usr/local/lib/libpython.so').name == 'libpython.so'
292 """)
292 """)
293
293
294 def splitpath(self):
294 def splitpath(self):
295 """ p.splitpath() -> Return (p.parent, p.name). """
295 """ p.splitpath() -> Return (p.parent, p.name). """
296 parent, child = self.module.split(self)
296 parent, child = self.module.split(self)
297 return self._next_class(parent), child
297 return self._next_class(parent), child
298
298
299 def splitdrive(self):
299 def splitdrive(self):
300 """ p.splitdrive() -> Return (p.drive, <the rest of p>).
300 """ p.splitdrive() -> Return (p.drive, <the rest of p>).
301
301
302 Split the drive specifier from this path. If there is
302 Split the drive specifier from this path. If there is
303 no drive specifier, p.drive is empty, so the return value
303 no drive specifier, p.drive is empty, so the return value
304 is simply (path(''), p). This is always the case on Unix.
304 is simply (path(''), p). This is always the case on Unix.
305 """
305 """
306 drive, rel = self.module.splitdrive(self)
306 drive, rel = self.module.splitdrive(self)
307 return self._next_class(drive), rel
307 return self._next_class(drive), rel
308
308
309 def splitext(self):
309 def splitext(self):
310 """ p.splitext() -> Return (p.stripext(), p.ext).
310 """ p.splitext() -> Return (p.stripext(), p.ext).
311
311
312 Split the filename extension from this path and return
312 Split the filename extension from this path and return
313 the two parts. Either part may be empty.
313 the two parts. Either part may be empty.
314
314
315 The extension is everything from '.' to the end of the
315 The extension is everything from '.' to the end of the
316 last path segment. This has the property that if
316 last path segment. This has the property that if
317 (a, b) == p.splitext(), then a + b == p.
317 (a, b) == p.splitext(), then a + b == p.
318 """
318 """
319 filename, ext = self.module.splitext(self)
319 filename, ext = self.module.splitext(self)
320 return self._next_class(filename), ext
320 return self._next_class(filename), ext
321
321
322 def stripext(self):
322 def stripext(self):
323 """ p.stripext() -> Remove one file extension from the path.
323 """ p.stripext() -> Remove one file extension from the path.
324
324
325 For example, path('/home/guido/python.tar.gz').stripext()
325 For example, path('/home/guido/python.tar.gz').stripext()
326 returns path('/home/guido/python.tar').
326 returns path('/home/guido/python.tar').
327 """
327 """
328 return self.splitext()[0]
328 return self.splitext()[0]
329
329
330 def splitunc(self):
330 def splitunc(self):
331 unc, rest = self.module.splitunc(self)
331 unc, rest = self.module.splitunc(self)
332 return self._next_class(unc), rest
332 return self._next_class(unc), rest
333
333
334 @property
334 @property
335 def uncshare(self):
335 def uncshare(self):
336 """
336 """
337 The UNC mount point for this path.
337 The UNC mount point for this path.
338 This is empty for paths on local drives.
338 This is empty for paths on local drives.
339 """
339 """
340 unc, r = self.module.splitunc(self)
340 unc, r = self.module.splitunc(self)
341 return self._next_class(unc)
341 return self._next_class(unc)
342
342
343 @multimethod
343 @multimethod
344 def joinpath(cls, first, *others):
344 def joinpath(cls, first, *others):
345 """
345 """
346 Join first to zero or more path components, adding a separator
346 Join first to zero or more path components, adding a separator
347 character (first.module.sep) if needed. Returns a new instance of
347 character (first.module.sep) if needed. Returns a new instance of
348 first._next_class.
348 first._next_class.
349 """
349 """
350 if not isinstance(first, cls):
350 if not isinstance(first, cls):
351 first = cls(first)
351 first = cls(first)
352 return first._next_class(first.module.join(first, *others))
352 return first._next_class(first.module.join(first, *others))
353
353
354 def splitall(self):
354 def splitall(self):
355 r""" Return a list of the path components in this path.
355 r""" Return a list of the path components in this path.
356
356
357 The first item in the list will be a path. Its value will be
357 The first item in the list will be a path. Its value will be
358 either os.curdir, os.pardir, empty, or the root directory of
358 either os.curdir, os.pardir, empty, or the root directory of
359 this path (for example, ``'/'`` or ``'C:\\'``). The other items in
359 this path (for example, ``'/'`` or ``'C:\\'``). The other items in
360 the list will be strings.
360 the list will be strings.
361
361
362 ``path.path.joinpath(*result)`` will yield the original path.
362 ``path.path.joinpath(*result)`` will yield the original path.
363 """
363 """
364 parts = []
364 parts = []
365 loc = self
365 loc = self
366 while loc != os.curdir and loc != os.pardir:
366 while loc != os.curdir and loc != os.pardir:
367 prev = loc
367 prev = loc
368 loc, child = prev.splitpath()
368 loc, child = prev.splitpath()
369 if loc == prev:
369 if loc == prev:
370 break
370 break
371 parts.append(child)
371 parts.append(child)
372 parts.append(loc)
372 parts.append(loc)
373 parts.reverse()
373 parts.reverse()
374 return parts
374 return parts
375
375
376 def relpath(self, start='.'):
376 def relpath(self, start='.'):
377 """ Return this path as a relative path,
377 """ Return this path as a relative path,
378 based from start, which defaults to the current working directory.
378 based from start, which defaults to the current working directory.
379 """
379 """
380 cwd = self._next_class(start)
380 cwd = self._next_class(start)
381 return cwd.relpathto(self)
381 return cwd.relpathto(self)
382
382
383 def relpathto(self, dest):
383 def relpathto(self, dest):
384 """ Return a relative path from self to dest.
384 """ Return a relative path from self to dest.
385
385
386 If there is no relative path from self to dest, for example if
386 If there is no relative path from self to dest, for example if
387 they reside on different drives in Windows, then this returns
387 they reside on different drives in Windows, then this returns
388 dest.abspath().
388 dest.abspath().
389 """
389 """
390 origin = self.abspath()
390 origin = self.abspath()
391 dest = self._next_class(dest).abspath()
391 dest = self._next_class(dest).abspath()
392
392
393 orig_list = origin.normcase().splitall()
393 orig_list = origin.normcase().splitall()
394 # Don't normcase dest! We want to preserve the case.
394 # Don't normcase dest! We want to preserve the case.
395 dest_list = dest.splitall()
395 dest_list = dest.splitall()
396
396
397 if orig_list[0] != self.module.normcase(dest_list[0]):
397 if orig_list[0] != self.module.normcase(dest_list[0]):
398 # Can't get here from there.
398 # Can't get here from there.
399 return dest
399 return dest
400
400
401 # Find the location where the two paths start to differ.
401 # Find the location where the two paths start to differ.
402 i = 0
402 i = 0
403 for start_seg, dest_seg in zip(orig_list, dest_list):
403 for start_seg, dest_seg in zip(orig_list, dest_list):
404 if start_seg != self.module.normcase(dest_seg):
404 if start_seg != self.module.normcase(dest_seg):
405 break
405 break
406 i += 1
406 i += 1
407
407
408 # Now i is the point where the two paths diverge.
408 # Now i is the point where the two paths diverge.
409 # Need a certain number of "os.pardir"s to work up
409 # Need a certain number of "os.pardir"s to work up
410 # from the origin to the point of divergence.
410 # from the origin to the point of divergence.
411 segments = [os.pardir] * (len(orig_list) - i)
411 segments = [os.pardir] * (len(orig_list) - i)
412 # Need to add the diverging part of dest_list.
412 # Need to add the diverging part of dest_list.
413 segments += dest_list[i:]
413 segments += dest_list[i:]
414 if len(segments) == 0:
414 if len(segments) == 0:
415 # If they happen to be identical, use os.curdir.
415 # If they happen to be identical, use os.curdir.
416 relpath = os.curdir
416 relpath = os.curdir
417 else:
417 else:
418 relpath = self.module.join(*segments)
418 relpath = self.module.join(*segments)
419 return self._next_class(relpath)
419 return self._next_class(relpath)
420
420
421 # --- Listing, searching, walking, and matching
421 # --- Listing, searching, walking, and matching
422
422
423 def listdir(self, pattern=None):
423 def listdir(self, pattern=None):
424 """ D.listdir() -> List of items in this directory.
424 """ D.listdir() -> List of items in this directory.
425
425
426 Use D.files() or D.dirs() instead if you want a listing
426 Use D.files() or D.dirs() instead if you want a listing
427 of just files or just subdirectories.
427 of just files or just subdirectories.
428
428
429 The elements of the list are path objects.
429 The elements of the list are path objects.
430
430
431 With the optional 'pattern' argument, this only lists
431 With the optional 'pattern' argument, this only lists
432 items whose names match the given pattern.
432 items whose names match the given pattern.
433 """
433 """
434 names = os.listdir(self)
434 names = os.listdir(self)
435 if pattern is not None:
435 if pattern is not None:
436 names = fnmatch.filter(names, pattern)
436 names = fnmatch.filter(names, pattern)
437 return [self / child for child in names]
437 return [self / child for child in names]
438
438
439 def dirs(self, pattern=None):
439 def dirs(self, pattern=None):
440 """ D.dirs() -> List of this directory's subdirectories.
440 """ D.dirs() -> List of this directory's subdirectories.
441
441
442 The elements of the list are path objects.
442 The elements of the list are path objects.
443 This does not walk recursively into subdirectories
443 This does not walk recursively into subdirectories
444 (but see path.walkdirs).
444 (but see path.walkdirs).
445
445
446 With the optional 'pattern' argument, this only lists
446 With the optional 'pattern' argument, this only lists
447 directories whose names match the given pattern. For
447 directories whose names match the given pattern. For
448 example, ``d.dirs('build-*')``.
448 example, ``d.dirs('build-*')``.
449 """
449 """
450 return [p for p in self.listdir(pattern) if p.isdir()]
450 return [p for p in self.listdir(pattern) if p.isdir()]
451
451
452 def files(self, pattern=None):
452 def files(self, pattern=None):
453 """ D.files() -> List of the files in this directory.
453 """ D.files() -> List of the files in this directory.
454
454
455 The elements of the list are path objects.
455 The elements of the list are path objects.
456 This does not walk into subdirectories (see path.walkfiles).
456 This does not walk into subdirectories (see path.walkfiles).
457
457
458 With the optional 'pattern' argument, this only lists files
458 With the optional 'pattern' argument, this only lists files
459 whose names match the given pattern. For example,
459 whose names match the given pattern. For example,
460 ``d.files('*.pyc')``.
460 ``d.files('*.pyc')``.
461 """
461 """
462
462
463 return [p for p in self.listdir(pattern) if p.isfile()]
463 return [p for p in self.listdir(pattern) if p.isfile()]
464
464
465 def walk(self, pattern=None, errors='strict'):
465 def walk(self, pattern=None, errors='strict'):
466 """ D.walk() -> iterator over files and subdirs, recursively.
466 """ D.walk() -> iterator over files and subdirs, recursively.
467
467
468 The iterator yields path objects naming each child item of
468 The iterator yields path objects naming each child item of
469 this directory and its descendants. This requires that
469 this directory and its descendants. This requires that
470 D.isdir().
470 D.isdir().
471
471
472 This performs a depth-first traversal of the directory tree.
472 This performs a depth-first traversal of the directory tree.
473 Each directory is returned just before all its children.
473 Each directory is returned just before all its children.
474
474
475 The errors= keyword argument controls behavior when an
475 The errors= keyword argument controls behavior when an
476 error occurs. The default is 'strict', which causes an
476 error occurs. The default is 'strict', which causes an
477 exception. The other allowed values are 'warn', which
477 exception. The other allowed values are 'warn', which
478 reports the error via warnings.warn(), and 'ignore'.
478 reports the error via warnings.warn(), and 'ignore'.
479 """
479 """
480 if errors not in ('strict', 'warn', 'ignore'):
480 if errors not in ('strict', 'warn', 'ignore'):
481 raise ValueError("invalid errors parameter")
481 raise ValueError("invalid errors parameter")
482
482
483 try:
483 try:
484 childList = self.listdir()
484 childList = self.listdir()
485 except Exception:
485 except Exception:
486 if errors == 'ignore':
486 if errors == 'ignore':
487 return
487 return
488 elif errors == 'warn':
488 elif errors == 'warn':
489 warnings.warn(
489 warnings.warn(
490 "Unable to list directory '%s': %s"
490 "Unable to list directory '%s': %s"
491 % (self, sys.exc_info()[1]),
491 % (self, sys.exc_info()[1]),
492 TreeWalkWarning)
492 TreeWalkWarning)
493 return
493 return
494 else:
494 else:
495 raise
495 raise
496
496
497 for child in childList:
497 for child in childList:
498 if pattern is None or child.fnmatch(pattern):
498 if pattern is None or child.fnmatch(pattern):
499 yield child
499 yield child
500 try:
500 try:
501 isdir = child.isdir()
501 isdir = child.isdir()
502 except Exception:
502 except Exception:
503 if errors == 'ignore':
503 if errors == 'ignore':
504 isdir = False
504 isdir = False
505 elif errors == 'warn':
505 elif errors == 'warn':
506 warnings.warn(
506 warnings.warn(
507 "Unable to access '%s': %s"
507 "Unable to access '%s': %s"
508 % (child, sys.exc_info()[1]),
508 % (child, sys.exc_info()[1]),
509 TreeWalkWarning)
509 TreeWalkWarning)
510 isdir = False
510 isdir = False
511 else:
511 else:
512 raise
512 raise
513
513
514 if isdir:
514 if isdir:
515 for item in child.walk(pattern, errors):
515 for item in child.walk(pattern, errors):
516 yield item
516 yield item
517
517
518 def walkdirs(self, pattern=None, errors='strict'):
518 def walkdirs(self, pattern=None, errors='strict'):
519 """ D.walkdirs() -> iterator over subdirs, recursively.
519 """ D.walkdirs() -> iterator over subdirs, recursively.
520
520
521 With the optional 'pattern' argument, this yields only
521 With the optional 'pattern' argument, this yields only
522 directories whose names match the given pattern. For
522 directories whose names match the given pattern. For
523 example, ``mydir.walkdirs('*test')`` yields only directories
523 example, ``mydir.walkdirs('*test')`` yields only directories
524 with names ending in 'test'.
524 with names ending in 'test'.
525
525
526 The errors= keyword argument controls behavior when an
526 The errors= keyword argument controls behavior when an
527 error occurs. The default is 'strict', which causes an
527 error occurs. The default is 'strict', which causes an
528 exception. The other allowed values are 'warn', which
528 exception. The other allowed values are 'warn', which
529 reports the error via warnings.warn(), and 'ignore'.
529 reports the error via warnings.warn(), and 'ignore'.
530 """
530 """
531 if errors not in ('strict', 'warn', 'ignore'):
531 if errors not in ('strict', 'warn', 'ignore'):
532 raise ValueError("invalid errors parameter")
532 raise ValueError("invalid errors parameter")
533
533
534 try:
534 try:
535 dirs = self.dirs()
535 dirs = self.dirs()
536 except Exception:
536 except Exception:
537 if errors == 'ignore':
537 if errors == 'ignore':
538 return
538 return
539 elif errors == 'warn':
539 elif errors == 'warn':
540 warnings.warn(
540 warnings.warn(
541 "Unable to list directory '%s': %s"
541 "Unable to list directory '%s': %s"
542 % (self, sys.exc_info()[1]),
542 % (self, sys.exc_info()[1]),
543 TreeWalkWarning)
543 TreeWalkWarning)
544 return
544 return
545 else:
545 else:
546 raise
546 raise
547
547
548 for child in dirs:
548 for child in dirs:
549 if pattern is None or child.fnmatch(pattern):
549 if pattern is None or child.fnmatch(pattern):
550 yield child
550 yield child
551 for subsubdir in child.walkdirs(pattern, errors):
551 for subsubdir in child.walkdirs(pattern, errors):
552 yield subsubdir
552 yield subsubdir
553
553
554 def walkfiles(self, pattern=None, errors='strict'):
554 def walkfiles(self, pattern=None, errors='strict'):
555 """ D.walkfiles() -> iterator over files in D, recursively.
555 """ D.walkfiles() -> iterator over files in D, recursively.
556
556
557 The optional argument, pattern, limits the results to files
557 The optional argument, pattern, limits the results to files
558 with names that match the pattern. For example,
558 with names that match the pattern. For example,
559 ``mydir.walkfiles('*.tmp')`` yields only files with the .tmp
559 ``mydir.walkfiles('*.tmp')`` yields only files with the .tmp
560 extension.
560 extension.
561 """
561 """
562 if errors not in ('strict', 'warn', 'ignore'):
562 if errors not in ('strict', 'warn', 'ignore'):
563 raise ValueError("invalid errors parameter")
563 raise ValueError("invalid errors parameter")
564
564
565 try:
565 try:
566 childList = self.listdir()
566 childList = self.listdir()
567 except Exception:
567 except Exception:
568 if errors == 'ignore':
568 if errors == 'ignore':
569 return
569 return
570 elif errors == 'warn':
570 elif errors == 'warn':
571 warnings.warn(
571 warnings.warn(
572 "Unable to list directory '%s': %s"
572 "Unable to list directory '%s': %s"
573 % (self, sys.exc_info()[1]),
573 % (self, sys.exc_info()[1]),
574 TreeWalkWarning)
574 TreeWalkWarning)
575 return
575 return
576 else:
576 else:
577 raise
577 raise
578
578
579 for child in childList:
579 for child in childList:
580 try:
580 try:
581 isfile = child.isfile()
581 isfile = child.isfile()
582 isdir = not isfile and child.isdir()
582 isdir = not isfile and child.isdir()
583 except:
583 except:
584 if errors == 'ignore':
584 if errors == 'ignore':
585 continue
585 continue
586 elif errors == 'warn':
586 elif errors == 'warn':
587 warnings.warn(
587 warnings.warn(
588 "Unable to access '%s': %s"
588 "Unable to access '%s': %s"
589 % (self, sys.exc_info()[1]),
589 % (self, sys.exc_info()[1]),
590 TreeWalkWarning)
590 TreeWalkWarning)
591 continue
591 continue
592 else:
592 else:
593 raise
593 raise
594
594
595 if isfile:
595 if isfile:
596 if pattern is None or child.fnmatch(pattern):
596 if pattern is None or child.fnmatch(pattern):
597 yield child
597 yield child
598 elif isdir:
598 elif isdir:
599 for f in child.walkfiles(pattern, errors):
599 for f in child.walkfiles(pattern, errors):
600 yield f
600 yield f
601
601
602 def fnmatch(self, pattern):
602 def fnmatch(self, pattern):
603 """ Return True if self.name matches the given pattern.
603 """ Return True if self.name matches the given pattern.
604
604
605 pattern - A filename pattern with wildcards,
605 pattern - A filename pattern with wildcards,
606 for example ``'*.py'``.
606 for example ``'*.py'``.
607 """
607 """
608 return fnmatch.fnmatch(self.name, pattern)
608 return fnmatch.fnmatch(self.name, pattern)
609
609
610 def glob(self, pattern):
610 def glob(self, pattern):
611 """ Return a list of path objects that match the pattern.
611 """ Return a list of path objects that match the pattern.
612
612
613 pattern - a path relative to this directory, with wildcards.
613 pattern - a path relative to this directory, with wildcards.
614
614
615 For example, path('/users').glob('*/bin/*') returns a list
615 For example, path('/users').glob('*/bin/*') returns a list
616 of all the files users have in their bin directories.
616 of all the files users have in their bin directories.
617 """
617 """
618 cls = self._next_class
618 cls = self._next_class
619 return [cls(s) for s in glob.glob(self / pattern)]
619 return [cls(s) for s in glob.glob(self / pattern)]
620
620
621 #
621 #
622 # --- Reading or writing an entire file at once.
622 # --- Reading or writing an entire file at once.
623
623
624 def open(self, *args, **kwargs):
624 def open(self, *args, **kwargs):
625 """ Open this file. Return a file object. """
625 """ Open this file. Return a file object. """
626 return open(self, *args, **kwargs)
626 return open(self, *args, **kwargs)
627
627
628 def bytes(self):
628 def bytes(self):
629 """ Open this file, read all bytes, return them as a string. """
629 """ Open this file, read all bytes, return them as a string. """
630 with self.open('rb') as f:
630 with self.open('rb') as f:
631 return f.read()
631 return f.read()
632
632
633 def chunks(self, size, *args, **kwargs):
633 def chunks(self, size, *args, **kwargs):
634 """ Returns a generator yielding chunks of the file, so it can
634 """ Returns a generator yielding chunks of the file, so it can
635 be read piece by piece with a simple for loop.
635 be read piece by piece with a simple for loop.
636
636
637 Any argument you pass after `size` will be passed to `open()`.
637 Any argument you pass after `size` will be passed to `open()`.
638
638
639 :example:
639 :example:
640
640
641 >>> for chunk in path("file.txt").chunk(8192):
641 >>> for chunk in path("file.txt").chunk(8192):
642 ... print(chunk)
642 ... print(chunk)
643
643
644 This will read the file by chunks of 8192 bytes.
644 This will read the file by chunks of 8192 bytes.
645 """
645 """
646 with open(self, *args, **kwargs) as f:
646 with open(self, *args, **kwargs) as f:
647 while True:
647 while True:
648 d = f.read(size)
648 d = f.read(size)
649 if not d:
649 if not d:
650 break
650 break
651 yield d
651 yield d
652
652
653 def write_bytes(self, bytes, append=False):
653 def write_bytes(self, bytes, append=False):
654 """ Open this file and write the given bytes to it.
654 """ Open this file and write the given bytes to it.
655
655
656 Default behavior is to overwrite any existing file.
656 Default behavior is to overwrite any existing file.
657 Call p.write_bytes(bytes, append=True) to append instead.
657 Call p.write_bytes(bytes, append=True) to append instead.
658 """
658 """
659 if append:
659 if append:
660 mode = 'ab'
660 mode = 'ab'
661 else:
661 else:
662 mode = 'wb'
662 mode = 'wb'
663 with self.open(mode) as f:
663 with self.open(mode) as f:
664 f.write(bytes)
664 f.write(bytes)
665
665
666 def text(self, encoding=None, errors='strict'):
666 def text(self, encoding=None, errors='strict'):
667 r""" Open this file, read it in, return the content as a string.
667 r""" Open this file, read it in, return the content as a string.
668
668
669 This method uses 'U' mode, so '\r\n' and '\r' are automatically
669 This method uses 'U' mode, so '\r\n' and '\r' are automatically
670 translated to '\n'.
670 translated to '\n'.
671
671
672 Optional arguments:
672 Optional arguments:
673
673
674 encoding - The Unicode encoding (or character set) of
674 encoding - The Unicode encoding (or character set) of
675 the file. If present, the content of the file is
675 the file. If present, the content of the file is
676 decoded and returned as a unicode object; otherwise
676 decoded and returned as a unicode object; otherwise
677 it is returned as an 8-bit str.
677 it is returned as an 8-bit str.
678 errors - How to handle Unicode errors; see help(str.decode)
678 errors - How to handle Unicode errors; see help(str.decode)
679 for the options. Default is 'strict'.
679 for the options. Default is 'strict'.
680 """
680 """
681 if encoding is None:
681 if encoding is None:
682 # 8-bit
682 # 8-bit
683 with self.open('U') as f:
683 with self.open('U') as f:
684 return f.read()
684 return f.read()
685 else:
685 else:
686 # Unicode
686 # Unicode
687 with codecs.open(self, 'r', encoding, errors) as f:
687 with codecs.open(self, 'r', encoding, errors) as f:
688 # (Note - Can't use 'U' mode here, since codecs.open
688 # (Note - Can't use 'U' mode here, since codecs.open
689 # doesn't support 'U' mode.)
689 # doesn't support 'U' mode.)
690 t = f.read()
690 t = f.read()
691 return (t.replace(u('\r\n'), u('\n'))
691 return (t.replace(u('\r\n'), u('\n'))
692 .replace(u('\r\x85'), u('\n'))
692 .replace(u('\r\x85'), u('\n'))
693 .replace(u('\r'), u('\n'))
693 .replace(u('\r'), u('\n'))
694 .replace(u('\x85'), u('\n'))
694 .replace(u('\x85'), u('\n'))
695 .replace(u('\u2028'), u('\n')))
695 .replace(u('\u2028'), u('\n')))
696
696
697 def write_text(self, text, encoding=None, errors='strict',
697 def write_text(self, text, encoding=None, errors='strict',
698 linesep=os.linesep, append=False):
698 linesep=os.linesep, append=False):
699 r""" Write the given text to this file.
699 r""" Write the given text to this file.
700
700
701 The default behavior is to overwrite any existing file;
701 The default behavior is to overwrite any existing file;
702 to append instead, use the 'append=True' keyword argument.
702 to append instead, use the 'append=True' keyword argument.
703
703
704 There are two differences between path.write_text() and
704 There are two differences between path.write_text() and
705 path.write_bytes(): newline handling and Unicode handling.
705 path.write_bytes(): newline handling and Unicode handling.
706 See below.
706 See below.
707
707
708 Parameters:
708 Parameters:
709
709
710 - text - str/unicode - The text to be written.
710 - text - str/unicode - The text to be written.
711
711
712 - encoding - str - The Unicode encoding that will be used.
712 - encoding - str - The Unicode encoding that will be used.
713 This is ignored if 'text' isn't a Unicode string.
713 This is ignored if 'text' isn't a Unicode string.
714
714
715 - errors - str - How to handle Unicode encoding errors.
715 - errors - str - How to handle Unicode encoding errors.
716 Default is 'strict'. See help(unicode.encode) for the
716 Default is 'strict'. See help(unicode.encode) for the
717 options. This is ignored if 'text' isn't a Unicode
717 options. This is ignored if 'text' isn't a Unicode
718 string.
718 string.
719
719
720 - linesep - keyword argument - str/unicode - The sequence of
720 - linesep - keyword argument - str/unicode - The sequence of
721 characters to be used to mark end-of-line. The default is
721 characters to be used to mark end-of-line. The default is
722 os.linesep. You can also specify None; this means to
722 os.linesep. You can also specify None; this means to
723 leave all newlines as they are in 'text'.
723 leave all newlines as they are in 'text'.
724
724
725 - append - keyword argument - bool - Specifies what to do if
725 - append - keyword argument - bool - Specifies what to do if
726 the file already exists (True: append to the end of it;
726 the file already exists (True: append to the end of it;
727 False: overwrite it.) The default is False.
727 False: overwrite it.) The default is False.
728
728
729
729
730 --- Newline handling.
730 --- Newline handling.
731
731
732 write_text() converts all standard end-of-line sequences
732 write_text() converts all standard end-of-line sequences
733 ('\n', '\r', and '\r\n') to your platform's default end-of-line
733 ('\n', '\r', and '\r\n') to your platform's default end-of-line
734 sequence (see os.linesep; on Windows, for example, the
734 sequence (see os.linesep; on Windows, for example, the
735 end-of-line marker is '\r\n').
735 end-of-line marker is '\r\n').
736
736
737 If you don't like your platform's default, you can override it
737 If you don't like your platform's default, you can override it
738 using the 'linesep=' keyword argument. If you specifically want
738 using the 'linesep=' keyword argument. If you specifically want
739 write_text() to preserve the newlines as-is, use 'linesep=None'.
739 write_text() to preserve the newlines as-is, use 'linesep=None'.
740
740
741 This applies to Unicode text the same as to 8-bit text, except
741 This applies to Unicode text the same as to 8-bit text, except
742 there are three additional standard Unicode end-of-line sequences:
742 there are three additional standard Unicode end-of-line sequences:
743 u'\x85', u'\r\x85', and u'\u2028'.
743 u'\x85', u'\r\x85', and u'\u2028'.
744
744
745 (This is slightly different from when you open a file for
745 (This is slightly different from when you open a file for
746 writing with fopen(filename, "w") in C or open(filename, 'w')
746 writing with fopen(filename, "w") in C or open(filename, 'w')
747 in Python.)
747 in Python.)
748
748
749
749
750 --- Unicode
750 --- Unicode
751
751
752 If 'text' isn't Unicode, then apart from newline handling, the
752 If 'text' isn't Unicode, then apart from newline handling, the
753 bytes are written verbatim to the file. The 'encoding' and
753 bytes are written verbatim to the file. The 'encoding' and
754 'errors' arguments are not used and must be omitted.
754 'errors' arguments are not used and must be omitted.
755
755
756 If 'text' is Unicode, it is first converted to bytes using the
756 If 'text' is Unicode, it is first converted to bytes using the
757 specified 'encoding' (or the default encoding if 'encoding'
757 specified 'encoding' (or the default encoding if 'encoding'
758 isn't specified). The 'errors' argument applies only to this
758 isn't specified). The 'errors' argument applies only to this
759 conversion.
759 conversion.
760
760
761 """
761 """
762 if isinstance(text, unicode):
762 if isinstance(text, unicode):
763 if linesep is not None:
763 if linesep is not None:
764 # Convert all standard end-of-line sequences to
764 # Convert all standard end-of-line sequences to
765 # ordinary newline characters.
765 # ordinary newline characters.
766 text = (text.replace(u('\r\n'), u('\n'))
766 text = (text.replace(u('\r\n'), u('\n'))
767 .replace(u('\r\x85'), u('\n'))
767 .replace(u('\r\x85'), u('\n'))
768 .replace(u('\r'), u('\n'))
768 .replace(u('\r'), u('\n'))
769 .replace(u('\x85'), u('\n'))
769 .replace(u('\x85'), u('\n'))
770 .replace(u('\u2028'), u('\n')))
770 .replace(u('\u2028'), u('\n')))
771 text = text.replace(u('\n'), linesep)
771 text = text.replace(u('\n'), linesep)
772 if encoding is None:
772 if encoding is None:
773 encoding = sys.getdefaultencoding()
773 encoding = sys.getdefaultencoding()
774 bytes = text.encode(encoding, errors)
774 bytes = text.encode(encoding, errors)
775 else:
775 else:
776 # It is an error to specify an encoding if 'text' is
776 # It is an error to specify an encoding if 'text' is
777 # an 8-bit string.
777 # an 8-bit string.
778 assert encoding is None
778 assert encoding is None
779
779
780 if linesep is not None:
780 if linesep is not None:
781 text = (text.replace('\r\n', '\n')
781 text = (text.replace('\r\n', '\n')
782 .replace('\r', '\n'))
782 .replace('\r', '\n'))
783 bytes = text.replace('\n', linesep)
783 bytes = text.replace('\n', linesep)
784
784
785 self.write_bytes(bytes, append)
785 self.write_bytes(bytes, append)
786
786
787 def lines(self, encoding=None, errors='strict', retain=True):
787 def lines(self, encoding=None, errors='strict', retain=True):
788 r""" Open this file, read all lines, return them in a list.
788 r""" Open this file, read all lines, return them in a list.
789
789
790 Optional arguments:
790 Optional arguments:
791 encoding - The Unicode encoding (or character set) of
791 encoding - The Unicode encoding (or character set) of
792 the file. The default is None, meaning the content
792 the file. The default is None, meaning the content
793 of the file is read as 8-bit characters and returned
793 of the file is read as 8-bit characters and returned
794 as a list of (non-Unicode) str objects.
794 as a list of (non-Unicode) str objects.
795 errors - How to handle Unicode errors; see help(str.decode)
795 errors - How to handle Unicode errors; see help(str.decode)
796 for the options. Default is 'strict'
796 for the options. Default is 'strict'
797 retain - If true, retain newline characters; but all newline
797 retain - If true, retain newline characters; but all newline
798 character combinations ('\r', '\n', '\r\n') are
798 character combinations ('\r', '\n', '\r\n') are
799 translated to '\n'. If false, newline characters are
799 translated to '\n'. If false, newline characters are
800 stripped off. Default is True.
800 stripped off. Default is True.
801
801
802 This uses 'U' mode.
802 This uses 'U' mode.
803 """
803 """
804 if encoding is None and retain:
804 if encoding is None and retain:
805 with self.open('U') as f:
805 with self.open('U') as f:
806 return f.readlines()
806 return f.readlines()
807 else:
807 else:
808 return self.text(encoding, errors).splitlines(retain)
808 return self.text(encoding, errors).splitlines(retain)
809
809
810 def write_lines(self, lines, encoding=None, errors='strict',
810 def write_lines(self, lines, encoding=None, errors='strict',
811 linesep=os.linesep, append=False):
811 linesep=os.linesep, append=False):
812 r""" Write the given lines of text to this file.
812 r""" Write the given lines of text to this file.
813
813
814 By default this overwrites any existing file at this path.
814 By default this overwrites any existing file at this path.
815
815
816 This puts a platform-specific newline sequence on every line.
816 This puts a platform-specific newline sequence on every line.
817 See 'linesep' below.
817 See 'linesep' below.
818
818
819 lines - A list of strings.
819 lines - A list of strings.
820
820
821 encoding - A Unicode encoding to use. This applies only if
821 encoding - A Unicode encoding to use. This applies only if
822 'lines' contains any Unicode strings.
822 'lines' contains any Unicode strings.
823
823
824 errors - How to handle errors in Unicode encoding. This
824 errors - How to handle errors in Unicode encoding. This
825 also applies only to Unicode strings.
825 also applies only to Unicode strings.
826
826
827 linesep - The desired line-ending. This line-ending is
827 linesep - The desired line-ending. This line-ending is
828 applied to every line. If a line already has any
828 applied to every line. If a line already has any
829 standard line ending ('\r', '\n', '\r\n', u'\x85',
829 standard line ending ('\r', '\n', '\r\n', u'\x85',
830 u'\r\x85', u'\u2028'), that will be stripped off and
830 u'\r\x85', u'\u2028'), that will be stripped off and
831 this will be used instead. The default is os.linesep,
831 this will be used instead. The default is os.linesep,
832 which is platform-dependent ('\r\n' on Windows, '\n' on
832 which is platform-dependent ('\r\n' on Windows, '\n' on
833 Unix, etc.) Specify None to write the lines as-is,
833 Unix, etc.) Specify None to write the lines as-is,
834 like file.writelines().
834 like file.writelines().
835
835
836 Use the keyword argument append=True to append lines to the
836 Use the keyword argument append=True to append lines to the
837 file. The default is to overwrite the file. Warning:
837 file. The default is to overwrite the file. Warning:
838 When you use this with Unicode data, if the encoding of the
838 When you use this with Unicode data, if the encoding of the
839 existing data in the file is different from the encoding
839 existing data in the file is different from the encoding
840 you specify with the encoding= parameter, the result is
840 you specify with the encoding= parameter, the result is
841 mixed-encoding data, which can really confuse someone trying
841 mixed-encoding data, which can really confuse someone trying
842 to read the file later.
842 to read the file later.
843 """
843 """
844 if append:
844 if append:
845 mode = 'ab'
845 mode = 'ab'
846 else:
846 else:
847 mode = 'wb'
847 mode = 'wb'
848 with self.open(mode) as f:
848 with self.open(mode) as f:
849 for line in lines:
849 for line in lines:
850 isUnicode = isinstance(line, unicode)
850 isUnicode = isinstance(line, unicode)
851 if linesep is not None:
851 if linesep is not None:
852 # Strip off any existing line-end and add the
852 # Strip off any existing line-end and add the
853 # specified linesep string.
853 # specified linesep string.
854 if isUnicode:
854 if isUnicode:
855 if line[-2:] in (u('\r\n'), u('\x0d\x85')):
855 if line[-2:] in (u('\r\n'), u('\x0d\x85')):
856 line = line[:-2]
856 line = line[:-2]
857 elif line[-1:] in (u('\r'), u('\n'),
857 elif line[-1:] in (u('\r'), u('\n'),
858 u('\x85'), u('\u2028')):
858 u('\x85'), u('\u2028')):
859 line = line[:-1]
859 line = line[:-1]
860 else:
860 else:
861 if line[-2:] == '\r\n':
861 if line[-2:] == '\r\n':
862 line = line[:-2]
862 line = line[:-2]
863 elif line[-1:] in ('\r', '\n'):
863 elif line[-1:] in ('\r', '\n'):
864 line = line[:-1]
864 line = line[:-1]
865 line += linesep
865 line += linesep
866 if isUnicode:
866 if isUnicode:
867 if encoding is None:
867 if encoding is None:
868 encoding = sys.getdefaultencoding()
868 encoding = sys.getdefaultencoding()
869 line = line.encode(encoding, errors)
869 line = line.encode(encoding, errors)
870 f.write(line)
870 f.write(line)
871
871
872 def read_md5(self):
872 def read_md5(self):
873 """ Calculate the md5 hash for this file.
873 """ Calculate the md5 hash for this file.
874
874
875 This reads through the entire file.
875 This reads through the entire file.
876 """
876 """
877 return self.read_hash('md5')
877 return self.read_hash('md5')
878
878
879 def _hash(self, hash_name):
879 def _hash(self, hash_name):
880 """ Returns a hash object for the file at the current path.
880 """ Returns a hash object for the file at the current path.
881
881
882 `hash_name` should be a hash algo name such as 'md5' or 'sha1'
882 `hash_name` should be a hash algo name such as 'md5' or 'sha1'
883 that's available in the `hashlib` module.
883 that's available in the `hashlib` module.
884 """
884 """
885 m = hashlib.new(hash_name)
885 m = hashlib.new(hash_name)
886 for chunk in self.chunks(8192):
886 for chunk in self.chunks(8192):
887 m.update(chunk)
887 m.update(chunk)
888 return m
888 return m
889
889
890 def read_hash(self, hash_name):
890 def read_hash(self, hash_name):
891 """ Calculate given hash for this file.
891 """ Calculate given hash for this file.
892
892
893 List of supported hashes can be obtained from hashlib package. This
893 List of supported hashes can be obtained from hashlib package. This
894 reads the entire file.
894 reads the entire file.
895 """
895 """
896 return self._hash(hash_name).digest()
896 return self._hash(hash_name).digest()
897
897
898 def read_hexhash(self, hash_name):
898 def read_hexhash(self, hash_name):
899 """ Calculate given hash for this file, returning hexdigest.
899 """ Calculate given hash for this file, returning hexdigest.
900
900
901 List of supported hashes can be obtained from hashlib package. This
901 List of supported hashes can be obtained from hashlib package. This
902 reads the entire file.
902 reads the entire file.
903 """
903 """
904 return self._hash(hash_name).hexdigest()
904 return self._hash(hash_name).hexdigest()
905
905
906 # --- Methods for querying the filesystem.
906 # --- Methods for querying the filesystem.
907 # N.B. On some platforms, the os.path functions may be implemented in C
907 # N.B. On some platforms, the os.path functions may be implemented in C
908 # (e.g. isdir on Windows, Python 3.2.2), and compiled functions don't get
908 # (e.g. isdir on Windows, Python 3.2.2), and compiled functions don't get
909 # bound. Playing it safe and wrapping them all in method calls.
909 # bound. Playing it safe and wrapping them all in method calls.
910
910
911 def isabs(self):
911 def isabs(self):
912 return self.module.isabs(self)
912 return self.module.isabs(self)
913
913
914 def exists(self):
914 def exists(self):
915 return self.module.exists(self)
915 return self.module.exists(self)
916
916
917 def isdir(self):
917 def isdir(self):
918 return self.module.isdir(self)
918 return self.module.isdir(self)
919
919
920 def isfile(self):
920 def isfile(self):
921 return self.module.isfile(self)
921 return self.module.isfile(self)
922
922
923 def islink(self):
923 def islink(self):
924 return self.module.islink(self)
924 return self.module.islink(self)
925
925
926 def ismount(self):
926 def ismount(self):
927 return self.module.ismount(self)
927 return self.module.ismount(self)
928
928
929 def samefile(self, other):
929 def samefile(self, other):
930 return self.module.samefile(self, other)
930 return self.module.samefile(self, other)
931
931
932 def getatime(self):
932 def getatime(self):
933 return self.module.getatime(self)
933 return self.module.getatime(self)
934
934
935 atime = property(
935 atime = property(
936 getatime, None, None,
936 getatime, None, None,
937 """ Last access time of the file. """)
937 """ Last access time of the file. """)
938
938
939 def getmtime(self):
939 def getmtime(self):
940 return self.module.getmtime(self)
940 return self.module.getmtime(self)
941
941
942 mtime = property(
942 mtime = property(
943 getmtime, None, None,
943 getmtime, None, None,
944 """ Last-modified time of the file. """)
944 """ Last-modified time of the file. """)
945
945
946 def getctime(self):
946 def getctime(self):
947 return self.module.getctime(self)
947 return self.module.getctime(self)
948
948
949 ctime = property(
949 ctime = property(
950 getctime, None, None,
950 getctime, None, None,
951 """ Creation time of the file. """)
951 """ Creation time of the file. """)
952
952
953 def getsize(self):
953 def getsize(self):
954 return self.module.getsize(self)
954 return self.module.getsize(self)
955
955
956 size = property(
956 size = property(
957 getsize, None, None,
957 getsize, None, None,
958 """ Size of the file, in bytes. """)
958 """ Size of the file, in bytes. """)
959
959
960 if hasattr(os, 'access'):
960 if hasattr(os, 'access'):
961 def access(self, mode):
961 def access(self, mode):
962 """ Return true if current user has access to this path.
962 """ Return true if current user has access to this path.
963
963
964 mode - One of the constants os.F_OK, os.R_OK, os.W_OK, os.X_OK
964 mode - One of the constants os.F_OK, os.R_OK, os.W_OK, os.X_OK
965 """
965 """
966 return os.access(self, mode)
966 return os.access(self, mode)
967
967
968 def stat(self):
968 def stat(self):
969 """ Perform a stat() system call on this path. """
969 """ Perform a stat() system call on this path. """
970 return os.stat(self)
970 return os.stat(self)
971
971
972 def lstat(self):
972 def lstat(self):
973 """ Like path.stat(), but do not follow symbolic links. """
973 """ Like path.stat(), but do not follow symbolic links. """
974 return os.lstat(self)
974 return os.lstat(self)
975
975
976 def __get_owner_windows(self):
976 def __get_owner_windows(self):
977 r"""
977 r"""
978 Return the name of the owner of this file or directory. Follow
978 Return the name of the owner of this file or directory. Follow
979 symbolic links.
979 symbolic links.
980
980
981 Return a name of the form ur'DOMAIN\User Name'; may be a group.
981 Return a name of the form ur'DOMAIN\User Name'; may be a group.
982 """
982 """
983 desc = win32security.GetFileSecurity(
983 desc = win32security.GetFileSecurity(
984 self, win32security.OWNER_SECURITY_INFORMATION)
984 self, win32security.OWNER_SECURITY_INFORMATION)
985 sid = desc.GetSecurityDescriptorOwner()
985 sid = desc.GetSecurityDescriptorOwner()
986 account, domain, typecode = win32security.LookupAccountSid(None, sid)
986 account, domain, typecode = win32security.LookupAccountSid(None, sid)
987 return domain + u('\\') + account
987 return domain + u('\\') + account
988
988
989 def __get_owner_unix(self):
989 def __get_owner_unix(self):
990 """
990 """
991 Return the name of the owner of this file or directory. Follow
991 Return the name of the owner of this file or directory. Follow
992 symbolic links.
992 symbolic links.
993 """
993 """
994 st = self.stat()
994 st = self.stat()
995 return pwd.getpwuid(st.st_uid).pw_name
995 return pwd.getpwuid(st.st_uid).pw_name
996
996
997 def __get_owner_not_implemented(self):
997 def __get_owner_not_implemented(self):
998 raise NotImplementedError("Ownership not available on this platform.")
998 raise NotImplementedError("Ownership not available on this platform.")
999
999
1000 if 'win32security' in globals():
1000 if 'win32security' in globals():
1001 get_owner = __get_owner_windows
1001 get_owner = __get_owner_windows
1002 elif 'pwd' in globals():
1002 elif 'pwd' in globals():
1003 get_owner = __get_owner_unix
1003 get_owner = __get_owner_unix
1004 else:
1004 else:
1005 get_owner = __get_owner_not_implemented
1005 get_owner = __get_owner_not_implemented
1006
1006
1007 owner = property(
1007 owner = property(
1008 get_owner, None, None,
1008 get_owner, None, None,
1009 """ Name of the owner of this file or directory. """)
1009 """ Name of the owner of this file or directory. """)
1010
1010
1011 if hasattr(os, 'statvfs'):
1011 if hasattr(os, 'statvfs'):
1012 def statvfs(self):
1012 def statvfs(self):
1013 """ Perform a statvfs() system call on this path. """
1013 """ Perform a statvfs() system call on this path. """
1014 return os.statvfs(self)
1014 return os.statvfs(self)
1015
1015
1016 if hasattr(os, 'pathconf'):
1016 if hasattr(os, 'pathconf'):
1017 def pathconf(self, name):
1017 def pathconf(self, name):
1018 return os.pathconf(self, name)
1018 return os.pathconf(self, name)
1019
1019
1020 #
1020 #
1021 # --- Modifying operations on files and directories
1021 # --- Modifying operations on files and directories
1022
1022
1023 def utime(self, times):
1023 def utime(self, times):
1024 """ Set the access and modified times of this file. """
1024 """ Set the access and modified times of this file. """
1025 os.utime(self, times)
1025 os.utime(self, times)
1026 return self
1026 return self
1027
1027
1028 def chmod(self, mode):
1028 def chmod(self, mode):
1029 os.chmod(self, mode)
1029 os.chmod(self, mode)
1030 return self
1030 return self
1031
1031
1032 if hasattr(os, 'chown'):
1032 if hasattr(os, 'chown'):
1033 def chown(self, uid=-1, gid=-1):
1033 def chown(self, uid=-1, gid=-1):
1034 os.chown(self, uid, gid)
1034 os.chown(self, uid, gid)
1035 return self
1035 return self
1036
1036
1037 def rename(self, new):
1037 def rename(self, new):
1038 os.rename(self, new)
1038 os.rename(self, new)
1039 return self._next_class(new)
1039 return self._next_class(new)
1040
1040
1041 def renames(self, new):
1041 def renames(self, new):
1042 os.renames(self, new)
1042 os.renames(self, new)
1043 return self._next_class(new)
1043 return self._next_class(new)
1044
1044
1045 #
1045 #
1046 # --- Create/delete operations on directories
1046 # --- Create/delete operations on directories
1047
1047
1048 def mkdir(self, mode=o777):
1048 def mkdir(self, mode=o777):
1049 os.mkdir(self, mode)
1049 os.mkdir(self, mode)
1050 return self
1050 return self
1051
1051
1052 def mkdir_p(self, mode=o777):
1052 def mkdir_p(self, mode=o777):
1053 try:
1053 try:
1054 self.mkdir(mode)
1054 self.mkdir(mode)
1055 except OSError:
1055 except OSError:
1056 _, e, _ = sys.exc_info()
1056 _, e, _ = sys.exc_info()
1057 if e.errno != errno.EEXIST:
1057 if e.errno != errno.EEXIST:
1058 raise
1058 raise
1059 return self
1059 return self
1060
1060
1061 def makedirs(self, mode=o777):
1061 def makedirs(self, mode=o777):
1062 os.makedirs(self, mode)
1062 os.makedirs(self, mode)
1063 return self
1063 return self
1064
1064
1065 def makedirs_p(self, mode=o777):
1065 def makedirs_p(self, mode=o777):
1066 try:
1066 try:
1067 self.makedirs(mode)
1067 self.makedirs(mode)
1068 except OSError:
1068 except OSError:
1069 _, e, _ = sys.exc_info()
1069 _, e, _ = sys.exc_info()
1070 if e.errno != errno.EEXIST:
1070 if e.errno != errno.EEXIST:
1071 raise
1071 raise
1072 return self
1072 return self
1073
1073
1074 def rmdir(self):
1074 def rmdir(self):
1075 os.rmdir(self)
1075 os.rmdir(self)
1076 return self
1076 return self
1077
1077
1078 def rmdir_p(self):
1078 def rmdir_p(self):
1079 try:
1079 try:
1080 self.rmdir()
1080 self.rmdir()
1081 except OSError:
1081 except OSError:
1082 _, e, _ = sys.exc_info()
1082 _, e, _ = sys.exc_info()
1083 if e.errno != errno.ENOTEMPTY and e.errno != errno.EEXIST:
1083 if e.errno != errno.ENOTEMPTY and e.errno != errno.EEXIST:
1084 raise
1084 raise
1085 return self
1085 return self
1086
1086
1087 def removedirs(self):
1087 def removedirs(self):
1088 os.removedirs(self)
1088 os.removedirs(self)
1089 return self
1089 return self
1090
1090
1091 def removedirs_p(self):
1091 def removedirs_p(self):
1092 try:
1092 try:
1093 self.removedirs()
1093 self.removedirs()
1094 except OSError:
1094 except OSError:
1095 _, e, _ = sys.exc_info()
1095 _, e, _ = sys.exc_info()
1096 if e.errno != errno.ENOTEMPTY and e.errno != errno.EEXIST:
1096 if e.errno != errno.ENOTEMPTY and e.errno != errno.EEXIST:
1097 raise
1097 raise
1098 return self
1098 return self
1099
1099
1100 # --- Modifying operations on files
1100 # --- Modifying operations on files
1101
1101
1102 def touch(self):
1102 def touch(self):
1103 """ Set the access/modified times of this file to the current time.
1103 """ Set the access/modified times of this file to the current time.
1104 Create the file if it does not exist.
1104 Create the file if it does not exist.
1105 """
1105 """
1106 fd = os.open(self, os.O_WRONLY | os.O_CREAT, o666)
1106 fd = os.open(self, os.O_WRONLY | os.O_CREAT, o666)
1107 os.close(fd)
1107 os.close(fd)
1108 os.utime(self, None)
1108 os.utime(self, None)
1109 return self
1109 return self
1110
1110
1111 def remove(self):
1111 def remove(self):
1112 os.remove(self)
1112 os.remove(self)
1113 return self
1113 return self
1114
1114
1115 def remove_p(self):
1115 def remove_p(self):
1116 try:
1116 try:
1117 self.unlink()
1117 self.unlink()
1118 except OSError:
1118 except OSError:
1119 _, e, _ = sys.exc_info()
1119 _, e, _ = sys.exc_info()
1120 if e.errno != errno.ENOENT:
1120 if e.errno != errno.ENOENT:
1121 raise
1121 raise
1122 return self
1122 return self
1123
1123
1124 def unlink(self):
1124 def unlink(self):
1125 os.unlink(self)
1125 os.unlink(self)
1126 return self
1126 return self
1127
1127
1128 def unlink_p(self):
1128 def unlink_p(self):
1129 self.remove_p()
1129 self.remove_p()
1130 return self
1130 return self
1131
1131
1132 # --- Links
1132 # --- Links
1133
1133
1134 if hasattr(os, 'link'):
1134 if hasattr(os, 'link'):
1135 def link(self, newpath):
1135 def link(self, newpath):
1136 """ Create a hard link at 'newpath', pointing to this file. """
1136 """ Create a hard link at 'newpath', pointing to this file. """
1137 os.link(self, newpath)
1137 os.link(self, newpath)
1138 return self._next_class(newpath)
1138 return self._next_class(newpath)
1139
1139
1140 if hasattr(os, 'symlink'):
1140 if hasattr(os, 'symlink'):
1141 def symlink(self, newlink):
1141 def symlink(self, newlink):
1142 """ Create a symbolic link at 'newlink', pointing here. """
1142 """ Create a symbolic link at 'newlink', pointing here. """
1143 os.symlink(self, newlink)
1143 os.symlink(self, newlink)
1144 return self._next_class(newlink)
1144 return self._next_class(newlink)
1145
1145
1146 if hasattr(os, 'readlink'):
1146 if hasattr(os, 'readlink'):
1147 def readlink(self):
1147 def readlink(self):
1148 """ Return the path to which this symbolic link points.
1148 """ Return the path to which this symbolic link points.
1149
1149
1150 The result may be an absolute or a relative path.
1150 The result may be an absolute or a relative path.
1151 """
1151 """
1152 return self._next_class(os.readlink(self))
1152 return self._next_class(os.readlink(self))
1153
1153
1154 def readlinkabs(self):
1154 def readlinkabs(self):
1155 """ Return the path to which this symbolic link points.
1155 """ Return the path to which this symbolic link points.
1156
1156
1157 The result is always an absolute path.
1157 The result is always an absolute path.
1158 """
1158 """
1159 p = self.readlink()
1159 p = self.readlink()
1160 if p.isabs():
1160 if p.isabs():
1161 return p
1161 return p
1162 else:
1162 else:
1163 return (self.parent / p).abspath()
1163 return (self.parent / p).abspath()
1164
1164
1165 #
1165 #
1166 # --- High-level functions from shutil
1166 # --- High-level functions from shutil
1167
1167
1168 copyfile = shutil.copyfile
1168 copyfile = shutil.copyfile
1169 copymode = shutil.copymode
1169 copymode = shutil.copymode
1170 copystat = shutil.copystat
1170 copystat = shutil.copystat
1171 copy = shutil.copy
1171 copy = shutil.copy
1172 copy2 = shutil.copy2
1172 copy2 = shutil.copy2
1173 copytree = shutil.copytree
1173 copytree = shutil.copytree
1174 if hasattr(shutil, 'move'):
1174 if hasattr(shutil, 'move'):
1175 move = shutil.move
1175 move = shutil.move
1176 rmtree = shutil.rmtree
1176 rmtree = shutil.rmtree
1177
1177
1178 def rmtree_p(self):
1178 def rmtree_p(self):
1179 try:
1179 try:
1180 self.rmtree()
1180 self.rmtree()
1181 except OSError:
1181 except OSError:
1182 _, e, _ = sys.exc_info()
1182 _, e, _ = sys.exc_info()
1183 if e.errno != errno.ENOENT:
1183 if e.errno != errno.ENOENT:
1184 raise
1184 raise
1185 return self
1185 return self
1186
1186
1187 def chdir(self):
1187 def chdir(self):
1188 os.chdir(self)
1188 os.chdir(self)
1189
1189
1190 cd = chdir
1190 cd = chdir
1191
1191
1192 #
1192 #
1193 # --- Special stuff from os
1193 # --- Special stuff from os
1194
1194
1195 if hasattr(os, 'chroot'):
1195 if hasattr(os, 'chroot'):
1196 def chroot(self):
1196 def chroot(self):
1197 os.chroot(self)
1197 os.chroot(self)
1198
1198
1199 if hasattr(os, 'startfile'):
1199 if hasattr(os, 'startfile'):
1200 def startfile(self):
1200 def startfile(self):
1201 os.startfile(self)
1201 os.startfile(self)
1202 return self
1202 return self
1203
1203
1204
1204
1205 class tempdir(path):
1205 class tempdir(path):
1206 """
1206 """
1207 A temporary directory via tempfile.mkdtemp, and constructed with the
1207 A temporary directory via tempfile.mkdtemp, and constructed with the
1208 same parameters that you can use as a context manager.
1208 same parameters that you can use as a context manager.
1209
1209
1210 Example:
1210 Example:
1211
1211
1212 with tempdir() as d:
1212 with tempdir() as d:
1213 # do stuff with the path object "d"
1213 # do stuff with the path object "d"
1214
1214
1215 # here the directory is deleted automatically
1215 # here the directory is deleted automatically
1216 """
1216 """
1217
1217
1218 @ClassProperty
1218 @ClassProperty
1219 @classmethod
1219 @classmethod
1220 def _next_class(cls):
1220 def _next_class(cls):
1221 return path
1221 return path
1222
1222
1223 def __new__(cls, *args, **kwargs):
1223 def __new__(cls, *args, **kwargs):
1224 dirname = tempfile.mkdtemp(*args, **kwargs)
1224 dirname = tempfile.mkdtemp(*args, **kwargs)
1225 return super(tempdir, cls).__new__(cls, dirname)
1225 return super(tempdir, cls).__new__(cls, dirname)
1226
1226
1227 def __init__(self, *args, **kwargs):
1227 def __init__(self, *args, **kwargs):
1228 pass
1228 pass
1229
1229
1230 def __enter__(self):
1230 def __enter__(self):
1231 return self
1231 return self
1232
1232
1233 def __exit__(self, exc_type, exc_value, traceback):
1233 def __exit__(self, exc_type, exc_value, traceback):
1234 if not exc_value:
1234 if not exc_value:
1235 self.rmtree()
1235 self.rmtree()
1236
1236
1237
1237
1238 def _permission_mask(mode):
1238 def _permission_mask(mode):
1239 """
1239 """
1240 Convert a Unix chmod symbolic mode like 'ugo+rwx' to a function
1240 Convert a Unix chmod symbolic mode like 'ugo+rwx' to a function
1241 suitable for applying to a mask to affect that change.
1241 suitable for applying to a mask to affect that change.
1242
1242
1243 >>> mask = _permission_mask('ugo+rwx')
1243 >>> mask = _permission_mask('ugo+rwx')
1244 >>> oct(mask(o554))
1244 >>> oct(mask(o554))
1245 'o777'
1245 'o777'
1246
1246
1247 >>> oct(_permission_mask('gw-x')(o777))
1247 >>> oct(_permission_mask('gw-x')(o777))
1248 'o766'
1248 'o766'
1249 """
1249 """
1250 parsed = re.match('(?P<who>[ugo]+)(?P<op>[-+])(?P<what>[rwx]+)$', mode)
1250 parsed = re.match('(?P<who>[ugo]+)(?P<op>[-+])(?P<what>[rwx]+)$', mode)
1251 if not parsed:
1251 if not parsed:
1252 raise ValueError("Unrecognized symbolic mode", mode)
1252 raise ValueError("Unrecognized symbolic mode", mode)
1253 spec_map = dict(r=4, w=2, x=1)
1253 spec_map = dict(r=4, w=2, x=1)
1254 spec = reduce(operator.or_, [spec_map[perm]
1254 spec = reduce(operator.or_, [spec_map[perm]
1255 for perm in parsed.group('what')])
1255 for perm in parsed.group('what')])
1256 # now apply spec to each in who
1256 # now apply spec to each in who
1257 shift_map = dict(u=6, g=3, o=0)
1257 shift_map = dict(u=6, g=3, o=0)
1258 mask = reduce(operator.or_, [spec << shift_map[subj]
1258 mask = reduce(operator.or_, [spec << shift_map[subj]
1259 for subj in parsed.group('who')])
1259 for subj in parsed.group('who')])
1260
1260
1261 op = parsed.group('op')
1261 op = parsed.group('op')
1262 # if op is -, invert the mask
1262 # if op is -, invert the mask
1263 if op == '-':
1263 if op == '-':
1264 mask ^= o777
1264 mask ^= o777
1265
1265
1266 op_map = {'+': operator.or_, '-': operator.and_}
1266 op_map = {'+': operator.or_, '-': operator.and_}
1267 return functools.partial(op_map[op], mask)
1267 return functools.partial(op_map[op], mask)
@@ -1,172 +1,171 b''
1 """Manage IPython.parallel clusters in the notebook.
1 """Manage IPython.parallel clusters in the notebook.
2
2
3 Authors:
3 Authors:
4
4
5 * Brian Granger
5 * Brian Granger
6 """
6 """
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 import os
20
21 from tornado import web
19 from tornado import web
22 from zmq.eventloop import ioloop
20 from zmq.eventloop import ioloop
23
21
24 from IPython.config.configurable import LoggingConfigurable
22 from IPython.config.configurable import LoggingConfigurable
25 from IPython.utils.traitlets import Dict, Instance, CFloat
23 from IPython.utils.traitlets import Dict, Instance, CFloat
26 from IPython.parallel.apps.ipclusterapp import IPClusterStart
24 from IPython.parallel.apps.ipclusterapp import IPClusterStart
27 from IPython.core.profileapp import list_profiles_in
25 from IPython.core.profileapp import list_profiles_in
28 from IPython.core.profiledir import ProfileDir
26 from IPython.core.profiledir import ProfileDir
27 from IPython.utils import py3compat
29 from IPython.utils.path import get_ipython_dir
28 from IPython.utils.path import get_ipython_dir
30
29
31
30
32 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
33 # Classes
32 # Classes
34 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
35
34
36
35
37 class DummyIPClusterStart(IPClusterStart):
36 class DummyIPClusterStart(IPClusterStart):
38 """Dummy subclass to skip init steps that conflict with global app.
37 """Dummy subclass to skip init steps that conflict with global app.
39
38
40 Instantiating and initializing this class should result in fully configured
39 Instantiating and initializing this class should result in fully configured
41 launchers, but no other side effects or state.
40 launchers, but no other side effects or state.
42 """
41 """
43
42
44 def init_signal(self):
43 def init_signal(self):
45 pass
44 pass
46 def reinit_logging(self):
45 def reinit_logging(self):
47 pass
46 pass
48
47
49
48
50 class ClusterManager(LoggingConfigurable):
49 class ClusterManager(LoggingConfigurable):
51
50
52 profiles = Dict()
51 profiles = Dict()
53
52
54 delay = CFloat(1., config=True,
53 delay = CFloat(1., config=True,
55 help="delay (in s) between starting the controller and the engines")
54 help="delay (in s) between starting the controller and the engines")
56
55
57 loop = Instance('zmq.eventloop.ioloop.IOLoop')
56 loop = Instance('zmq.eventloop.ioloop.IOLoop')
58 def _loop_default(self):
57 def _loop_default(self):
59 from zmq.eventloop.ioloop import IOLoop
58 from zmq.eventloop.ioloop import IOLoop
60 return IOLoop.instance()
59 return IOLoop.instance()
61
60
62 def build_launchers(self, profile_dir):
61 def build_launchers(self, profile_dir):
63 starter = DummyIPClusterStart(log=self.log)
62 starter = DummyIPClusterStart(log=self.log)
64 starter.initialize(['--profile-dir', profile_dir])
63 starter.initialize(['--profile-dir', profile_dir])
65 cl = starter.controller_launcher
64 cl = starter.controller_launcher
66 esl = starter.engine_launcher
65 esl = starter.engine_launcher
67 n = starter.n
66 n = starter.n
68 return cl, esl, n
67 return cl, esl, n
69
68
70 def get_profile_dir(self, name, path):
69 def get_profile_dir(self, name, path):
71 p = ProfileDir.find_profile_dir_by_name(path,name=name)
70 p = ProfileDir.find_profile_dir_by_name(path,name=name)
72 return p.location
71 return p.location
73
72
74 def update_profiles(self):
73 def update_profiles(self):
75 """List all profiles in the ipython_dir and cwd.
74 """List all profiles in the ipython_dir and cwd.
76 """
75 """
77 for path in [get_ipython_dir(), os.getcwdu()]:
76 for path in [get_ipython_dir(), py3compat.getcwd()]:
78 for profile in list_profiles_in(path):
77 for profile in list_profiles_in(path):
79 pd = self.get_profile_dir(profile, path)
78 pd = self.get_profile_dir(profile, path)
80 if profile not in self.profiles:
79 if profile not in self.profiles:
81 self.log.debug("Adding cluster profile '%s'" % profile)
80 self.log.debug("Adding cluster profile '%s'" % profile)
82 self.profiles[profile] = {
81 self.profiles[profile] = {
83 'profile': profile,
82 'profile': profile,
84 'profile_dir': pd,
83 'profile_dir': pd,
85 'status': 'stopped'
84 'status': 'stopped'
86 }
85 }
87
86
88 def list_profiles(self):
87 def list_profiles(self):
89 self.update_profiles()
88 self.update_profiles()
90 # sorted list, but ensure that 'default' always comes first
89 # sorted list, but ensure that 'default' always comes first
91 default_first = lambda name: name if name != 'default' else ''
90 default_first = lambda name: name if name != 'default' else ''
92 result = [self.profile_info(p) for p in sorted(self.profiles, key=default_first)]
91 result = [self.profile_info(p) for p in sorted(self.profiles, key=default_first)]
93 return result
92 return result
94
93
95 def check_profile(self, profile):
94 def check_profile(self, profile):
96 if profile not in self.profiles:
95 if profile not in self.profiles:
97 raise web.HTTPError(404, u'profile not found')
96 raise web.HTTPError(404, u'profile not found')
98
97
99 def profile_info(self, profile):
98 def profile_info(self, profile):
100 self.check_profile(profile)
99 self.check_profile(profile)
101 result = {}
100 result = {}
102 data = self.profiles.get(profile)
101 data = self.profiles.get(profile)
103 result['profile'] = profile
102 result['profile'] = profile
104 result['profile_dir'] = data['profile_dir']
103 result['profile_dir'] = data['profile_dir']
105 result['status'] = data['status']
104 result['status'] = data['status']
106 if 'n' in data:
105 if 'n' in data:
107 result['n'] = data['n']
106 result['n'] = data['n']
108 return result
107 return result
109
108
110 def start_cluster(self, profile, n=None):
109 def start_cluster(self, profile, n=None):
111 """Start a cluster for a given profile."""
110 """Start a cluster for a given profile."""
112 self.check_profile(profile)
111 self.check_profile(profile)
113 data = self.profiles[profile]
112 data = self.profiles[profile]
114 if data['status'] == 'running':
113 if data['status'] == 'running':
115 raise web.HTTPError(409, u'cluster already running')
114 raise web.HTTPError(409, u'cluster already running')
116 cl, esl, default_n = self.build_launchers(data['profile_dir'])
115 cl, esl, default_n = self.build_launchers(data['profile_dir'])
117 n = n if n is not None else default_n
116 n = n if n is not None else default_n
118 def clean_data():
117 def clean_data():
119 data.pop('controller_launcher',None)
118 data.pop('controller_launcher',None)
120 data.pop('engine_set_launcher',None)
119 data.pop('engine_set_launcher',None)
121 data.pop('n',None)
120 data.pop('n',None)
122 data['status'] = 'stopped'
121 data['status'] = 'stopped'
123 def engines_stopped(r):
122 def engines_stopped(r):
124 self.log.debug('Engines stopped')
123 self.log.debug('Engines stopped')
125 if cl.running:
124 if cl.running:
126 cl.stop()
125 cl.stop()
127 clean_data()
126 clean_data()
128 esl.on_stop(engines_stopped)
127 esl.on_stop(engines_stopped)
129 def controller_stopped(r):
128 def controller_stopped(r):
130 self.log.debug('Controller stopped')
129 self.log.debug('Controller stopped')
131 if esl.running:
130 if esl.running:
132 esl.stop()
131 esl.stop()
133 clean_data()
132 clean_data()
134 cl.on_stop(controller_stopped)
133 cl.on_stop(controller_stopped)
135
134
136 dc = ioloop.DelayedCallback(lambda: cl.start(), 0, self.loop)
135 dc = ioloop.DelayedCallback(lambda: cl.start(), 0, self.loop)
137 dc.start()
136 dc.start()
138 dc = ioloop.DelayedCallback(lambda: esl.start(n), 1000*self.delay, self.loop)
137 dc = ioloop.DelayedCallback(lambda: esl.start(n), 1000*self.delay, self.loop)
139 dc.start()
138 dc.start()
140
139
141 self.log.debug('Cluster started')
140 self.log.debug('Cluster started')
142 data['controller_launcher'] = cl
141 data['controller_launcher'] = cl
143 data['engine_set_launcher'] = esl
142 data['engine_set_launcher'] = esl
144 data['n'] = n
143 data['n'] = n
145 data['status'] = 'running'
144 data['status'] = 'running'
146 return self.profile_info(profile)
145 return self.profile_info(profile)
147
146
148 def stop_cluster(self, profile):
147 def stop_cluster(self, profile):
149 """Stop a cluster for a given profile."""
148 """Stop a cluster for a given profile."""
150 self.check_profile(profile)
149 self.check_profile(profile)
151 data = self.profiles[profile]
150 data = self.profiles[profile]
152 if data['status'] == 'stopped':
151 if data['status'] == 'stopped':
153 raise web.HTTPError(409, u'cluster not running')
152 raise web.HTTPError(409, u'cluster not running')
154 data = self.profiles[profile]
153 data = self.profiles[profile]
155 cl = data['controller_launcher']
154 cl = data['controller_launcher']
156 esl = data['engine_set_launcher']
155 esl = data['engine_set_launcher']
157 if cl.running:
156 if cl.running:
158 cl.stop()
157 cl.stop()
159 if esl.running:
158 if esl.running:
160 esl.stop()
159 esl.stop()
161 # Return a temp info dict, the real one is updated in the on_stop
160 # Return a temp info dict, the real one is updated in the on_stop
162 # logic above.
161 # logic above.
163 result = {
162 result = {
164 'profile': data['profile'],
163 'profile': data['profile'],
165 'profile_dir': data['profile_dir'],
164 'profile_dir': data['profile_dir'],
166 'status': 'stopped'
165 'status': 'stopped'
167 }
166 }
168 return result
167 return result
169
168
170 def stop_all_clusters(self):
169 def stop_all_clusters(self):
171 for p in self.profiles.keys():
170 for p in self.profiles.keys():
172 self.stop_cluster(p)
171 self.stop_cluster(p)
@@ -1,173 +1,174 b''
1 """A base class notebook manager.
1 """A base class notebook manager.
2
2
3 Authors:
3 Authors:
4
4
5 * Brian Granger
5 * Brian Granger
6 * Zach Sailer
6 * Zach Sailer
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2011 The IPython Development Team
10 # Copyright (C) 2011 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 import os
20 import os
21
21
22 from IPython.config.configurable import LoggingConfigurable
22 from IPython.config.configurable import LoggingConfigurable
23 from IPython.nbformat import current
23 from IPython.nbformat import current
24 from IPython.utils.traitlets import List, Dict, Unicode, TraitError
24 from IPython.utils import py3compat
25 from IPython.utils.traitlets import Unicode, TraitError
25
26
26 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
27 # Classes
28 # Classes
28 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
29
30
30 class NotebookManager(LoggingConfigurable):
31 class NotebookManager(LoggingConfigurable):
31
32
32 # Todo:
33 # Todo:
33 # The notebook_dir attribute is used to mean a couple of different things:
34 # The notebook_dir attribute is used to mean a couple of different things:
34 # 1. Where the notebooks are stored if FileNotebookManager is used.
35 # 1. Where the notebooks are stored if FileNotebookManager is used.
35 # 2. The cwd of the kernel for a project.
36 # 2. The cwd of the kernel for a project.
36 # Right now we use this attribute in a number of different places and
37 # Right now we use this attribute in a number of different places and
37 # we are going to have to disentangle all of this.
38 # we are going to have to disentangle all of this.
38 notebook_dir = Unicode(os.getcwdu(), config=True, help="""
39 notebook_dir = Unicode(py3compat.getcwd(), config=True, help="""
39 The directory to use for notebooks.
40 The directory to use for notebooks.
40 """)
41 """)
41
42
42 filename_ext = Unicode(u'.ipynb')
43 filename_ext = Unicode(u'.ipynb')
43
44
44 def path_exists(self, path):
45 def path_exists(self, path):
45 """Does the API-style path (directory) actually exist?
46 """Does the API-style path (directory) actually exist?
46
47
47 Override this method in subclasses.
48 Override this method in subclasses.
48
49
49 Parameters
50 Parameters
50 ----------
51 ----------
51 path : string
52 path : string
52 The
53 The
53
54
54 Returns
55 Returns
55 -------
56 -------
56 exists : bool
57 exists : bool
57 Whether the path does indeed exist.
58 Whether the path does indeed exist.
58 """
59 """
59 raise NotImplementedError
60 raise NotImplementedError
60
61
61 def _notebook_dir_changed(self, name, old, new):
62 def _notebook_dir_changed(self, name, old, new):
62 """Do a bit of validation of the notebook dir."""
63 """Do a bit of validation of the notebook dir."""
63 if not os.path.isabs(new):
64 if not os.path.isabs(new):
64 # If we receive a non-absolute path, make it absolute.
65 # If we receive a non-absolute path, make it absolute.
65 self.notebook_dir = os.path.abspath(new)
66 self.notebook_dir = os.path.abspath(new)
66 return
67 return
67 if os.path.exists(new) and not os.path.isdir(new):
68 if os.path.exists(new) and not os.path.isdir(new):
68 raise TraitError("notebook dir %r is not a directory" % new)
69 raise TraitError("notebook dir %r is not a directory" % new)
69 if not os.path.exists(new):
70 if not os.path.exists(new):
70 self.log.info("Creating notebook dir %s", new)
71 self.log.info("Creating notebook dir %s", new)
71 try:
72 try:
72 os.mkdir(new)
73 os.mkdir(new)
73 except:
74 except:
74 raise TraitError("Couldn't create notebook dir %r" % new)
75 raise TraitError("Couldn't create notebook dir %r" % new)
75
76
76 # Main notebook API
77 # Main notebook API
77
78
78 def increment_filename(self, basename, path=''):
79 def increment_filename(self, basename, path=''):
79 """Increment a notebook filename without the .ipynb to make it unique.
80 """Increment a notebook filename without the .ipynb to make it unique.
80
81
81 Parameters
82 Parameters
82 ----------
83 ----------
83 basename : unicode
84 basename : unicode
84 The name of a notebook without the ``.ipynb`` file extension.
85 The name of a notebook without the ``.ipynb`` file extension.
85 path : unicode
86 path : unicode
86 The URL path of the notebooks directory
87 The URL path of the notebooks directory
87 """
88 """
88 return basename
89 return basename
89
90
90 def list_notebooks(self, path=''):
91 def list_notebooks(self, path=''):
91 """Return a list of notebook dicts without content.
92 """Return a list of notebook dicts without content.
92
93
93 This returns a list of dicts, each of the form::
94 This returns a list of dicts, each of the form::
94
95
95 dict(notebook_id=notebook,name=name)
96 dict(notebook_id=notebook,name=name)
96
97
97 This list of dicts should be sorted by name::
98 This list of dicts should be sorted by name::
98
99
99 data = sorted(data, key=lambda item: item['name'])
100 data = sorted(data, key=lambda item: item['name'])
100 """
101 """
101 raise NotImplementedError('must be implemented in a subclass')
102 raise NotImplementedError('must be implemented in a subclass')
102
103
103 def get_notebook_model(self, name, path='', content=True):
104 def get_notebook_model(self, name, path='', content=True):
104 """Get the notebook model with or without content."""
105 """Get the notebook model with or without content."""
105 raise NotImplementedError('must be implemented in a subclass')
106 raise NotImplementedError('must be implemented in a subclass')
106
107
107 def save_notebook_model(self, model, name, path=''):
108 def save_notebook_model(self, model, name, path=''):
108 """Save the notebook model and return the model with no content."""
109 """Save the notebook model and return the model with no content."""
109 raise NotImplementedError('must be implemented in a subclass')
110 raise NotImplementedError('must be implemented in a subclass')
110
111
111 def update_notebook_model(self, model, name, path=''):
112 def update_notebook_model(self, model, name, path=''):
112 """Update the notebook model and return the model with no content."""
113 """Update the notebook model and return the model with no content."""
113 raise NotImplementedError('must be implemented in a subclass')
114 raise NotImplementedError('must be implemented in a subclass')
114
115
115 def delete_notebook_model(self, name, path=''):
116 def delete_notebook_model(self, name, path=''):
116 """Delete notebook by name and path."""
117 """Delete notebook by name and path."""
117 raise NotImplementedError('must be implemented in a subclass')
118 raise NotImplementedError('must be implemented in a subclass')
118
119
119 def create_notebook_model(self, model=None, path=''):
120 def create_notebook_model(self, model=None, path=''):
120 """Create a new notebook and return its model with no content."""
121 """Create a new notebook and return its model with no content."""
121 path = path.strip('/')
122 path = path.strip('/')
122 if model is None:
123 if model is None:
123 model = {}
124 model = {}
124 if 'content' not in model:
125 if 'content' not in model:
125 metadata = current.new_metadata(name=u'')
126 metadata = current.new_metadata(name=u'')
126 model['content'] = current.new_notebook(metadata=metadata)
127 model['content'] = current.new_notebook(metadata=metadata)
127 if 'name' not in model:
128 if 'name' not in model:
128 model['name'] = self.increment_filename('Untitled', path)
129 model['name'] = self.increment_filename('Untitled', path)
129
130
130 model['path'] = path
131 model['path'] = path
131 model = self.save_notebook_model(model, model['name'], model['path'])
132 model = self.save_notebook_model(model, model['name'], model['path'])
132 return model
133 return model
133
134
134 def copy_notebook(self, from_name, to_name=None, path=''):
135 def copy_notebook(self, from_name, to_name=None, path=''):
135 """Copy an existing notebook and return its new model.
136 """Copy an existing notebook and return its new model.
136
137
137 If to_name not specified, increment `from_name-Copy#.ipynb`.
138 If to_name not specified, increment `from_name-Copy#.ipynb`.
138 """
139 """
139 path = path.strip('/')
140 path = path.strip('/')
140 model = self.get_notebook_model(from_name, path)
141 model = self.get_notebook_model(from_name, path)
141 if not to_name:
142 if not to_name:
142 base = os.path.splitext(from_name)[0] + '-Copy'
143 base = os.path.splitext(from_name)[0] + '-Copy'
143 to_name = self.increment_filename(base, path)
144 to_name = self.increment_filename(base, path)
144 model['name'] = to_name
145 model['name'] = to_name
145 model = self.save_notebook_model(model, to_name, path)
146 model = self.save_notebook_model(model, to_name, path)
146 return model
147 return model
147
148
148 # Checkpoint-related
149 # Checkpoint-related
149
150
150 def create_checkpoint(self, name, path=''):
151 def create_checkpoint(self, name, path=''):
151 """Create a checkpoint of the current state of a notebook
152 """Create a checkpoint of the current state of a notebook
152
153
153 Returns a checkpoint_id for the new checkpoint.
154 Returns a checkpoint_id for the new checkpoint.
154 """
155 """
155 raise NotImplementedError("must be implemented in a subclass")
156 raise NotImplementedError("must be implemented in a subclass")
156
157
157 def list_checkpoints(self, name, path=''):
158 def list_checkpoints(self, name, path=''):
158 """Return a list of checkpoints for a given notebook"""
159 """Return a list of checkpoints for a given notebook"""
159 return []
160 return []
160
161
161 def restore_checkpoint(self, checkpoint_id, name, path=''):
162 def restore_checkpoint(self, checkpoint_id, name, path=''):
162 """Restore a notebook from one of its checkpoints"""
163 """Restore a notebook from one of its checkpoints"""
163 raise NotImplementedError("must be implemented in a subclass")
164 raise NotImplementedError("must be implemented in a subclass")
164
165
165 def delete_checkpoint(self, checkpoint_id, name, path=''):
166 def delete_checkpoint(self, checkpoint_id, name, path=''):
166 """delete a checkpoint for a notebook"""
167 """delete a checkpoint for a notebook"""
167 raise NotImplementedError("must be implemented in a subclass")
168 raise NotImplementedError("must be implemented in a subclass")
168
169
169 def log_info(self):
170 def log_info(self):
170 self.log.info(self.info_string())
171 self.log.info(self.info_string())
171
172
172 def info_string(self):
173 def info_string(self):
173 return "Serving notebooks"
174 return "Serving notebooks"
@@ -1,275 +1,276 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 The Base Application class for IPython.parallel apps
3 The Base Application class for IPython.parallel apps
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 * Min RK
8 * Min RK
9
9
10 """
10 """
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2011 The IPython Development Team
13 # Copyright (C) 2008-2011 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import os
23 import os
24 import logging
24 import logging
25 import re
25 import re
26 import sys
26 import sys
27
27
28 from subprocess import Popen, PIPE
28 from subprocess import Popen, PIPE
29
29
30 from IPython.config.application import catch_config_error, LevelFormatter
30 from IPython.config.application import catch_config_error, LevelFormatter
31 from IPython.core import release
31 from IPython.core import release
32 from IPython.core.crashhandler import CrashHandler
32 from IPython.core.crashhandler import CrashHandler
33 from IPython.core.application import (
33 from IPython.core.application import (
34 BaseIPythonApplication,
34 BaseIPythonApplication,
35 base_aliases as base_ip_aliases,
35 base_aliases as base_ip_aliases,
36 base_flags as base_ip_flags
36 base_flags as base_ip_flags
37 )
37 )
38 from IPython.utils.path import expand_path
38 from IPython.utils.path import expand_path
39 from IPython.utils import py3compat
39 from IPython.utils.py3compat import unicode_type
40 from IPython.utils.py3compat import unicode_type
40
41
41 from IPython.utils.traitlets import Unicode, Bool, Instance, Dict
42 from IPython.utils.traitlets import Unicode, Bool, Instance, Dict
42
43
43 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
44 # Module errors
45 # Module errors
45 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
46
47
47 class PIDFileError(Exception):
48 class PIDFileError(Exception):
48 pass
49 pass
49
50
50
51
51 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
52 # Crash handler for this application
53 # Crash handler for this application
53 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
54
55
55 class ParallelCrashHandler(CrashHandler):
56 class ParallelCrashHandler(CrashHandler):
56 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
57 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
57
58
58 def __init__(self, app):
59 def __init__(self, app):
59 contact_name = release.authors['Min'][0]
60 contact_name = release.authors['Min'][0]
60 contact_email = release.author_email
61 contact_email = release.author_email
61 bug_tracker = 'https://github.com/ipython/ipython/issues'
62 bug_tracker = 'https://github.com/ipython/ipython/issues'
62 super(ParallelCrashHandler,self).__init__(
63 super(ParallelCrashHandler,self).__init__(
63 app, contact_name, contact_email, bug_tracker
64 app, contact_name, contact_email, bug_tracker
64 )
65 )
65
66
66
67
67 #-----------------------------------------------------------------------------
68 #-----------------------------------------------------------------------------
68 # Main application
69 # Main application
69 #-----------------------------------------------------------------------------
70 #-----------------------------------------------------------------------------
70 base_aliases = {}
71 base_aliases = {}
71 base_aliases.update(base_ip_aliases)
72 base_aliases.update(base_ip_aliases)
72 base_aliases.update({
73 base_aliases.update({
73 'work-dir' : 'BaseParallelApplication.work_dir',
74 'work-dir' : 'BaseParallelApplication.work_dir',
74 'log-to-file' : 'BaseParallelApplication.log_to_file',
75 'log-to-file' : 'BaseParallelApplication.log_to_file',
75 'clean-logs' : 'BaseParallelApplication.clean_logs',
76 'clean-logs' : 'BaseParallelApplication.clean_logs',
76 'log-url' : 'BaseParallelApplication.log_url',
77 'log-url' : 'BaseParallelApplication.log_url',
77 'cluster-id' : 'BaseParallelApplication.cluster_id',
78 'cluster-id' : 'BaseParallelApplication.cluster_id',
78 })
79 })
79
80
80 base_flags = {
81 base_flags = {
81 'log-to-file' : (
82 'log-to-file' : (
82 {'BaseParallelApplication' : {'log_to_file' : True}},
83 {'BaseParallelApplication' : {'log_to_file' : True}},
83 "send log output to a file"
84 "send log output to a file"
84 )
85 )
85 }
86 }
86 base_flags.update(base_ip_flags)
87 base_flags.update(base_ip_flags)
87
88
88 class BaseParallelApplication(BaseIPythonApplication):
89 class BaseParallelApplication(BaseIPythonApplication):
89 """The base Application for IPython.parallel apps
90 """The base Application for IPython.parallel apps
90
91
91 Principle extensions to BaseIPyythonApplication:
92 Principle extensions to BaseIPyythonApplication:
92
93
93 * work_dir
94 * work_dir
94 * remote logging via pyzmq
95 * remote logging via pyzmq
95 * IOLoop instance
96 * IOLoop instance
96 """
97 """
97
98
98 crash_handler_class = ParallelCrashHandler
99 crash_handler_class = ParallelCrashHandler
99
100
100 def _log_level_default(self):
101 def _log_level_default(self):
101 # temporarily override default_log_level to INFO
102 # temporarily override default_log_level to INFO
102 return logging.INFO
103 return logging.INFO
103
104
104 def _log_format_default(self):
105 def _log_format_default(self):
105 """override default log format to include time"""
106 """override default log format to include time"""
106 return u"%(asctime)s.%(msecs).03d [%(name)s]%(highlevel)s %(message)s"
107 return u"%(asctime)s.%(msecs).03d [%(name)s]%(highlevel)s %(message)s"
107
108
108 work_dir = Unicode(os.getcwdu(), config=True,
109 work_dir = Unicode(py3compat.getcwd(), config=True,
109 help='Set the working dir for the process.'
110 help='Set the working dir for the process.'
110 )
111 )
111 def _work_dir_changed(self, name, old, new):
112 def _work_dir_changed(self, name, old, new):
112 self.work_dir = unicode_type(expand_path(new))
113 self.work_dir = unicode_type(expand_path(new))
113
114
114 log_to_file = Bool(config=True,
115 log_to_file = Bool(config=True,
115 help="whether to log to a file")
116 help="whether to log to a file")
116
117
117 clean_logs = Bool(False, config=True,
118 clean_logs = Bool(False, config=True,
118 help="whether to cleanup old logfiles before starting")
119 help="whether to cleanup old logfiles before starting")
119
120
120 log_url = Unicode('', config=True,
121 log_url = Unicode('', config=True,
121 help="The ZMQ URL of the iplogger to aggregate logging.")
122 help="The ZMQ URL of the iplogger to aggregate logging.")
122
123
123 cluster_id = Unicode('', config=True,
124 cluster_id = Unicode('', config=True,
124 help="""String id to add to runtime files, to prevent name collisions when
125 help="""String id to add to runtime files, to prevent name collisions when
125 using multiple clusters with a single profile simultaneously.
126 using multiple clusters with a single profile simultaneously.
126
127
127 When set, files will be named like: 'ipcontroller-<cluster_id>-engine.json'
128 When set, files will be named like: 'ipcontroller-<cluster_id>-engine.json'
128
129
129 Since this is text inserted into filenames, typical recommendations apply:
130 Since this is text inserted into filenames, typical recommendations apply:
130 Simple character strings are ideal, and spaces are not recommended (but should
131 Simple character strings are ideal, and spaces are not recommended (but should
131 generally work).
132 generally work).
132 """
133 """
133 )
134 )
134 def _cluster_id_changed(self, name, old, new):
135 def _cluster_id_changed(self, name, old, new):
135 self.name = self.__class__.name
136 self.name = self.__class__.name
136 if new:
137 if new:
137 self.name += '-%s'%new
138 self.name += '-%s'%new
138
139
139 def _config_files_default(self):
140 def _config_files_default(self):
140 return ['ipcontroller_config.py', 'ipengine_config.py', 'ipcluster_config.py']
141 return ['ipcontroller_config.py', 'ipengine_config.py', 'ipcluster_config.py']
141
142
142 loop = Instance('zmq.eventloop.ioloop.IOLoop')
143 loop = Instance('zmq.eventloop.ioloop.IOLoop')
143 def _loop_default(self):
144 def _loop_default(self):
144 from zmq.eventloop.ioloop import IOLoop
145 from zmq.eventloop.ioloop import IOLoop
145 return IOLoop.instance()
146 return IOLoop.instance()
146
147
147 aliases = Dict(base_aliases)
148 aliases = Dict(base_aliases)
148 flags = Dict(base_flags)
149 flags = Dict(base_flags)
149
150
150 @catch_config_error
151 @catch_config_error
151 def initialize(self, argv=None):
152 def initialize(self, argv=None):
152 """initialize the app"""
153 """initialize the app"""
153 super(BaseParallelApplication, self).initialize(argv)
154 super(BaseParallelApplication, self).initialize(argv)
154 self.to_work_dir()
155 self.to_work_dir()
155 self.reinit_logging()
156 self.reinit_logging()
156
157
157 def to_work_dir(self):
158 def to_work_dir(self):
158 wd = self.work_dir
159 wd = self.work_dir
159 if unicode_type(wd) != os.getcwdu():
160 if unicode_type(wd) != py3compat.getcwd():
160 os.chdir(wd)
161 os.chdir(wd)
161 self.log.info("Changing to working dir: %s" % wd)
162 self.log.info("Changing to working dir: %s" % wd)
162 # This is the working dir by now.
163 # This is the working dir by now.
163 sys.path.insert(0, '')
164 sys.path.insert(0, '')
164
165
165 def reinit_logging(self):
166 def reinit_logging(self):
166 # Remove old log files
167 # Remove old log files
167 log_dir = self.profile_dir.log_dir
168 log_dir = self.profile_dir.log_dir
168 if self.clean_logs:
169 if self.clean_logs:
169 for f in os.listdir(log_dir):
170 for f in os.listdir(log_dir):
170 if re.match(r'%s-\d+\.(log|err|out)' % self.name, f):
171 if re.match(r'%s-\d+\.(log|err|out)' % self.name, f):
171 try:
172 try:
172 os.remove(os.path.join(log_dir, f))
173 os.remove(os.path.join(log_dir, f))
173 except (OSError, IOError):
174 except (OSError, IOError):
174 # probably just conflict from sibling process
175 # probably just conflict from sibling process
175 # already removing it
176 # already removing it
176 pass
177 pass
177 if self.log_to_file:
178 if self.log_to_file:
178 # Start logging to the new log file
179 # Start logging to the new log file
179 log_filename = self.name + u'-' + str(os.getpid()) + u'.log'
180 log_filename = self.name + u'-' + str(os.getpid()) + u'.log'
180 logfile = os.path.join(log_dir, log_filename)
181 logfile = os.path.join(log_dir, log_filename)
181 open_log_file = open(logfile, 'w')
182 open_log_file = open(logfile, 'w')
182 else:
183 else:
183 open_log_file = None
184 open_log_file = None
184 if open_log_file is not None:
185 if open_log_file is not None:
185 while self.log.handlers:
186 while self.log.handlers:
186 self.log.removeHandler(self.log.handlers[0])
187 self.log.removeHandler(self.log.handlers[0])
187 self._log_handler = logging.StreamHandler(open_log_file)
188 self._log_handler = logging.StreamHandler(open_log_file)
188 self.log.addHandler(self._log_handler)
189 self.log.addHandler(self._log_handler)
189 else:
190 else:
190 self._log_handler = self.log.handlers[0]
191 self._log_handler = self.log.handlers[0]
191 # Add timestamps to log format:
192 # Add timestamps to log format:
192 self._log_formatter = LevelFormatter(self.log_format,
193 self._log_formatter = LevelFormatter(self.log_format,
193 datefmt=self.log_datefmt)
194 datefmt=self.log_datefmt)
194 self._log_handler.setFormatter(self._log_formatter)
195 self._log_handler.setFormatter(self._log_formatter)
195 # do not propagate log messages to root logger
196 # do not propagate log messages to root logger
196 # ipcluster app will sometimes print duplicate messages during shutdown
197 # ipcluster app will sometimes print duplicate messages during shutdown
197 # if this is 1 (default):
198 # if this is 1 (default):
198 self.log.propagate = False
199 self.log.propagate = False
199
200
200 def write_pid_file(self, overwrite=False):
201 def write_pid_file(self, overwrite=False):
201 """Create a .pid file in the pid_dir with my pid.
202 """Create a .pid file in the pid_dir with my pid.
202
203
203 This must be called after pre_construct, which sets `self.pid_dir`.
204 This must be called after pre_construct, which sets `self.pid_dir`.
204 This raises :exc:`PIDFileError` if the pid file exists already.
205 This raises :exc:`PIDFileError` if the pid file exists already.
205 """
206 """
206 pid_file = os.path.join(self.profile_dir.pid_dir, self.name + u'.pid')
207 pid_file = os.path.join(self.profile_dir.pid_dir, self.name + u'.pid')
207 if os.path.isfile(pid_file):
208 if os.path.isfile(pid_file):
208 pid = self.get_pid_from_file()
209 pid = self.get_pid_from_file()
209 if not overwrite:
210 if not overwrite:
210 raise PIDFileError(
211 raise PIDFileError(
211 'The pid file [%s] already exists. \nThis could mean that this '
212 'The pid file [%s] already exists. \nThis could mean that this '
212 'server is already running with [pid=%s].' % (pid_file, pid)
213 'server is already running with [pid=%s].' % (pid_file, pid)
213 )
214 )
214 with open(pid_file, 'w') as f:
215 with open(pid_file, 'w') as f:
215 self.log.info("Creating pid file: %s" % pid_file)
216 self.log.info("Creating pid file: %s" % pid_file)
216 f.write(repr(os.getpid())+'\n')
217 f.write(repr(os.getpid())+'\n')
217
218
218 def remove_pid_file(self):
219 def remove_pid_file(self):
219 """Remove the pid file.
220 """Remove the pid file.
220
221
221 This should be called at shutdown by registering a callback with
222 This should be called at shutdown by registering a callback with
222 :func:`reactor.addSystemEventTrigger`. This needs to return
223 :func:`reactor.addSystemEventTrigger`. This needs to return
223 ``None``.
224 ``None``.
224 """
225 """
225 pid_file = os.path.join(self.profile_dir.pid_dir, self.name + u'.pid')
226 pid_file = os.path.join(self.profile_dir.pid_dir, self.name + u'.pid')
226 if os.path.isfile(pid_file):
227 if os.path.isfile(pid_file):
227 try:
228 try:
228 self.log.info("Removing pid file: %s" % pid_file)
229 self.log.info("Removing pid file: %s" % pid_file)
229 os.remove(pid_file)
230 os.remove(pid_file)
230 except:
231 except:
231 self.log.warn("Error removing the pid file: %s" % pid_file)
232 self.log.warn("Error removing the pid file: %s" % pid_file)
232
233
233 def get_pid_from_file(self):
234 def get_pid_from_file(self):
234 """Get the pid from the pid file.
235 """Get the pid from the pid file.
235
236
236 If the pid file doesn't exist a :exc:`PIDFileError` is raised.
237 If the pid file doesn't exist a :exc:`PIDFileError` is raised.
237 """
238 """
238 pid_file = os.path.join(self.profile_dir.pid_dir, self.name + u'.pid')
239 pid_file = os.path.join(self.profile_dir.pid_dir, self.name + u'.pid')
239 if os.path.isfile(pid_file):
240 if os.path.isfile(pid_file):
240 with open(pid_file, 'r') as f:
241 with open(pid_file, 'r') as f:
241 s = f.read().strip()
242 s = f.read().strip()
242 try:
243 try:
243 pid = int(s)
244 pid = int(s)
244 except:
245 except:
245 raise PIDFileError("invalid pid file: %s (contents: %r)"%(pid_file, s))
246 raise PIDFileError("invalid pid file: %s (contents: %r)"%(pid_file, s))
246 return pid
247 return pid
247 else:
248 else:
248 raise PIDFileError('pid file not found: %s' % pid_file)
249 raise PIDFileError('pid file not found: %s' % pid_file)
249
250
250 def check_pid(self, pid):
251 def check_pid(self, pid):
251 if os.name == 'nt':
252 if os.name == 'nt':
252 try:
253 try:
253 import ctypes
254 import ctypes
254 # returns 0 if no such process (of ours) exists
255 # returns 0 if no such process (of ours) exists
255 # positive int otherwise
256 # positive int otherwise
256 p = ctypes.windll.kernel32.OpenProcess(1,0,pid)
257 p = ctypes.windll.kernel32.OpenProcess(1,0,pid)
257 except Exception:
258 except Exception:
258 self.log.warn(
259 self.log.warn(
259 "Could not determine whether pid %i is running via `OpenProcess`. "
260 "Could not determine whether pid %i is running via `OpenProcess`. "
260 " Making the likely assumption that it is."%pid
261 " Making the likely assumption that it is."%pid
261 )
262 )
262 return True
263 return True
263 return bool(p)
264 return bool(p)
264 else:
265 else:
265 try:
266 try:
266 p = Popen(['ps','x'], stdout=PIPE, stderr=PIPE)
267 p = Popen(['ps','x'], stdout=PIPE, stderr=PIPE)
267 output,_ = p.communicate()
268 output,_ = p.communicate()
268 except OSError:
269 except OSError:
269 self.log.warn(
270 self.log.warn(
270 "Could not determine whether pid %i is running via `ps x`. "
271 "Could not determine whether pid %i is running via `ps x`. "
271 " Making the likely assumption that it is."%pid
272 " Making the likely assumption that it is."%pid
272 )
273 )
273 return True
274 return True
274 pids = list(map(int, re.findall(r'^\W*\d+', output, re.MULTILINE)))
275 pids = list(map(int, re.findall(r'^\W*\d+', output, re.MULTILINE)))
275 return pid in pids
276 return pid in pids
@@ -1,764 +1,764 b''
1 """Nose Plugin that supports IPython doctests.
1 """Nose Plugin that supports IPython doctests.
2
2
3 Limitations:
3 Limitations:
4
4
5 - When generating examples for use as doctests, make sure that you have
5 - When generating examples for use as doctests, make sure that you have
6 pretty-printing OFF. This can be done either by setting the
6 pretty-printing OFF. This can be done either by setting the
7 ``PlainTextFormatter.pprint`` option in your configuration file to False, or
7 ``PlainTextFormatter.pprint`` option in your configuration file to False, or
8 by interactively disabling it with %Pprint. This is required so that IPython
8 by interactively disabling it with %Pprint. This is required so that IPython
9 output matches that of normal Python, which is used by doctest for internal
9 output matches that of normal Python, which is used by doctest for internal
10 execution.
10 execution.
11
11
12 - Do not rely on specific prompt numbers for results (such as using
12 - Do not rely on specific prompt numbers for results (such as using
13 '_34==True', for example). For IPython tests run via an external process the
13 '_34==True', for example). For IPython tests run via an external process the
14 prompt numbers may be different, and IPython tests run as normal python code
14 prompt numbers may be different, and IPython tests run as normal python code
15 won't even have these special _NN variables set at all.
15 won't even have these special _NN variables set at all.
16 """
16 """
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Module imports
19 # Module imports
20
20
21 # From the standard library
21 # From the standard library
22 import doctest
22 import doctest
23 import inspect
23 import inspect
24 import logging
24 import logging
25 import os
25 import os
26 import re
26 import re
27 import sys
27 import sys
28 import traceback
28 import traceback
29 import unittest
29 import unittest
30
30
31 from inspect import getmodule
31 from inspect import getmodule
32
32
33 # We are overriding the default doctest runner, so we need to import a few
33 # We are overriding the default doctest runner, so we need to import a few
34 # things from doctest directly
34 # things from doctest directly
35 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
35 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
36 _unittest_reportflags, DocTestRunner,
36 _unittest_reportflags, DocTestRunner,
37 _extract_future_flags, pdb, _OutputRedirectingPdb,
37 _extract_future_flags, pdb, _OutputRedirectingPdb,
38 _exception_traceback,
38 _exception_traceback,
39 linecache)
39 linecache)
40
40
41 # Third-party modules
41 # Third-party modules
42 import nose.core
42 import nose.core
43
43
44 from nose.plugins import doctests, Plugin
44 from nose.plugins import doctests, Plugin
45 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
45 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
46
46
47 # Our own imports
47 # Our own imports
48 from IPython.utils.py3compat import builtin_mod, PY3
48 from IPython.utils.py3compat import builtin_mod, PY3, getcwd
49
49
50 if PY3:
50 if PY3:
51 from io import StringIO
51 from io import StringIO
52 else:
52 else:
53 from StringIO import StringIO
53 from StringIO import StringIO
54
54
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56 # Module globals and other constants
56 # Module globals and other constants
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58
58
59 log = logging.getLogger(__name__)
59 log = logging.getLogger(__name__)
60
60
61
61
62 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
63 # Classes and functions
63 # Classes and functions
64 #-----------------------------------------------------------------------------
64 #-----------------------------------------------------------------------------
65
65
66 def is_extension_module(filename):
66 def is_extension_module(filename):
67 """Return whether the given filename is an extension module.
67 """Return whether the given filename is an extension module.
68
68
69 This simply checks that the extension is either .so or .pyd.
69 This simply checks that the extension is either .so or .pyd.
70 """
70 """
71 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
71 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
72
72
73
73
74 class DocTestSkip(object):
74 class DocTestSkip(object):
75 """Object wrapper for doctests to be skipped."""
75 """Object wrapper for doctests to be skipped."""
76
76
77 ds_skip = """Doctest to skip.
77 ds_skip = """Doctest to skip.
78 >>> 1 #doctest: +SKIP
78 >>> 1 #doctest: +SKIP
79 """
79 """
80
80
81 def __init__(self,obj):
81 def __init__(self,obj):
82 self.obj = obj
82 self.obj = obj
83
83
84 def __getattribute__(self,key):
84 def __getattribute__(self,key):
85 if key == '__doc__':
85 if key == '__doc__':
86 return DocTestSkip.ds_skip
86 return DocTestSkip.ds_skip
87 else:
87 else:
88 return getattr(object.__getattribute__(self,'obj'),key)
88 return getattr(object.__getattribute__(self,'obj'),key)
89
89
90 # Modified version of the one in the stdlib, that fixes a python bug (doctests
90 # Modified version of the one in the stdlib, that fixes a python bug (doctests
91 # not found in extension modules, http://bugs.python.org/issue3158)
91 # not found in extension modules, http://bugs.python.org/issue3158)
92 class DocTestFinder(doctest.DocTestFinder):
92 class DocTestFinder(doctest.DocTestFinder):
93
93
94 def _from_module(self, module, object):
94 def _from_module(self, module, object):
95 """
95 """
96 Return true if the given object is defined in the given
96 Return true if the given object is defined in the given
97 module.
97 module.
98 """
98 """
99 if module is None:
99 if module is None:
100 return True
100 return True
101 elif inspect.isfunction(object):
101 elif inspect.isfunction(object):
102 return module.__dict__ is object.__globals__
102 return module.__dict__ is object.__globals__
103 elif inspect.isbuiltin(object):
103 elif inspect.isbuiltin(object):
104 return module.__name__ == object.__module__
104 return module.__name__ == object.__module__
105 elif inspect.isclass(object):
105 elif inspect.isclass(object):
106 return module.__name__ == object.__module__
106 return module.__name__ == object.__module__
107 elif inspect.ismethod(object):
107 elif inspect.ismethod(object):
108 # This one may be a bug in cython that fails to correctly set the
108 # This one may be a bug in cython that fails to correctly set the
109 # __module__ attribute of methods, but since the same error is easy
109 # __module__ attribute of methods, but since the same error is easy
110 # to make by extension code writers, having this safety in place
110 # to make by extension code writers, having this safety in place
111 # isn't such a bad idea
111 # isn't such a bad idea
112 return module.__name__ == object.__self__.__class__.__module__
112 return module.__name__ == object.__self__.__class__.__module__
113 elif inspect.getmodule(object) is not None:
113 elif inspect.getmodule(object) is not None:
114 return module is inspect.getmodule(object)
114 return module is inspect.getmodule(object)
115 elif hasattr(object, '__module__'):
115 elif hasattr(object, '__module__'):
116 return module.__name__ == object.__module__
116 return module.__name__ == object.__module__
117 elif isinstance(object, property):
117 elif isinstance(object, property):
118 return True # [XX] no way not be sure.
118 return True # [XX] no way not be sure.
119 else:
119 else:
120 raise ValueError("object must be a class or function, got %r" % object)
120 raise ValueError("object must be a class or function, got %r" % object)
121
121
122 def _find(self, tests, obj, name, module, source_lines, globs, seen):
122 def _find(self, tests, obj, name, module, source_lines, globs, seen):
123 """
123 """
124 Find tests for the given object and any contained objects, and
124 Find tests for the given object and any contained objects, and
125 add them to `tests`.
125 add them to `tests`.
126 """
126 """
127 #print '_find for:', obj, name, module # dbg
127 #print '_find for:', obj, name, module # dbg
128 if hasattr(obj,"skip_doctest"):
128 if hasattr(obj,"skip_doctest"):
129 #print 'SKIPPING DOCTEST FOR:',obj # dbg
129 #print 'SKIPPING DOCTEST FOR:',obj # dbg
130 obj = DocTestSkip(obj)
130 obj = DocTestSkip(obj)
131
131
132 doctest.DocTestFinder._find(self,tests, obj, name, module,
132 doctest.DocTestFinder._find(self,tests, obj, name, module,
133 source_lines, globs, seen)
133 source_lines, globs, seen)
134
134
135 # Below we re-run pieces of the above method with manual modifications,
135 # Below we re-run pieces of the above method with manual modifications,
136 # because the original code is buggy and fails to correctly identify
136 # because the original code is buggy and fails to correctly identify
137 # doctests in extension modules.
137 # doctests in extension modules.
138
138
139 # Local shorthands
139 # Local shorthands
140 from inspect import isroutine, isclass, ismodule
140 from inspect import isroutine, isclass, ismodule
141
141
142 # Look for tests in a module's contained objects.
142 # Look for tests in a module's contained objects.
143 if inspect.ismodule(obj) and self._recurse:
143 if inspect.ismodule(obj) and self._recurse:
144 for valname, val in obj.__dict__.items():
144 for valname, val in obj.__dict__.items():
145 valname1 = '%s.%s' % (name, valname)
145 valname1 = '%s.%s' % (name, valname)
146 if ( (isroutine(val) or isclass(val))
146 if ( (isroutine(val) or isclass(val))
147 and self._from_module(module, val) ):
147 and self._from_module(module, val) ):
148
148
149 self._find(tests, val, valname1, module, source_lines,
149 self._find(tests, val, valname1, module, source_lines,
150 globs, seen)
150 globs, seen)
151
151
152 # Look for tests in a class's contained objects.
152 # Look for tests in a class's contained objects.
153 if inspect.isclass(obj) and self._recurse:
153 if inspect.isclass(obj) and self._recurse:
154 #print 'RECURSE into class:',obj # dbg
154 #print 'RECURSE into class:',obj # dbg
155 for valname, val in obj.__dict__.items():
155 for valname, val in obj.__dict__.items():
156 # Special handling for staticmethod/classmethod.
156 # Special handling for staticmethod/classmethod.
157 if isinstance(val, staticmethod):
157 if isinstance(val, staticmethod):
158 val = getattr(obj, valname)
158 val = getattr(obj, valname)
159 if isinstance(val, classmethod):
159 if isinstance(val, classmethod):
160 val = getattr(obj, valname).__func__
160 val = getattr(obj, valname).__func__
161
161
162 # Recurse to methods, properties, and nested classes.
162 # Recurse to methods, properties, and nested classes.
163 if ((inspect.isfunction(val) or inspect.isclass(val) or
163 if ((inspect.isfunction(val) or inspect.isclass(val) or
164 inspect.ismethod(val) or
164 inspect.ismethod(val) or
165 isinstance(val, property)) and
165 isinstance(val, property)) and
166 self._from_module(module, val)):
166 self._from_module(module, val)):
167 valname = '%s.%s' % (name, valname)
167 valname = '%s.%s' % (name, valname)
168 self._find(tests, val, valname, module, source_lines,
168 self._find(tests, val, valname, module, source_lines,
169 globs, seen)
169 globs, seen)
170
170
171
171
172 class IPDoctestOutputChecker(doctest.OutputChecker):
172 class IPDoctestOutputChecker(doctest.OutputChecker):
173 """Second-chance checker with support for random tests.
173 """Second-chance checker with support for random tests.
174
174
175 If the default comparison doesn't pass, this checker looks in the expected
175 If the default comparison doesn't pass, this checker looks in the expected
176 output string for flags that tell us to ignore the output.
176 output string for flags that tell us to ignore the output.
177 """
177 """
178
178
179 random_re = re.compile(r'#\s*random\s+')
179 random_re = re.compile(r'#\s*random\s+')
180
180
181 def check_output(self, want, got, optionflags):
181 def check_output(self, want, got, optionflags):
182 """Check output, accepting special markers embedded in the output.
182 """Check output, accepting special markers embedded in the output.
183
183
184 If the output didn't pass the default validation but the special string
184 If the output didn't pass the default validation but the special string
185 '#random' is included, we accept it."""
185 '#random' is included, we accept it."""
186
186
187 # Let the original tester verify first, in case people have valid tests
187 # Let the original tester verify first, in case people have valid tests
188 # that happen to have a comment saying '#random' embedded in.
188 # that happen to have a comment saying '#random' embedded in.
189 ret = doctest.OutputChecker.check_output(self, want, got,
189 ret = doctest.OutputChecker.check_output(self, want, got,
190 optionflags)
190 optionflags)
191 if not ret and self.random_re.search(want):
191 if not ret and self.random_re.search(want):
192 #print >> sys.stderr, 'RANDOM OK:',want # dbg
192 #print >> sys.stderr, 'RANDOM OK:',want # dbg
193 return True
193 return True
194
194
195 return ret
195 return ret
196
196
197
197
198 class DocTestCase(doctests.DocTestCase):
198 class DocTestCase(doctests.DocTestCase):
199 """Proxy for DocTestCase: provides an address() method that
199 """Proxy for DocTestCase: provides an address() method that
200 returns the correct address for the doctest case. Otherwise
200 returns the correct address for the doctest case. Otherwise
201 acts as a proxy to the test case. To provide hints for address(),
201 acts as a proxy to the test case. To provide hints for address(),
202 an obj may also be passed -- this will be used as the test object
202 an obj may also be passed -- this will be used as the test object
203 for purposes of determining the test address, if it is provided.
203 for purposes of determining the test address, if it is provided.
204 """
204 """
205
205
206 # Note: this method was taken from numpy's nosetester module.
206 # Note: this method was taken from numpy's nosetester module.
207
207
208 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
208 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
209 # its constructor that blocks non-default arguments from being passed
209 # its constructor that blocks non-default arguments from being passed
210 # down into doctest.DocTestCase
210 # down into doctest.DocTestCase
211
211
212 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
212 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
213 checker=None, obj=None, result_var='_'):
213 checker=None, obj=None, result_var='_'):
214 self._result_var = result_var
214 self._result_var = result_var
215 doctests.DocTestCase.__init__(self, test,
215 doctests.DocTestCase.__init__(self, test,
216 optionflags=optionflags,
216 optionflags=optionflags,
217 setUp=setUp, tearDown=tearDown,
217 setUp=setUp, tearDown=tearDown,
218 checker=checker)
218 checker=checker)
219 # Now we must actually copy the original constructor from the stdlib
219 # Now we must actually copy the original constructor from the stdlib
220 # doctest class, because we can't call it directly and a bug in nose
220 # doctest class, because we can't call it directly and a bug in nose
221 # means it never gets passed the right arguments.
221 # means it never gets passed the right arguments.
222
222
223 self._dt_optionflags = optionflags
223 self._dt_optionflags = optionflags
224 self._dt_checker = checker
224 self._dt_checker = checker
225 self._dt_test = test
225 self._dt_test = test
226 self._dt_test_globs_ori = test.globs
226 self._dt_test_globs_ori = test.globs
227 self._dt_setUp = setUp
227 self._dt_setUp = setUp
228 self._dt_tearDown = tearDown
228 self._dt_tearDown = tearDown
229
229
230 # XXX - store this runner once in the object!
230 # XXX - store this runner once in the object!
231 runner = IPDocTestRunner(optionflags=optionflags,
231 runner = IPDocTestRunner(optionflags=optionflags,
232 checker=checker, verbose=False)
232 checker=checker, verbose=False)
233 self._dt_runner = runner
233 self._dt_runner = runner
234
234
235
235
236 # Each doctest should remember the directory it was loaded from, so
236 # Each doctest should remember the directory it was loaded from, so
237 # things like %run work without too many contortions
237 # things like %run work without too many contortions
238 self._ori_dir = os.path.dirname(test.filename)
238 self._ori_dir = os.path.dirname(test.filename)
239
239
240 # Modified runTest from the default stdlib
240 # Modified runTest from the default stdlib
241 def runTest(self):
241 def runTest(self):
242 test = self._dt_test
242 test = self._dt_test
243 runner = self._dt_runner
243 runner = self._dt_runner
244
244
245 old = sys.stdout
245 old = sys.stdout
246 new = StringIO()
246 new = StringIO()
247 optionflags = self._dt_optionflags
247 optionflags = self._dt_optionflags
248
248
249 if not (optionflags & REPORTING_FLAGS):
249 if not (optionflags & REPORTING_FLAGS):
250 # The option flags don't include any reporting flags,
250 # The option flags don't include any reporting flags,
251 # so add the default reporting flags
251 # so add the default reporting flags
252 optionflags |= _unittest_reportflags
252 optionflags |= _unittest_reportflags
253
253
254 try:
254 try:
255 # Save our current directory and switch out to the one where the
255 # Save our current directory and switch out to the one where the
256 # test was originally created, in case another doctest did a
256 # test was originally created, in case another doctest did a
257 # directory change. We'll restore this in the finally clause.
257 # directory change. We'll restore this in the finally clause.
258 curdir = os.getcwdu()
258 curdir = getcwd()
259 #print 'runTest in dir:', self._ori_dir # dbg
259 #print 'runTest in dir:', self._ori_dir # dbg
260 os.chdir(self._ori_dir)
260 os.chdir(self._ori_dir)
261
261
262 runner.DIVIDER = "-"*70
262 runner.DIVIDER = "-"*70
263 failures, tries = runner.run(test,out=new.write,
263 failures, tries = runner.run(test,out=new.write,
264 clear_globs=False)
264 clear_globs=False)
265 finally:
265 finally:
266 sys.stdout = old
266 sys.stdout = old
267 os.chdir(curdir)
267 os.chdir(curdir)
268
268
269 if failures:
269 if failures:
270 raise self.failureException(self.format_failure(new.getvalue()))
270 raise self.failureException(self.format_failure(new.getvalue()))
271
271
272 def setUp(self):
272 def setUp(self):
273 """Modified test setup that syncs with ipython namespace"""
273 """Modified test setup that syncs with ipython namespace"""
274 #print "setUp test", self._dt_test.examples # dbg
274 #print "setUp test", self._dt_test.examples # dbg
275 if isinstance(self._dt_test.examples[0], IPExample):
275 if isinstance(self._dt_test.examples[0], IPExample):
276 # for IPython examples *only*, we swap the globals with the ipython
276 # for IPython examples *only*, we swap the globals with the ipython
277 # namespace, after updating it with the globals (which doctest
277 # namespace, after updating it with the globals (which doctest
278 # fills with the necessary info from the module being tested).
278 # fills with the necessary info from the module being tested).
279 self.user_ns_orig = {}
279 self.user_ns_orig = {}
280 self.user_ns_orig.update(_ip.user_ns)
280 self.user_ns_orig.update(_ip.user_ns)
281 _ip.user_ns.update(self._dt_test.globs)
281 _ip.user_ns.update(self._dt_test.globs)
282 # We must remove the _ key in the namespace, so that Python's
282 # We must remove the _ key in the namespace, so that Python's
283 # doctest code sets it naturally
283 # doctest code sets it naturally
284 _ip.user_ns.pop('_', None)
284 _ip.user_ns.pop('_', None)
285 _ip.user_ns['__builtins__'] = builtin_mod
285 _ip.user_ns['__builtins__'] = builtin_mod
286 self._dt_test.globs = _ip.user_ns
286 self._dt_test.globs = _ip.user_ns
287
287
288 super(DocTestCase, self).setUp()
288 super(DocTestCase, self).setUp()
289
289
290 def tearDown(self):
290 def tearDown(self):
291
291
292 # Undo the test.globs reassignment we made, so that the parent class
292 # Undo the test.globs reassignment we made, so that the parent class
293 # teardown doesn't destroy the ipython namespace
293 # teardown doesn't destroy the ipython namespace
294 if isinstance(self._dt_test.examples[0], IPExample):
294 if isinstance(self._dt_test.examples[0], IPExample):
295 self._dt_test.globs = self._dt_test_globs_ori
295 self._dt_test.globs = self._dt_test_globs_ori
296 _ip.user_ns.clear()
296 _ip.user_ns.clear()
297 _ip.user_ns.update(self.user_ns_orig)
297 _ip.user_ns.update(self.user_ns_orig)
298
298
299 # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
299 # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
300 # it does look like one to me: its tearDown method tries to run
300 # it does look like one to me: its tearDown method tries to run
301 #
301 #
302 # delattr(builtin_mod, self._result_var)
302 # delattr(builtin_mod, self._result_var)
303 #
303 #
304 # without checking that the attribute really is there; it implicitly
304 # without checking that the attribute really is there; it implicitly
305 # assumes it should have been set via displayhook. But if the
305 # assumes it should have been set via displayhook. But if the
306 # displayhook was never called, this doesn't necessarily happen. I
306 # displayhook was never called, this doesn't necessarily happen. I
307 # haven't been able to find a little self-contained example outside of
307 # haven't been able to find a little self-contained example outside of
308 # ipython that would show the problem so I can report it to the nose
308 # ipython that would show the problem so I can report it to the nose
309 # team, but it does happen a lot in our code.
309 # team, but it does happen a lot in our code.
310 #
310 #
311 # So here, we just protect as narrowly as possible by trapping an
311 # So here, we just protect as narrowly as possible by trapping an
312 # attribute error whose message would be the name of self._result_var,
312 # attribute error whose message would be the name of self._result_var,
313 # and letting any other error propagate.
313 # and letting any other error propagate.
314 try:
314 try:
315 super(DocTestCase, self).tearDown()
315 super(DocTestCase, self).tearDown()
316 except AttributeError as exc:
316 except AttributeError as exc:
317 if exc.args[0] != self._result_var:
317 if exc.args[0] != self._result_var:
318 raise
318 raise
319
319
320
320
321 # A simple subclassing of the original with a different class name, so we can
321 # A simple subclassing of the original with a different class name, so we can
322 # distinguish and treat differently IPython examples from pure python ones.
322 # distinguish and treat differently IPython examples from pure python ones.
323 class IPExample(doctest.Example): pass
323 class IPExample(doctest.Example): pass
324
324
325
325
326 class IPExternalExample(doctest.Example):
326 class IPExternalExample(doctest.Example):
327 """Doctest examples to be run in an external process."""
327 """Doctest examples to be run in an external process."""
328
328
329 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
329 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
330 options=None):
330 options=None):
331 # Parent constructor
331 # Parent constructor
332 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
332 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
333
333
334 # An EXTRA newline is needed to prevent pexpect hangs
334 # An EXTRA newline is needed to prevent pexpect hangs
335 self.source += '\n'
335 self.source += '\n'
336
336
337
337
338 class IPDocTestParser(doctest.DocTestParser):
338 class IPDocTestParser(doctest.DocTestParser):
339 """
339 """
340 A class used to parse strings containing doctest examples.
340 A class used to parse strings containing doctest examples.
341
341
342 Note: This is a version modified to properly recognize IPython input and
342 Note: This is a version modified to properly recognize IPython input and
343 convert any IPython examples into valid Python ones.
343 convert any IPython examples into valid Python ones.
344 """
344 """
345 # This regular expression is used to find doctest examples in a
345 # This regular expression is used to find doctest examples in a
346 # string. It defines three groups: `source` is the source code
346 # string. It defines three groups: `source` is the source code
347 # (including leading indentation and prompts); `indent` is the
347 # (including leading indentation and prompts); `indent` is the
348 # indentation of the first (PS1) line of the source code; and
348 # indentation of the first (PS1) line of the source code; and
349 # `want` is the expected output (including leading indentation).
349 # `want` is the expected output (including leading indentation).
350
350
351 # Classic Python prompts or default IPython ones
351 # Classic Python prompts or default IPython ones
352 _PS1_PY = r'>>>'
352 _PS1_PY = r'>>>'
353 _PS2_PY = r'\.\.\.'
353 _PS2_PY = r'\.\.\.'
354
354
355 _PS1_IP = r'In\ \[\d+\]:'
355 _PS1_IP = r'In\ \[\d+\]:'
356 _PS2_IP = r'\ \ \ \.\.\.+:'
356 _PS2_IP = r'\ \ \ \.\.\.+:'
357
357
358 _RE_TPL = r'''
358 _RE_TPL = r'''
359 # Source consists of a PS1 line followed by zero or more PS2 lines.
359 # Source consists of a PS1 line followed by zero or more PS2 lines.
360 (?P<source>
360 (?P<source>
361 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
361 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
362 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
362 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
363 \n? # a newline
363 \n? # a newline
364 # Want consists of any non-blank lines that do not start with PS1.
364 # Want consists of any non-blank lines that do not start with PS1.
365 (?P<want> (?:(?![ ]*$) # Not a blank line
365 (?P<want> (?:(?![ ]*$) # Not a blank line
366 (?![ ]*%s) # Not a line starting with PS1
366 (?![ ]*%s) # Not a line starting with PS1
367 (?![ ]*%s) # Not a line starting with PS2
367 (?![ ]*%s) # Not a line starting with PS2
368 .*$\n? # But any other line
368 .*$\n? # But any other line
369 )*)
369 )*)
370 '''
370 '''
371
371
372 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
372 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
373 re.MULTILINE | re.VERBOSE)
373 re.MULTILINE | re.VERBOSE)
374
374
375 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
375 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
376 re.MULTILINE | re.VERBOSE)
376 re.MULTILINE | re.VERBOSE)
377
377
378 # Mark a test as being fully random. In this case, we simply append the
378 # Mark a test as being fully random. In this case, we simply append the
379 # random marker ('#random') to each individual example's output. This way
379 # random marker ('#random') to each individual example's output. This way
380 # we don't need to modify any other code.
380 # we don't need to modify any other code.
381 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
381 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
382
382
383 # Mark tests to be executed in an external process - currently unsupported.
383 # Mark tests to be executed in an external process - currently unsupported.
384 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
384 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
385
385
386 def ip2py(self,source):
386 def ip2py(self,source):
387 """Convert input IPython source into valid Python."""
387 """Convert input IPython source into valid Python."""
388 block = _ip.input_transformer_manager.transform_cell(source)
388 block = _ip.input_transformer_manager.transform_cell(source)
389 if len(block.splitlines()) == 1:
389 if len(block.splitlines()) == 1:
390 return _ip.prefilter(block)
390 return _ip.prefilter(block)
391 else:
391 else:
392 return block
392 return block
393
393
394 def parse(self, string, name='<string>'):
394 def parse(self, string, name='<string>'):
395 """
395 """
396 Divide the given string into examples and intervening text,
396 Divide the given string into examples and intervening text,
397 and return them as a list of alternating Examples and strings.
397 and return them as a list of alternating Examples and strings.
398 Line numbers for the Examples are 0-based. The optional
398 Line numbers for the Examples are 0-based. The optional
399 argument `name` is a name identifying this string, and is only
399 argument `name` is a name identifying this string, and is only
400 used for error messages.
400 used for error messages.
401 """
401 """
402
402
403 #print 'Parse string:\n',string # dbg
403 #print 'Parse string:\n',string # dbg
404
404
405 string = string.expandtabs()
405 string = string.expandtabs()
406 # If all lines begin with the same indentation, then strip it.
406 # If all lines begin with the same indentation, then strip it.
407 min_indent = self._min_indent(string)
407 min_indent = self._min_indent(string)
408 if min_indent > 0:
408 if min_indent > 0:
409 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
409 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
410
410
411 output = []
411 output = []
412 charno, lineno = 0, 0
412 charno, lineno = 0, 0
413
413
414 # We make 'all random' tests by adding the '# random' mark to every
414 # We make 'all random' tests by adding the '# random' mark to every
415 # block of output in the test.
415 # block of output in the test.
416 if self._RANDOM_TEST.search(string):
416 if self._RANDOM_TEST.search(string):
417 random_marker = '\n# random'
417 random_marker = '\n# random'
418 else:
418 else:
419 random_marker = ''
419 random_marker = ''
420
420
421 # Whether to convert the input from ipython to python syntax
421 # Whether to convert the input from ipython to python syntax
422 ip2py = False
422 ip2py = False
423 # Find all doctest examples in the string. First, try them as Python
423 # Find all doctest examples in the string. First, try them as Python
424 # examples, then as IPython ones
424 # examples, then as IPython ones
425 terms = list(self._EXAMPLE_RE_PY.finditer(string))
425 terms = list(self._EXAMPLE_RE_PY.finditer(string))
426 if terms:
426 if terms:
427 # Normal Python example
427 # Normal Python example
428 #print '-'*70 # dbg
428 #print '-'*70 # dbg
429 #print 'PyExample, Source:\n',string # dbg
429 #print 'PyExample, Source:\n',string # dbg
430 #print '-'*70 # dbg
430 #print '-'*70 # dbg
431 Example = doctest.Example
431 Example = doctest.Example
432 else:
432 else:
433 # It's an ipython example. Note that IPExamples are run
433 # It's an ipython example. Note that IPExamples are run
434 # in-process, so their syntax must be turned into valid python.
434 # in-process, so their syntax must be turned into valid python.
435 # IPExternalExamples are run out-of-process (via pexpect) so they
435 # IPExternalExamples are run out-of-process (via pexpect) so they
436 # don't need any filtering (a real ipython will be executing them).
436 # don't need any filtering (a real ipython will be executing them).
437 terms = list(self._EXAMPLE_RE_IP.finditer(string))
437 terms = list(self._EXAMPLE_RE_IP.finditer(string))
438 if self._EXTERNAL_IP.search(string):
438 if self._EXTERNAL_IP.search(string):
439 #print '-'*70 # dbg
439 #print '-'*70 # dbg
440 #print 'IPExternalExample, Source:\n',string # dbg
440 #print 'IPExternalExample, Source:\n',string # dbg
441 #print '-'*70 # dbg
441 #print '-'*70 # dbg
442 Example = IPExternalExample
442 Example = IPExternalExample
443 else:
443 else:
444 #print '-'*70 # dbg
444 #print '-'*70 # dbg
445 #print 'IPExample, Source:\n',string # dbg
445 #print 'IPExample, Source:\n',string # dbg
446 #print '-'*70 # dbg
446 #print '-'*70 # dbg
447 Example = IPExample
447 Example = IPExample
448 ip2py = True
448 ip2py = True
449
449
450 for m in terms:
450 for m in terms:
451 # Add the pre-example text to `output`.
451 # Add the pre-example text to `output`.
452 output.append(string[charno:m.start()])
452 output.append(string[charno:m.start()])
453 # Update lineno (lines before this example)
453 # Update lineno (lines before this example)
454 lineno += string.count('\n', charno, m.start())
454 lineno += string.count('\n', charno, m.start())
455 # Extract info from the regexp match.
455 # Extract info from the regexp match.
456 (source, options, want, exc_msg) = \
456 (source, options, want, exc_msg) = \
457 self._parse_example(m, name, lineno,ip2py)
457 self._parse_example(m, name, lineno,ip2py)
458
458
459 # Append the random-output marker (it defaults to empty in most
459 # Append the random-output marker (it defaults to empty in most
460 # cases, it's only non-empty for 'all-random' tests):
460 # cases, it's only non-empty for 'all-random' tests):
461 want += random_marker
461 want += random_marker
462
462
463 if Example is IPExternalExample:
463 if Example is IPExternalExample:
464 options[doctest.NORMALIZE_WHITESPACE] = True
464 options[doctest.NORMALIZE_WHITESPACE] = True
465 want += '\n'
465 want += '\n'
466
466
467 # Create an Example, and add it to the list.
467 # Create an Example, and add it to the list.
468 if not self._IS_BLANK_OR_COMMENT(source):
468 if not self._IS_BLANK_OR_COMMENT(source):
469 output.append(Example(source, want, exc_msg,
469 output.append(Example(source, want, exc_msg,
470 lineno=lineno,
470 lineno=lineno,
471 indent=min_indent+len(m.group('indent')),
471 indent=min_indent+len(m.group('indent')),
472 options=options))
472 options=options))
473 # Update lineno (lines inside this example)
473 # Update lineno (lines inside this example)
474 lineno += string.count('\n', m.start(), m.end())
474 lineno += string.count('\n', m.start(), m.end())
475 # Update charno.
475 # Update charno.
476 charno = m.end()
476 charno = m.end()
477 # Add any remaining post-example text to `output`.
477 # Add any remaining post-example text to `output`.
478 output.append(string[charno:])
478 output.append(string[charno:])
479 return output
479 return output
480
480
481 def _parse_example(self, m, name, lineno,ip2py=False):
481 def _parse_example(self, m, name, lineno,ip2py=False):
482 """
482 """
483 Given a regular expression match from `_EXAMPLE_RE` (`m`),
483 Given a regular expression match from `_EXAMPLE_RE` (`m`),
484 return a pair `(source, want)`, where `source` is the matched
484 return a pair `(source, want)`, where `source` is the matched
485 example's source code (with prompts and indentation stripped);
485 example's source code (with prompts and indentation stripped);
486 and `want` is the example's expected output (with indentation
486 and `want` is the example's expected output (with indentation
487 stripped).
487 stripped).
488
488
489 `name` is the string's name, and `lineno` is the line number
489 `name` is the string's name, and `lineno` is the line number
490 where the example starts; both are used for error messages.
490 where the example starts; both are used for error messages.
491
491
492 Optional:
492 Optional:
493 `ip2py`: if true, filter the input via IPython to convert the syntax
493 `ip2py`: if true, filter the input via IPython to convert the syntax
494 into valid python.
494 into valid python.
495 """
495 """
496
496
497 # Get the example's indentation level.
497 # Get the example's indentation level.
498 indent = len(m.group('indent'))
498 indent = len(m.group('indent'))
499
499
500 # Divide source into lines; check that they're properly
500 # Divide source into lines; check that they're properly
501 # indented; and then strip their indentation & prompts.
501 # indented; and then strip their indentation & prompts.
502 source_lines = m.group('source').split('\n')
502 source_lines = m.group('source').split('\n')
503
503
504 # We're using variable-length input prompts
504 # We're using variable-length input prompts
505 ps1 = m.group('ps1')
505 ps1 = m.group('ps1')
506 ps2 = m.group('ps2')
506 ps2 = m.group('ps2')
507 ps1_len = len(ps1)
507 ps1_len = len(ps1)
508
508
509 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
509 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
510 if ps2:
510 if ps2:
511 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
511 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
512
512
513 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
513 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
514
514
515 if ip2py:
515 if ip2py:
516 # Convert source input from IPython into valid Python syntax
516 # Convert source input from IPython into valid Python syntax
517 source = self.ip2py(source)
517 source = self.ip2py(source)
518
518
519 # Divide want into lines; check that it's properly indented; and
519 # Divide want into lines; check that it's properly indented; and
520 # then strip the indentation. Spaces before the last newline should
520 # then strip the indentation. Spaces before the last newline should
521 # be preserved, so plain rstrip() isn't good enough.
521 # be preserved, so plain rstrip() isn't good enough.
522 want = m.group('want')
522 want = m.group('want')
523 want_lines = want.split('\n')
523 want_lines = want.split('\n')
524 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
524 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
525 del want_lines[-1] # forget final newline & spaces after it
525 del want_lines[-1] # forget final newline & spaces after it
526 self._check_prefix(want_lines, ' '*indent, name,
526 self._check_prefix(want_lines, ' '*indent, name,
527 lineno + len(source_lines))
527 lineno + len(source_lines))
528
528
529 # Remove ipython output prompt that might be present in the first line
529 # Remove ipython output prompt that might be present in the first line
530 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
530 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
531
531
532 want = '\n'.join([wl[indent:] for wl in want_lines])
532 want = '\n'.join([wl[indent:] for wl in want_lines])
533
533
534 # If `want` contains a traceback message, then extract it.
534 # If `want` contains a traceback message, then extract it.
535 m = self._EXCEPTION_RE.match(want)
535 m = self._EXCEPTION_RE.match(want)
536 if m:
536 if m:
537 exc_msg = m.group('msg')
537 exc_msg = m.group('msg')
538 else:
538 else:
539 exc_msg = None
539 exc_msg = None
540
540
541 # Extract options from the source.
541 # Extract options from the source.
542 options = self._find_options(source, name, lineno)
542 options = self._find_options(source, name, lineno)
543
543
544 return source, options, want, exc_msg
544 return source, options, want, exc_msg
545
545
546 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
546 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
547 """
547 """
548 Given the lines of a source string (including prompts and
548 Given the lines of a source string (including prompts and
549 leading indentation), check to make sure that every prompt is
549 leading indentation), check to make sure that every prompt is
550 followed by a space character. If any line is not followed by
550 followed by a space character. If any line is not followed by
551 a space character, then raise ValueError.
551 a space character, then raise ValueError.
552
552
553 Note: IPython-modified version which takes the input prompt length as a
553 Note: IPython-modified version which takes the input prompt length as a
554 parameter, so that prompts of variable length can be dealt with.
554 parameter, so that prompts of variable length can be dealt with.
555 """
555 """
556 space_idx = indent+ps1_len
556 space_idx = indent+ps1_len
557 min_len = space_idx+1
557 min_len = space_idx+1
558 for i, line in enumerate(lines):
558 for i, line in enumerate(lines):
559 if len(line) >= min_len and line[space_idx] != ' ':
559 if len(line) >= min_len and line[space_idx] != ' ':
560 raise ValueError('line %r of the docstring for %s '
560 raise ValueError('line %r of the docstring for %s '
561 'lacks blank after %s: %r' %
561 'lacks blank after %s: %r' %
562 (lineno+i+1, name,
562 (lineno+i+1, name,
563 line[indent:space_idx], line))
563 line[indent:space_idx], line))
564
564
565
565
566 SKIP = doctest.register_optionflag('SKIP')
566 SKIP = doctest.register_optionflag('SKIP')
567
567
568
568
569 class IPDocTestRunner(doctest.DocTestRunner,object):
569 class IPDocTestRunner(doctest.DocTestRunner,object):
570 """Test runner that synchronizes the IPython namespace with test globals.
570 """Test runner that synchronizes the IPython namespace with test globals.
571 """
571 """
572
572
573 def run(self, test, compileflags=None, out=None, clear_globs=True):
573 def run(self, test, compileflags=None, out=None, clear_globs=True):
574
574
575 # Hack: ipython needs access to the execution context of the example,
575 # Hack: ipython needs access to the execution context of the example,
576 # so that it can propagate user variables loaded by %run into
576 # so that it can propagate user variables loaded by %run into
577 # test.globs. We put them here into our modified %run as a function
577 # test.globs. We put them here into our modified %run as a function
578 # attribute. Our new %run will then only make the namespace update
578 # attribute. Our new %run will then only make the namespace update
579 # when called (rather than unconconditionally updating test.globs here
579 # when called (rather than unconconditionally updating test.globs here
580 # for all examples, most of which won't be calling %run anyway).
580 # for all examples, most of which won't be calling %run anyway).
581 #_ip._ipdoctest_test_globs = test.globs
581 #_ip._ipdoctest_test_globs = test.globs
582 #_ip._ipdoctest_test_filename = test.filename
582 #_ip._ipdoctest_test_filename = test.filename
583
583
584 test.globs.update(_ip.user_ns)
584 test.globs.update(_ip.user_ns)
585
585
586 return super(IPDocTestRunner,self).run(test,
586 return super(IPDocTestRunner,self).run(test,
587 compileflags,out,clear_globs)
587 compileflags,out,clear_globs)
588
588
589
589
590 class DocFileCase(doctest.DocFileCase):
590 class DocFileCase(doctest.DocFileCase):
591 """Overrides to provide filename
591 """Overrides to provide filename
592 """
592 """
593 def address(self):
593 def address(self):
594 return (self._dt_test.filename, None, None)
594 return (self._dt_test.filename, None, None)
595
595
596
596
597 class ExtensionDoctest(doctests.Doctest):
597 class ExtensionDoctest(doctests.Doctest):
598 """Nose Plugin that supports doctests in extension modules.
598 """Nose Plugin that supports doctests in extension modules.
599 """
599 """
600 name = 'extdoctest' # call nosetests with --with-extdoctest
600 name = 'extdoctest' # call nosetests with --with-extdoctest
601 enabled = True
601 enabled = True
602
602
603 def options(self, parser, env=os.environ):
603 def options(self, parser, env=os.environ):
604 Plugin.options(self, parser, env)
604 Plugin.options(self, parser, env)
605 parser.add_option('--doctest-tests', action='store_true',
605 parser.add_option('--doctest-tests', action='store_true',
606 dest='doctest_tests',
606 dest='doctest_tests',
607 default=env.get('NOSE_DOCTEST_TESTS',True),
607 default=env.get('NOSE_DOCTEST_TESTS',True),
608 help="Also look for doctests in test modules. "
608 help="Also look for doctests in test modules. "
609 "Note that classes, methods and functions should "
609 "Note that classes, methods and functions should "
610 "have either doctests or non-doctest tests, "
610 "have either doctests or non-doctest tests, "
611 "not both. [NOSE_DOCTEST_TESTS]")
611 "not both. [NOSE_DOCTEST_TESTS]")
612 parser.add_option('--doctest-extension', action="append",
612 parser.add_option('--doctest-extension', action="append",
613 dest="doctestExtension",
613 dest="doctestExtension",
614 help="Also look for doctests in files with "
614 help="Also look for doctests in files with "
615 "this extension [NOSE_DOCTEST_EXTENSION]")
615 "this extension [NOSE_DOCTEST_EXTENSION]")
616 # Set the default as a list, if given in env; otherwise
616 # Set the default as a list, if given in env; otherwise
617 # an additional value set on the command line will cause
617 # an additional value set on the command line will cause
618 # an error.
618 # an error.
619 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
619 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
620 if env_setting is not None:
620 if env_setting is not None:
621 parser.set_defaults(doctestExtension=tolist(env_setting))
621 parser.set_defaults(doctestExtension=tolist(env_setting))
622
622
623
623
624 def configure(self, options, config):
624 def configure(self, options, config):
625 Plugin.configure(self, options, config)
625 Plugin.configure(self, options, config)
626 # Pull standard doctest plugin out of config; we will do doctesting
626 # Pull standard doctest plugin out of config; we will do doctesting
627 config.plugins.plugins = [p for p in config.plugins.plugins
627 config.plugins.plugins = [p for p in config.plugins.plugins
628 if p.name != 'doctest']
628 if p.name != 'doctest']
629 self.doctest_tests = options.doctest_tests
629 self.doctest_tests = options.doctest_tests
630 self.extension = tolist(options.doctestExtension)
630 self.extension = tolist(options.doctestExtension)
631
631
632 self.parser = doctest.DocTestParser()
632 self.parser = doctest.DocTestParser()
633 self.finder = DocTestFinder()
633 self.finder = DocTestFinder()
634 self.checker = IPDoctestOutputChecker()
634 self.checker = IPDoctestOutputChecker()
635 self.globs = None
635 self.globs = None
636 self.extraglobs = None
636 self.extraglobs = None
637
637
638
638
639 def loadTestsFromExtensionModule(self,filename):
639 def loadTestsFromExtensionModule(self,filename):
640 bpath,mod = os.path.split(filename)
640 bpath,mod = os.path.split(filename)
641 modname = os.path.splitext(mod)[0]
641 modname = os.path.splitext(mod)[0]
642 try:
642 try:
643 sys.path.append(bpath)
643 sys.path.append(bpath)
644 module = __import__(modname)
644 module = __import__(modname)
645 tests = list(self.loadTestsFromModule(module))
645 tests = list(self.loadTestsFromModule(module))
646 finally:
646 finally:
647 sys.path.pop()
647 sys.path.pop()
648 return tests
648 return tests
649
649
650 # NOTE: the method below is almost a copy of the original one in nose, with
650 # NOTE: the method below is almost a copy of the original one in nose, with
651 # a few modifications to control output checking.
651 # a few modifications to control output checking.
652
652
653 def loadTestsFromModule(self, module):
653 def loadTestsFromModule(self, module):
654 #print '*** ipdoctest - lTM',module # dbg
654 #print '*** ipdoctest - lTM',module # dbg
655
655
656 if not self.matches(module.__name__):
656 if not self.matches(module.__name__):
657 log.debug("Doctest doesn't want module %s", module)
657 log.debug("Doctest doesn't want module %s", module)
658 return
658 return
659
659
660 tests = self.finder.find(module,globs=self.globs,
660 tests = self.finder.find(module,globs=self.globs,
661 extraglobs=self.extraglobs)
661 extraglobs=self.extraglobs)
662 if not tests:
662 if not tests:
663 return
663 return
664
664
665 # always use whitespace and ellipsis options
665 # always use whitespace and ellipsis options
666 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
666 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
667
667
668 tests.sort()
668 tests.sort()
669 module_file = module.__file__
669 module_file = module.__file__
670 if module_file[-4:] in ('.pyc', '.pyo'):
670 if module_file[-4:] in ('.pyc', '.pyo'):
671 module_file = module_file[:-1]
671 module_file = module_file[:-1]
672 for test in tests:
672 for test in tests:
673 if not test.examples:
673 if not test.examples:
674 continue
674 continue
675 if not test.filename:
675 if not test.filename:
676 test.filename = module_file
676 test.filename = module_file
677
677
678 yield DocTestCase(test,
678 yield DocTestCase(test,
679 optionflags=optionflags,
679 optionflags=optionflags,
680 checker=self.checker)
680 checker=self.checker)
681
681
682
682
683 def loadTestsFromFile(self, filename):
683 def loadTestsFromFile(self, filename):
684 #print "ipdoctest - from file", filename # dbg
684 #print "ipdoctest - from file", filename # dbg
685 if is_extension_module(filename):
685 if is_extension_module(filename):
686 for t in self.loadTestsFromExtensionModule(filename):
686 for t in self.loadTestsFromExtensionModule(filename):
687 yield t
687 yield t
688 else:
688 else:
689 if self.extension and anyp(filename.endswith, self.extension):
689 if self.extension and anyp(filename.endswith, self.extension):
690 name = os.path.basename(filename)
690 name = os.path.basename(filename)
691 dh = open(filename)
691 dh = open(filename)
692 try:
692 try:
693 doc = dh.read()
693 doc = dh.read()
694 finally:
694 finally:
695 dh.close()
695 dh.close()
696 test = self.parser.get_doctest(
696 test = self.parser.get_doctest(
697 doc, globs={'__file__': filename}, name=name,
697 doc, globs={'__file__': filename}, name=name,
698 filename=filename, lineno=0)
698 filename=filename, lineno=0)
699 if test.examples:
699 if test.examples:
700 #print 'FileCase:',test.examples # dbg
700 #print 'FileCase:',test.examples # dbg
701 yield DocFileCase(test)
701 yield DocFileCase(test)
702 else:
702 else:
703 yield False # no tests to load
703 yield False # no tests to load
704
704
705
705
706 class IPythonDoctest(ExtensionDoctest):
706 class IPythonDoctest(ExtensionDoctest):
707 """Nose Plugin that supports doctests in extension modules.
707 """Nose Plugin that supports doctests in extension modules.
708 """
708 """
709 name = 'ipdoctest' # call nosetests with --with-ipdoctest
709 name = 'ipdoctest' # call nosetests with --with-ipdoctest
710 enabled = True
710 enabled = True
711
711
712 def makeTest(self, obj, parent):
712 def makeTest(self, obj, parent):
713 """Look for doctests in the given object, which will be a
713 """Look for doctests in the given object, which will be a
714 function, method or class.
714 function, method or class.
715 """
715 """
716 #print 'Plugin analyzing:', obj, parent # dbg
716 #print 'Plugin analyzing:', obj, parent # dbg
717 # always use whitespace and ellipsis options
717 # always use whitespace and ellipsis options
718 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
718 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
719
719
720 doctests = self.finder.find(obj, module=getmodule(parent))
720 doctests = self.finder.find(obj, module=getmodule(parent))
721 if doctests:
721 if doctests:
722 for test in doctests:
722 for test in doctests:
723 if len(test.examples) == 0:
723 if len(test.examples) == 0:
724 continue
724 continue
725
725
726 yield DocTestCase(test, obj=obj,
726 yield DocTestCase(test, obj=obj,
727 optionflags=optionflags,
727 optionflags=optionflags,
728 checker=self.checker)
728 checker=self.checker)
729
729
730 def options(self, parser, env=os.environ):
730 def options(self, parser, env=os.environ):
731 #print "Options for nose plugin:", self.name # dbg
731 #print "Options for nose plugin:", self.name # dbg
732 Plugin.options(self, parser, env)
732 Plugin.options(self, parser, env)
733 parser.add_option('--ipdoctest-tests', action='store_true',
733 parser.add_option('--ipdoctest-tests', action='store_true',
734 dest='ipdoctest_tests',
734 dest='ipdoctest_tests',
735 default=env.get('NOSE_IPDOCTEST_TESTS',True),
735 default=env.get('NOSE_IPDOCTEST_TESTS',True),
736 help="Also look for doctests in test modules. "
736 help="Also look for doctests in test modules. "
737 "Note that classes, methods and functions should "
737 "Note that classes, methods and functions should "
738 "have either doctests or non-doctest tests, "
738 "have either doctests or non-doctest tests, "
739 "not both. [NOSE_IPDOCTEST_TESTS]")
739 "not both. [NOSE_IPDOCTEST_TESTS]")
740 parser.add_option('--ipdoctest-extension', action="append",
740 parser.add_option('--ipdoctest-extension', action="append",
741 dest="ipdoctest_extension",
741 dest="ipdoctest_extension",
742 help="Also look for doctests in files with "
742 help="Also look for doctests in files with "
743 "this extension [NOSE_IPDOCTEST_EXTENSION]")
743 "this extension [NOSE_IPDOCTEST_EXTENSION]")
744 # Set the default as a list, if given in env; otherwise
744 # Set the default as a list, if given in env; otherwise
745 # an additional value set on the command line will cause
745 # an additional value set on the command line will cause
746 # an error.
746 # an error.
747 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
747 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
748 if env_setting is not None:
748 if env_setting is not None:
749 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
749 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
750
750
751 def configure(self, options, config):
751 def configure(self, options, config):
752 #print "Configuring nose plugin:", self.name # dbg
752 #print "Configuring nose plugin:", self.name # dbg
753 Plugin.configure(self, options, config)
753 Plugin.configure(self, options, config)
754 # Pull standard doctest plugin out of config; we will do doctesting
754 # Pull standard doctest plugin out of config; we will do doctesting
755 config.plugins.plugins = [p for p in config.plugins.plugins
755 config.plugins.plugins = [p for p in config.plugins.plugins
756 if p.name != 'doctest']
756 if p.name != 'doctest']
757 self.doctest_tests = options.ipdoctest_tests
757 self.doctest_tests = options.ipdoctest_tests
758 self.extension = tolist(options.ipdoctest_extension)
758 self.extension = tolist(options.ipdoctest_extension)
759
759
760 self.parser = IPDocTestParser()
760 self.parser = IPDocTestParser()
761 self.finder = DocTestFinder(parser=self.parser)
761 self.finder = DocTestFinder(parser=self.parser)
762 self.checker = IPDoctestOutputChecker()
762 self.checker = IPDoctestOutputChecker()
763 self.globs = None
763 self.globs = None
764 self.extraglobs = None
764 self.extraglobs = None
@@ -1,187 +1,187 b''
1 """Windows-specific implementation of process utilities.
1 """Windows-specific implementation of process utilities.
2
2
3 This file is only meant to be imported by process.py, not by end-users.
3 This file is only meant to be imported by process.py, not by end-users.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2010-2011 The IPython Development Team
7 # Copyright (C) 2010-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # stdlib
18 # stdlib
19 import os
19 import os
20 import sys
20 import sys
21 import ctypes
21 import ctypes
22
22
23 from ctypes import c_int, POINTER
23 from ctypes import c_int, POINTER
24 from ctypes.wintypes import LPCWSTR, HLOCAL
24 from ctypes.wintypes import LPCWSTR, HLOCAL
25 from subprocess import STDOUT
25 from subprocess import STDOUT
26
26
27 # our own imports
27 # our own imports
28 from ._process_common import read_no_interrupt, process_handler, arg_split as py_arg_split
28 from ._process_common import read_no_interrupt, process_handler, arg_split as py_arg_split
29 from . import py3compat
29 from . import py3compat
30 from .encoding import DEFAULT_ENCODING
30 from .encoding import DEFAULT_ENCODING
31
31
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33 # Function definitions
33 # Function definitions
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35
35
36 class AvoidUNCPath(object):
36 class AvoidUNCPath(object):
37 """A context manager to protect command execution from UNC paths.
37 """A context manager to protect command execution from UNC paths.
38
38
39 In the Win32 API, commands can't be invoked with the cwd being a UNC path.
39 In the Win32 API, commands can't be invoked with the cwd being a UNC path.
40 This context manager temporarily changes directory to the 'C:' drive on
40 This context manager temporarily changes directory to the 'C:' drive on
41 entering, and restores the original working directory on exit.
41 entering, and restores the original working directory on exit.
42
42
43 The context manager returns the starting working directory *if* it made a
43 The context manager returns the starting working directory *if* it made a
44 change and None otherwise, so that users can apply the necessary adjustment
44 change and None otherwise, so that users can apply the necessary adjustment
45 to their system calls in the event of a change.
45 to their system calls in the event of a change.
46
46
47 Examples
47 Examples
48 --------
48 --------
49 ::
49 ::
50 cmd = 'dir'
50 cmd = 'dir'
51 with AvoidUNCPath() as path:
51 with AvoidUNCPath() as path:
52 if path is not None:
52 if path is not None:
53 cmd = '"pushd %s &&"%s' % (path, cmd)
53 cmd = '"pushd %s &&"%s' % (path, cmd)
54 os.system(cmd)
54 os.system(cmd)
55 """
55 """
56 def __enter__(self):
56 def __enter__(self):
57 self.path = os.getcwdu()
57 self.path = py3compat.getcwd()
58 self.is_unc_path = self.path.startswith(r"\\")
58 self.is_unc_path = self.path.startswith(r"\\")
59 if self.is_unc_path:
59 if self.is_unc_path:
60 # change to c drive (as cmd.exe cannot handle UNC addresses)
60 # change to c drive (as cmd.exe cannot handle UNC addresses)
61 os.chdir("C:")
61 os.chdir("C:")
62 return self.path
62 return self.path
63 else:
63 else:
64 # We return None to signal that there was no change in the working
64 # We return None to signal that there was no change in the working
65 # directory
65 # directory
66 return None
66 return None
67
67
68 def __exit__(self, exc_type, exc_value, traceback):
68 def __exit__(self, exc_type, exc_value, traceback):
69 if self.is_unc_path:
69 if self.is_unc_path:
70 os.chdir(self.path)
70 os.chdir(self.path)
71
71
72
72
73 def _find_cmd(cmd):
73 def _find_cmd(cmd):
74 """Find the full path to a .bat or .exe using the win32api module."""
74 """Find the full path to a .bat or .exe using the win32api module."""
75 try:
75 try:
76 from win32api import SearchPath
76 from win32api import SearchPath
77 except ImportError:
77 except ImportError:
78 raise ImportError('you need to have pywin32 installed for this to work')
78 raise ImportError('you need to have pywin32 installed for this to work')
79 else:
79 else:
80 PATH = os.environ['PATH']
80 PATH = os.environ['PATH']
81 extensions = ['.exe', '.com', '.bat', '.py']
81 extensions = ['.exe', '.com', '.bat', '.py']
82 path = None
82 path = None
83 for ext in extensions:
83 for ext in extensions:
84 try:
84 try:
85 path = SearchPath(PATH, cmd, ext)[0]
85 path = SearchPath(PATH, cmd, ext)[0]
86 except:
86 except:
87 pass
87 pass
88 if path is None:
88 if path is None:
89 raise OSError("command %r not found" % cmd)
89 raise OSError("command %r not found" % cmd)
90 else:
90 else:
91 return path
91 return path
92
92
93
93
94 def _system_body(p):
94 def _system_body(p):
95 """Callback for _system."""
95 """Callback for _system."""
96 enc = DEFAULT_ENCODING
96 enc = DEFAULT_ENCODING
97 for line in read_no_interrupt(p.stdout).splitlines():
97 for line in read_no_interrupt(p.stdout).splitlines():
98 line = line.decode(enc, 'replace')
98 line = line.decode(enc, 'replace')
99 print(line, file=sys.stdout)
99 print(line, file=sys.stdout)
100 for line in read_no_interrupt(p.stderr).splitlines():
100 for line in read_no_interrupt(p.stderr).splitlines():
101 line = line.decode(enc, 'replace')
101 line = line.decode(enc, 'replace')
102 print(line, file=sys.stderr)
102 print(line, file=sys.stderr)
103
103
104 # Wait to finish for returncode
104 # Wait to finish for returncode
105 return p.wait()
105 return p.wait()
106
106
107
107
108 def system(cmd):
108 def system(cmd):
109 """Win32 version of os.system() that works with network shares.
109 """Win32 version of os.system() that works with network shares.
110
110
111 Note that this implementation returns None, as meant for use in IPython.
111 Note that this implementation returns None, as meant for use in IPython.
112
112
113 Parameters
113 Parameters
114 ----------
114 ----------
115 cmd : str
115 cmd : str
116 A command to be executed in the system shell.
116 A command to be executed in the system shell.
117
117
118 Returns
118 Returns
119 -------
119 -------
120 None : we explicitly do NOT return the subprocess status code, as this
120 None : we explicitly do NOT return the subprocess status code, as this
121 utility is meant to be used extensively in IPython, where any return value
121 utility is meant to be used extensively in IPython, where any return value
122 would trigger :func:`sys.displayhook` calls.
122 would trigger :func:`sys.displayhook` calls.
123 """
123 """
124 # The controller provides interactivity with both
124 # The controller provides interactivity with both
125 # stdin and stdout
125 # stdin and stdout
126 #import _process_win32_controller
126 #import _process_win32_controller
127 #_process_win32_controller.system(cmd)
127 #_process_win32_controller.system(cmd)
128
128
129 with AvoidUNCPath() as path:
129 with AvoidUNCPath() as path:
130 if path is not None:
130 if path is not None:
131 cmd = '"pushd %s &&"%s' % (path, cmd)
131 cmd = '"pushd %s &&"%s' % (path, cmd)
132 return process_handler(cmd, _system_body)
132 return process_handler(cmd, _system_body)
133
133
134 def getoutput(cmd):
134 def getoutput(cmd):
135 """Return standard output of executing cmd in a shell.
135 """Return standard output of executing cmd in a shell.
136
136
137 Accepts the same arguments as os.system().
137 Accepts the same arguments as os.system().
138
138
139 Parameters
139 Parameters
140 ----------
140 ----------
141 cmd : str
141 cmd : str
142 A command to be executed in the system shell.
142 A command to be executed in the system shell.
143
143
144 Returns
144 Returns
145 -------
145 -------
146 stdout : str
146 stdout : str
147 """
147 """
148
148
149 with AvoidUNCPath() as path:
149 with AvoidUNCPath() as path:
150 if path is not None:
150 if path is not None:
151 cmd = '"pushd %s &&"%s' % (path, cmd)
151 cmd = '"pushd %s &&"%s' % (path, cmd)
152 out = process_handler(cmd, lambda p: p.communicate()[0], STDOUT)
152 out = process_handler(cmd, lambda p: p.communicate()[0], STDOUT)
153
153
154 if out is None:
154 if out is None:
155 out = b''
155 out = b''
156 return py3compat.bytes_to_str(out)
156 return py3compat.bytes_to_str(out)
157
157
158 try:
158 try:
159 CommandLineToArgvW = ctypes.windll.shell32.CommandLineToArgvW
159 CommandLineToArgvW = ctypes.windll.shell32.CommandLineToArgvW
160 CommandLineToArgvW.arg_types = [LPCWSTR, POINTER(c_int)]
160 CommandLineToArgvW.arg_types = [LPCWSTR, POINTER(c_int)]
161 CommandLineToArgvW.restype = POINTER(LPCWSTR)
161 CommandLineToArgvW.restype = POINTER(LPCWSTR)
162 LocalFree = ctypes.windll.kernel32.LocalFree
162 LocalFree = ctypes.windll.kernel32.LocalFree
163 LocalFree.res_type = HLOCAL
163 LocalFree.res_type = HLOCAL
164 LocalFree.arg_types = [HLOCAL]
164 LocalFree.arg_types = [HLOCAL]
165
165
166 def arg_split(commandline, posix=False, strict=True):
166 def arg_split(commandline, posix=False, strict=True):
167 """Split a command line's arguments in a shell-like manner.
167 """Split a command line's arguments in a shell-like manner.
168
168
169 This is a special version for windows that use a ctypes call to CommandLineToArgvW
169 This is a special version for windows that use a ctypes call to CommandLineToArgvW
170 to do the argv splitting. The posix paramter is ignored.
170 to do the argv splitting. The posix paramter is ignored.
171
171
172 If strict=False, process_common.arg_split(...strict=False) is used instead.
172 If strict=False, process_common.arg_split(...strict=False) is used instead.
173 """
173 """
174 #CommandLineToArgvW returns path to executable if called with empty string.
174 #CommandLineToArgvW returns path to executable if called with empty string.
175 if commandline.strip() == "":
175 if commandline.strip() == "":
176 return []
176 return []
177 if not strict:
177 if not strict:
178 # not really a cl-arg, fallback on _process_common
178 # not really a cl-arg, fallback on _process_common
179 return py_arg_split(commandline, posix=posix, strict=strict)
179 return py_arg_split(commandline, posix=posix, strict=strict)
180 argvn = c_int()
180 argvn = c_int()
181 result_pointer = CommandLineToArgvW(py3compat.cast_unicode(commandline.lstrip()), ctypes.byref(argvn))
181 result_pointer = CommandLineToArgvW(py3compat.cast_unicode(commandline.lstrip()), ctypes.byref(argvn))
182 result_array_type = LPCWSTR * argvn.value
182 result_array_type = LPCWSTR * argvn.value
183 result = [arg for arg in result_array_type.from_address(ctypes.addressof(result_pointer.contents))]
183 result = [arg for arg in result_array_type.from_address(ctypes.addressof(result_pointer.contents))]
184 retval = LocalFree(result_pointer)
184 retval = LocalFree(result_pointer)
185 return result
185 return result
186 except AttributeError:
186 except AttributeError:
187 arg_split = py_arg_split
187 arg_split = py_arg_split
@@ -1,577 +1,577 b''
1 """Windows-specific implementation of process utilities with direct WinAPI.
1 """Windows-specific implementation of process utilities with direct WinAPI.
2
2
3 This file is meant to be used by process.py
3 This file is meant to be used by process.py
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2010-2011 The IPython Development Team
7 # Copyright (C) 2010-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 from __future__ import print_function
13 from __future__ import print_function
14
14
15 # stdlib
15 # stdlib
16 import os, sys, threading
16 import os, sys, threading
17 import ctypes, msvcrt
17 import ctypes, msvcrt
18
18
19 # local imports
19 # local imports
20 from .py3compat import unicode_type
20 from . import py3compat
21
21
22 # Win32 API types needed for the API calls
22 # Win32 API types needed for the API calls
23 from ctypes import POINTER
23 from ctypes import POINTER
24 from ctypes.wintypes import HANDLE, HLOCAL, LPVOID, WORD, DWORD, BOOL, \
24 from ctypes.wintypes import HANDLE, HLOCAL, LPVOID, WORD, DWORD, BOOL, \
25 ULONG, LPCWSTR
25 ULONG, LPCWSTR
26 LPDWORD = POINTER(DWORD)
26 LPDWORD = POINTER(DWORD)
27 LPHANDLE = POINTER(HANDLE)
27 LPHANDLE = POINTER(HANDLE)
28 ULONG_PTR = POINTER(ULONG)
28 ULONG_PTR = POINTER(ULONG)
29 class SECURITY_ATTRIBUTES(ctypes.Structure):
29 class SECURITY_ATTRIBUTES(ctypes.Structure):
30 _fields_ = [("nLength", DWORD),
30 _fields_ = [("nLength", DWORD),
31 ("lpSecurityDescriptor", LPVOID),
31 ("lpSecurityDescriptor", LPVOID),
32 ("bInheritHandle", BOOL)]
32 ("bInheritHandle", BOOL)]
33 LPSECURITY_ATTRIBUTES = POINTER(SECURITY_ATTRIBUTES)
33 LPSECURITY_ATTRIBUTES = POINTER(SECURITY_ATTRIBUTES)
34 class STARTUPINFO(ctypes.Structure):
34 class STARTUPINFO(ctypes.Structure):
35 _fields_ = [("cb", DWORD),
35 _fields_ = [("cb", DWORD),
36 ("lpReserved", LPCWSTR),
36 ("lpReserved", LPCWSTR),
37 ("lpDesktop", LPCWSTR),
37 ("lpDesktop", LPCWSTR),
38 ("lpTitle", LPCWSTR),
38 ("lpTitle", LPCWSTR),
39 ("dwX", DWORD),
39 ("dwX", DWORD),
40 ("dwY", DWORD),
40 ("dwY", DWORD),
41 ("dwXSize", DWORD),
41 ("dwXSize", DWORD),
42 ("dwYSize", DWORD),
42 ("dwYSize", DWORD),
43 ("dwXCountChars", DWORD),
43 ("dwXCountChars", DWORD),
44 ("dwYCountChars", DWORD),
44 ("dwYCountChars", DWORD),
45 ("dwFillAttribute", DWORD),
45 ("dwFillAttribute", DWORD),
46 ("dwFlags", DWORD),
46 ("dwFlags", DWORD),
47 ("wShowWindow", WORD),
47 ("wShowWindow", WORD),
48 ("cbReserved2", WORD),
48 ("cbReserved2", WORD),
49 ("lpReserved2", LPVOID),
49 ("lpReserved2", LPVOID),
50 ("hStdInput", HANDLE),
50 ("hStdInput", HANDLE),
51 ("hStdOutput", HANDLE),
51 ("hStdOutput", HANDLE),
52 ("hStdError", HANDLE)]
52 ("hStdError", HANDLE)]
53 LPSTARTUPINFO = POINTER(STARTUPINFO)
53 LPSTARTUPINFO = POINTER(STARTUPINFO)
54 class PROCESS_INFORMATION(ctypes.Structure):
54 class PROCESS_INFORMATION(ctypes.Structure):
55 _fields_ = [("hProcess", HANDLE),
55 _fields_ = [("hProcess", HANDLE),
56 ("hThread", HANDLE),
56 ("hThread", HANDLE),
57 ("dwProcessId", DWORD),
57 ("dwProcessId", DWORD),
58 ("dwThreadId", DWORD)]
58 ("dwThreadId", DWORD)]
59 LPPROCESS_INFORMATION = POINTER(PROCESS_INFORMATION)
59 LPPROCESS_INFORMATION = POINTER(PROCESS_INFORMATION)
60
60
61 # Win32 API constants needed
61 # Win32 API constants needed
62 ERROR_HANDLE_EOF = 38
62 ERROR_HANDLE_EOF = 38
63 ERROR_BROKEN_PIPE = 109
63 ERROR_BROKEN_PIPE = 109
64 ERROR_NO_DATA = 232
64 ERROR_NO_DATA = 232
65 HANDLE_FLAG_INHERIT = 0x0001
65 HANDLE_FLAG_INHERIT = 0x0001
66 STARTF_USESTDHANDLES = 0x0100
66 STARTF_USESTDHANDLES = 0x0100
67 CREATE_SUSPENDED = 0x0004
67 CREATE_SUSPENDED = 0x0004
68 CREATE_NEW_CONSOLE = 0x0010
68 CREATE_NEW_CONSOLE = 0x0010
69 CREATE_NO_WINDOW = 0x08000000
69 CREATE_NO_WINDOW = 0x08000000
70 STILL_ACTIVE = 259
70 STILL_ACTIVE = 259
71 WAIT_TIMEOUT = 0x0102
71 WAIT_TIMEOUT = 0x0102
72 WAIT_FAILED = 0xFFFFFFFF
72 WAIT_FAILED = 0xFFFFFFFF
73 INFINITE = 0xFFFFFFFF
73 INFINITE = 0xFFFFFFFF
74 DUPLICATE_SAME_ACCESS = 0x00000002
74 DUPLICATE_SAME_ACCESS = 0x00000002
75 ENABLE_ECHO_INPUT = 0x0004
75 ENABLE_ECHO_INPUT = 0x0004
76 ENABLE_LINE_INPUT = 0x0002
76 ENABLE_LINE_INPUT = 0x0002
77 ENABLE_PROCESSED_INPUT = 0x0001
77 ENABLE_PROCESSED_INPUT = 0x0001
78
78
79 # Win32 API functions needed
79 # Win32 API functions needed
80 GetLastError = ctypes.windll.kernel32.GetLastError
80 GetLastError = ctypes.windll.kernel32.GetLastError
81 GetLastError.argtypes = []
81 GetLastError.argtypes = []
82 GetLastError.restype = DWORD
82 GetLastError.restype = DWORD
83
83
84 CreateFile = ctypes.windll.kernel32.CreateFileW
84 CreateFile = ctypes.windll.kernel32.CreateFileW
85 CreateFile.argtypes = [LPCWSTR, DWORD, DWORD, LPVOID, DWORD, DWORD, HANDLE]
85 CreateFile.argtypes = [LPCWSTR, DWORD, DWORD, LPVOID, DWORD, DWORD, HANDLE]
86 CreateFile.restype = HANDLE
86 CreateFile.restype = HANDLE
87
87
88 CreatePipe = ctypes.windll.kernel32.CreatePipe
88 CreatePipe = ctypes.windll.kernel32.CreatePipe
89 CreatePipe.argtypes = [POINTER(HANDLE), POINTER(HANDLE),
89 CreatePipe.argtypes = [POINTER(HANDLE), POINTER(HANDLE),
90 LPSECURITY_ATTRIBUTES, DWORD]
90 LPSECURITY_ATTRIBUTES, DWORD]
91 CreatePipe.restype = BOOL
91 CreatePipe.restype = BOOL
92
92
93 CreateProcess = ctypes.windll.kernel32.CreateProcessW
93 CreateProcess = ctypes.windll.kernel32.CreateProcessW
94 CreateProcess.argtypes = [LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES,
94 CreateProcess.argtypes = [LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES,
95 LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCWSTR, LPSTARTUPINFO,
95 LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCWSTR, LPSTARTUPINFO,
96 LPPROCESS_INFORMATION]
96 LPPROCESS_INFORMATION]
97 CreateProcess.restype = BOOL
97 CreateProcess.restype = BOOL
98
98
99 GetExitCodeProcess = ctypes.windll.kernel32.GetExitCodeProcess
99 GetExitCodeProcess = ctypes.windll.kernel32.GetExitCodeProcess
100 GetExitCodeProcess.argtypes = [HANDLE, LPDWORD]
100 GetExitCodeProcess.argtypes = [HANDLE, LPDWORD]
101 GetExitCodeProcess.restype = BOOL
101 GetExitCodeProcess.restype = BOOL
102
102
103 GetCurrentProcess = ctypes.windll.kernel32.GetCurrentProcess
103 GetCurrentProcess = ctypes.windll.kernel32.GetCurrentProcess
104 GetCurrentProcess.argtypes = []
104 GetCurrentProcess.argtypes = []
105 GetCurrentProcess.restype = HANDLE
105 GetCurrentProcess.restype = HANDLE
106
106
107 ResumeThread = ctypes.windll.kernel32.ResumeThread
107 ResumeThread = ctypes.windll.kernel32.ResumeThread
108 ResumeThread.argtypes = [HANDLE]
108 ResumeThread.argtypes = [HANDLE]
109 ResumeThread.restype = DWORD
109 ResumeThread.restype = DWORD
110
110
111 ReadFile = ctypes.windll.kernel32.ReadFile
111 ReadFile = ctypes.windll.kernel32.ReadFile
112 ReadFile.argtypes = [HANDLE, LPVOID, DWORD, LPDWORD, LPVOID]
112 ReadFile.argtypes = [HANDLE, LPVOID, DWORD, LPDWORD, LPVOID]
113 ReadFile.restype = BOOL
113 ReadFile.restype = BOOL
114
114
115 WriteFile = ctypes.windll.kernel32.WriteFile
115 WriteFile = ctypes.windll.kernel32.WriteFile
116 WriteFile.argtypes = [HANDLE, LPVOID, DWORD, LPDWORD, LPVOID]
116 WriteFile.argtypes = [HANDLE, LPVOID, DWORD, LPDWORD, LPVOID]
117 WriteFile.restype = BOOL
117 WriteFile.restype = BOOL
118
118
119 GetConsoleMode = ctypes.windll.kernel32.GetConsoleMode
119 GetConsoleMode = ctypes.windll.kernel32.GetConsoleMode
120 GetConsoleMode.argtypes = [HANDLE, LPDWORD]
120 GetConsoleMode.argtypes = [HANDLE, LPDWORD]
121 GetConsoleMode.restype = BOOL
121 GetConsoleMode.restype = BOOL
122
122
123 SetConsoleMode = ctypes.windll.kernel32.SetConsoleMode
123 SetConsoleMode = ctypes.windll.kernel32.SetConsoleMode
124 SetConsoleMode.argtypes = [HANDLE, DWORD]
124 SetConsoleMode.argtypes = [HANDLE, DWORD]
125 SetConsoleMode.restype = BOOL
125 SetConsoleMode.restype = BOOL
126
126
127 FlushConsoleInputBuffer = ctypes.windll.kernel32.FlushConsoleInputBuffer
127 FlushConsoleInputBuffer = ctypes.windll.kernel32.FlushConsoleInputBuffer
128 FlushConsoleInputBuffer.argtypes = [HANDLE]
128 FlushConsoleInputBuffer.argtypes = [HANDLE]
129 FlushConsoleInputBuffer.restype = BOOL
129 FlushConsoleInputBuffer.restype = BOOL
130
130
131 WaitForSingleObject = ctypes.windll.kernel32.WaitForSingleObject
131 WaitForSingleObject = ctypes.windll.kernel32.WaitForSingleObject
132 WaitForSingleObject.argtypes = [HANDLE, DWORD]
132 WaitForSingleObject.argtypes = [HANDLE, DWORD]
133 WaitForSingleObject.restype = DWORD
133 WaitForSingleObject.restype = DWORD
134
134
135 DuplicateHandle = ctypes.windll.kernel32.DuplicateHandle
135 DuplicateHandle = ctypes.windll.kernel32.DuplicateHandle
136 DuplicateHandle.argtypes = [HANDLE, HANDLE, HANDLE, LPHANDLE,
136 DuplicateHandle.argtypes = [HANDLE, HANDLE, HANDLE, LPHANDLE,
137 DWORD, BOOL, DWORD]
137 DWORD, BOOL, DWORD]
138 DuplicateHandle.restype = BOOL
138 DuplicateHandle.restype = BOOL
139
139
140 SetHandleInformation = ctypes.windll.kernel32.SetHandleInformation
140 SetHandleInformation = ctypes.windll.kernel32.SetHandleInformation
141 SetHandleInformation.argtypes = [HANDLE, DWORD, DWORD]
141 SetHandleInformation.argtypes = [HANDLE, DWORD, DWORD]
142 SetHandleInformation.restype = BOOL
142 SetHandleInformation.restype = BOOL
143
143
144 CloseHandle = ctypes.windll.kernel32.CloseHandle
144 CloseHandle = ctypes.windll.kernel32.CloseHandle
145 CloseHandle.argtypes = [HANDLE]
145 CloseHandle.argtypes = [HANDLE]
146 CloseHandle.restype = BOOL
146 CloseHandle.restype = BOOL
147
147
148 CommandLineToArgvW = ctypes.windll.shell32.CommandLineToArgvW
148 CommandLineToArgvW = ctypes.windll.shell32.CommandLineToArgvW
149 CommandLineToArgvW.argtypes = [LPCWSTR, POINTER(ctypes.c_int)]
149 CommandLineToArgvW.argtypes = [LPCWSTR, POINTER(ctypes.c_int)]
150 CommandLineToArgvW.restype = POINTER(LPCWSTR)
150 CommandLineToArgvW.restype = POINTER(LPCWSTR)
151
151
152 LocalFree = ctypes.windll.kernel32.LocalFree
152 LocalFree = ctypes.windll.kernel32.LocalFree
153 LocalFree.argtypes = [HLOCAL]
153 LocalFree.argtypes = [HLOCAL]
154 LocalFree.restype = HLOCAL
154 LocalFree.restype = HLOCAL
155
155
156 class AvoidUNCPath(object):
156 class AvoidUNCPath(object):
157 """A context manager to protect command execution from UNC paths.
157 """A context manager to protect command execution from UNC paths.
158
158
159 In the Win32 API, commands can't be invoked with the cwd being a UNC path.
159 In the Win32 API, commands can't be invoked with the cwd being a UNC path.
160 This context manager temporarily changes directory to the 'C:' drive on
160 This context manager temporarily changes directory to the 'C:' drive on
161 entering, and restores the original working directory on exit.
161 entering, and restores the original working directory on exit.
162
162
163 The context manager returns the starting working directory *if* it made a
163 The context manager returns the starting working directory *if* it made a
164 change and None otherwise, so that users can apply the necessary adjustment
164 change and None otherwise, so that users can apply the necessary adjustment
165 to their system calls in the event of a change.
165 to their system calls in the event of a change.
166
166
167 Examples
167 Examples
168 --------
168 --------
169 ::
169 ::
170 cmd = 'dir'
170 cmd = 'dir'
171 with AvoidUNCPath() as path:
171 with AvoidUNCPath() as path:
172 if path is not None:
172 if path is not None:
173 cmd = '"pushd %s &&"%s' % (path, cmd)
173 cmd = '"pushd %s &&"%s' % (path, cmd)
174 os.system(cmd)
174 os.system(cmd)
175 """
175 """
176 def __enter__(self):
176 def __enter__(self):
177 self.path = os.getcwdu()
177 self.path = py3compat.getcwd()
178 self.is_unc_path = self.path.startswith(r"\\")
178 self.is_unc_path = self.path.startswith(r"\\")
179 if self.is_unc_path:
179 if self.is_unc_path:
180 # change to c drive (as cmd.exe cannot handle UNC addresses)
180 # change to c drive (as cmd.exe cannot handle UNC addresses)
181 os.chdir("C:")
181 os.chdir("C:")
182 return self.path
182 return self.path
183 else:
183 else:
184 # We return None to signal that there was no change in the working
184 # We return None to signal that there was no change in the working
185 # directory
185 # directory
186 return None
186 return None
187
187
188 def __exit__(self, exc_type, exc_value, traceback):
188 def __exit__(self, exc_type, exc_value, traceback):
189 if self.is_unc_path:
189 if self.is_unc_path:
190 os.chdir(self.path)
190 os.chdir(self.path)
191
191
192
192
193 class Win32ShellCommandController(object):
193 class Win32ShellCommandController(object):
194 """Runs a shell command in a 'with' context.
194 """Runs a shell command in a 'with' context.
195
195
196 This implementation is Win32-specific.
196 This implementation is Win32-specific.
197
197
198 Example:
198 Example:
199 # Runs the command interactively with default console stdin/stdout
199 # Runs the command interactively with default console stdin/stdout
200 with ShellCommandController('python -i') as scc:
200 with ShellCommandController('python -i') as scc:
201 scc.run()
201 scc.run()
202
202
203 # Runs the command using the provided functions for stdin/stdout
203 # Runs the command using the provided functions for stdin/stdout
204 def my_stdout_func(s):
204 def my_stdout_func(s):
205 # print or save the string 's'
205 # print or save the string 's'
206 write_to_stdout(s)
206 write_to_stdout(s)
207 def my_stdin_func():
207 def my_stdin_func():
208 # If input is available, return it as a string.
208 # If input is available, return it as a string.
209 if input_available():
209 if input_available():
210 return get_input()
210 return get_input()
211 # If no input available, return None after a short delay to
211 # If no input available, return None after a short delay to
212 # keep from blocking.
212 # keep from blocking.
213 else:
213 else:
214 time.sleep(0.01)
214 time.sleep(0.01)
215 return None
215 return None
216
216
217 with ShellCommandController('python -i') as scc:
217 with ShellCommandController('python -i') as scc:
218 scc.run(my_stdout_func, my_stdin_func)
218 scc.run(my_stdout_func, my_stdin_func)
219 """
219 """
220
220
221 def __init__(self, cmd, mergeout = True):
221 def __init__(self, cmd, mergeout = True):
222 """Initializes the shell command controller.
222 """Initializes the shell command controller.
223
223
224 The cmd is the program to execute, and mergeout is
224 The cmd is the program to execute, and mergeout is
225 whether to blend stdout and stderr into one output
225 whether to blend stdout and stderr into one output
226 in stdout. Merging them together in this fashion more
226 in stdout. Merging them together in this fashion more
227 reliably keeps stdout and stderr in the correct order
227 reliably keeps stdout and stderr in the correct order
228 especially for interactive shell usage.
228 especially for interactive shell usage.
229 """
229 """
230 self.cmd = cmd
230 self.cmd = cmd
231 self.mergeout = mergeout
231 self.mergeout = mergeout
232
232
233 def __enter__(self):
233 def __enter__(self):
234 cmd = self.cmd
234 cmd = self.cmd
235 mergeout = self.mergeout
235 mergeout = self.mergeout
236
236
237 self.hstdout, self.hstdin, self.hstderr = None, None, None
237 self.hstdout, self.hstdin, self.hstderr = None, None, None
238 self.piProcInfo = None
238 self.piProcInfo = None
239 try:
239 try:
240 p_hstdout, c_hstdout, p_hstderr, \
240 p_hstdout, c_hstdout, p_hstderr, \
241 c_hstderr, p_hstdin, c_hstdin = [None]*6
241 c_hstderr, p_hstdin, c_hstdin = [None]*6
242
242
243 # SECURITY_ATTRIBUTES with inherit handle set to True
243 # SECURITY_ATTRIBUTES with inherit handle set to True
244 saAttr = SECURITY_ATTRIBUTES()
244 saAttr = SECURITY_ATTRIBUTES()
245 saAttr.nLength = ctypes.sizeof(saAttr)
245 saAttr.nLength = ctypes.sizeof(saAttr)
246 saAttr.bInheritHandle = True
246 saAttr.bInheritHandle = True
247 saAttr.lpSecurityDescriptor = None
247 saAttr.lpSecurityDescriptor = None
248
248
249 def create_pipe(uninherit):
249 def create_pipe(uninherit):
250 """Creates a Windows pipe, which consists of two handles.
250 """Creates a Windows pipe, which consists of two handles.
251
251
252 The 'uninherit' parameter controls which handle is not
252 The 'uninherit' parameter controls which handle is not
253 inherited by the child process.
253 inherited by the child process.
254 """
254 """
255 handles = HANDLE(), HANDLE()
255 handles = HANDLE(), HANDLE()
256 if not CreatePipe(ctypes.byref(handles[0]),
256 if not CreatePipe(ctypes.byref(handles[0]),
257 ctypes.byref(handles[1]), ctypes.byref(saAttr), 0):
257 ctypes.byref(handles[1]), ctypes.byref(saAttr), 0):
258 raise ctypes.WinError()
258 raise ctypes.WinError()
259 if not SetHandleInformation(handles[uninherit],
259 if not SetHandleInformation(handles[uninherit],
260 HANDLE_FLAG_INHERIT, 0):
260 HANDLE_FLAG_INHERIT, 0):
261 raise ctypes.WinError()
261 raise ctypes.WinError()
262 return handles[0].value, handles[1].value
262 return handles[0].value, handles[1].value
263
263
264 p_hstdout, c_hstdout = create_pipe(uninherit=0)
264 p_hstdout, c_hstdout = create_pipe(uninherit=0)
265 # 'mergeout' signals that stdout and stderr should be merged.
265 # 'mergeout' signals that stdout and stderr should be merged.
266 # We do that by using one pipe for both of them.
266 # We do that by using one pipe for both of them.
267 if mergeout:
267 if mergeout:
268 c_hstderr = HANDLE()
268 c_hstderr = HANDLE()
269 if not DuplicateHandle(GetCurrentProcess(), c_hstdout,
269 if not DuplicateHandle(GetCurrentProcess(), c_hstdout,
270 GetCurrentProcess(), ctypes.byref(c_hstderr),
270 GetCurrentProcess(), ctypes.byref(c_hstderr),
271 0, True, DUPLICATE_SAME_ACCESS):
271 0, True, DUPLICATE_SAME_ACCESS):
272 raise ctypes.WinError()
272 raise ctypes.WinError()
273 else:
273 else:
274 p_hstderr, c_hstderr = create_pipe(uninherit=0)
274 p_hstderr, c_hstderr = create_pipe(uninherit=0)
275 c_hstdin, p_hstdin = create_pipe(uninherit=1)
275 c_hstdin, p_hstdin = create_pipe(uninherit=1)
276
276
277 # Create the process object
277 # Create the process object
278 piProcInfo = PROCESS_INFORMATION()
278 piProcInfo = PROCESS_INFORMATION()
279 siStartInfo = STARTUPINFO()
279 siStartInfo = STARTUPINFO()
280 siStartInfo.cb = ctypes.sizeof(siStartInfo)
280 siStartInfo.cb = ctypes.sizeof(siStartInfo)
281 siStartInfo.hStdInput = c_hstdin
281 siStartInfo.hStdInput = c_hstdin
282 siStartInfo.hStdOutput = c_hstdout
282 siStartInfo.hStdOutput = c_hstdout
283 siStartInfo.hStdError = c_hstderr
283 siStartInfo.hStdError = c_hstderr
284 siStartInfo.dwFlags = STARTF_USESTDHANDLES
284 siStartInfo.dwFlags = STARTF_USESTDHANDLES
285 dwCreationFlags = CREATE_SUSPENDED | CREATE_NO_WINDOW # | CREATE_NEW_CONSOLE
285 dwCreationFlags = CREATE_SUSPENDED | CREATE_NO_WINDOW # | CREATE_NEW_CONSOLE
286
286
287 if not CreateProcess(None,
287 if not CreateProcess(None,
288 u"cmd.exe /c " + cmd,
288 u"cmd.exe /c " + cmd,
289 None, None, True, dwCreationFlags,
289 None, None, True, dwCreationFlags,
290 None, None, ctypes.byref(siStartInfo),
290 None, None, ctypes.byref(siStartInfo),
291 ctypes.byref(piProcInfo)):
291 ctypes.byref(piProcInfo)):
292 raise ctypes.WinError()
292 raise ctypes.WinError()
293
293
294 # Close this process's versions of the child handles
294 # Close this process's versions of the child handles
295 CloseHandle(c_hstdin)
295 CloseHandle(c_hstdin)
296 c_hstdin = None
296 c_hstdin = None
297 CloseHandle(c_hstdout)
297 CloseHandle(c_hstdout)
298 c_hstdout = None
298 c_hstdout = None
299 if c_hstderr != None:
299 if c_hstderr != None:
300 CloseHandle(c_hstderr)
300 CloseHandle(c_hstderr)
301 c_hstderr = None
301 c_hstderr = None
302
302
303 # Transfer ownership of the parent handles to the object
303 # Transfer ownership of the parent handles to the object
304 self.hstdin = p_hstdin
304 self.hstdin = p_hstdin
305 p_hstdin = None
305 p_hstdin = None
306 self.hstdout = p_hstdout
306 self.hstdout = p_hstdout
307 p_hstdout = None
307 p_hstdout = None
308 if not mergeout:
308 if not mergeout:
309 self.hstderr = p_hstderr
309 self.hstderr = p_hstderr
310 p_hstderr = None
310 p_hstderr = None
311 self.piProcInfo = piProcInfo
311 self.piProcInfo = piProcInfo
312
312
313 finally:
313 finally:
314 if p_hstdin:
314 if p_hstdin:
315 CloseHandle(p_hstdin)
315 CloseHandle(p_hstdin)
316 if c_hstdin:
316 if c_hstdin:
317 CloseHandle(c_hstdin)
317 CloseHandle(c_hstdin)
318 if p_hstdout:
318 if p_hstdout:
319 CloseHandle(p_hstdout)
319 CloseHandle(p_hstdout)
320 if c_hstdout:
320 if c_hstdout:
321 CloseHandle(c_hstdout)
321 CloseHandle(c_hstdout)
322 if p_hstderr:
322 if p_hstderr:
323 CloseHandle(p_hstderr)
323 CloseHandle(p_hstderr)
324 if c_hstderr:
324 if c_hstderr:
325 CloseHandle(c_hstderr)
325 CloseHandle(c_hstderr)
326
326
327 return self
327 return self
328
328
329 def _stdin_thread(self, handle, hprocess, func, stdout_func):
329 def _stdin_thread(self, handle, hprocess, func, stdout_func):
330 exitCode = DWORD()
330 exitCode = DWORD()
331 bytesWritten = DWORD(0)
331 bytesWritten = DWORD(0)
332 while True:
332 while True:
333 #print("stdin thread loop start")
333 #print("stdin thread loop start")
334 # Get the input string (may be bytes or unicode)
334 # Get the input string (may be bytes or unicode)
335 data = func()
335 data = func()
336
336
337 # None signals to poll whether the process has exited
337 # None signals to poll whether the process has exited
338 if data is None:
338 if data is None:
339 #print("checking for process completion")
339 #print("checking for process completion")
340 if not GetExitCodeProcess(hprocess, ctypes.byref(exitCode)):
340 if not GetExitCodeProcess(hprocess, ctypes.byref(exitCode)):
341 raise ctypes.WinError()
341 raise ctypes.WinError()
342 if exitCode.value != STILL_ACTIVE:
342 if exitCode.value != STILL_ACTIVE:
343 return
343 return
344 # TESTING: Does zero-sized writefile help?
344 # TESTING: Does zero-sized writefile help?
345 if not WriteFile(handle, "", 0,
345 if not WriteFile(handle, "", 0,
346 ctypes.byref(bytesWritten), None):
346 ctypes.byref(bytesWritten), None):
347 raise ctypes.WinError()
347 raise ctypes.WinError()
348 continue
348 continue
349 #print("\nGot str %s\n" % repr(data), file=sys.stderr)
349 #print("\nGot str %s\n" % repr(data), file=sys.stderr)
350
350
351 # Encode the string to the console encoding
351 # Encode the string to the console encoding
352 if isinstance(data, unicode): #FIXME: Python3
352 if isinstance(data, unicode): #FIXME: Python3
353 data = data.encode('utf_8')
353 data = data.encode('utf_8')
354
354
355 # What we have now must be a string of bytes
355 # What we have now must be a string of bytes
356 if not isinstance(data, str): #FIXME: Python3
356 if not isinstance(data, str): #FIXME: Python3
357 raise RuntimeError("internal stdin function string error")
357 raise RuntimeError("internal stdin function string error")
358
358
359 # An empty string signals EOF
359 # An empty string signals EOF
360 if len(data) == 0:
360 if len(data) == 0:
361 return
361 return
362
362
363 # In a windows console, sometimes the input is echoed,
363 # In a windows console, sometimes the input is echoed,
364 # but sometimes not. How do we determine when to do this?
364 # but sometimes not. How do we determine when to do this?
365 stdout_func(data)
365 stdout_func(data)
366 # WriteFile may not accept all the data at once.
366 # WriteFile may not accept all the data at once.
367 # Loop until everything is processed
367 # Loop until everything is processed
368 while len(data) != 0:
368 while len(data) != 0:
369 #print("Calling writefile")
369 #print("Calling writefile")
370 if not WriteFile(handle, data, len(data),
370 if not WriteFile(handle, data, len(data),
371 ctypes.byref(bytesWritten), None):
371 ctypes.byref(bytesWritten), None):
372 # This occurs at exit
372 # This occurs at exit
373 if GetLastError() == ERROR_NO_DATA:
373 if GetLastError() == ERROR_NO_DATA:
374 return
374 return
375 raise ctypes.WinError()
375 raise ctypes.WinError()
376 #print("Called writefile")
376 #print("Called writefile")
377 data = data[bytesWritten.value:]
377 data = data[bytesWritten.value:]
378
378
379 def _stdout_thread(self, handle, func):
379 def _stdout_thread(self, handle, func):
380 # Allocate the output buffer
380 # Allocate the output buffer
381 data = ctypes.create_string_buffer(4096)
381 data = ctypes.create_string_buffer(4096)
382 while True:
382 while True:
383 bytesRead = DWORD(0)
383 bytesRead = DWORD(0)
384 if not ReadFile(handle, data, 4096,
384 if not ReadFile(handle, data, 4096,
385 ctypes.byref(bytesRead), None):
385 ctypes.byref(bytesRead), None):
386 le = GetLastError()
386 le = GetLastError()
387 if le == ERROR_BROKEN_PIPE:
387 if le == ERROR_BROKEN_PIPE:
388 return
388 return
389 else:
389 else:
390 raise ctypes.WinError()
390 raise ctypes.WinError()
391 # FIXME: Python3
391 # FIXME: Python3
392 s = data.value[0:bytesRead.value]
392 s = data.value[0:bytesRead.value]
393 #print("\nv: %s" % repr(s), file=sys.stderr)
393 #print("\nv: %s" % repr(s), file=sys.stderr)
394 func(s.decode('utf_8', 'replace'))
394 func(s.decode('utf_8', 'replace'))
395
395
396 def run(self, stdout_func = None, stdin_func = None, stderr_func = None):
396 def run(self, stdout_func = None, stdin_func = None, stderr_func = None):
397 """Runs the process, using the provided functions for I/O.
397 """Runs the process, using the provided functions for I/O.
398
398
399 The function stdin_func should return strings whenever a
399 The function stdin_func should return strings whenever a
400 character or characters become available.
400 character or characters become available.
401 The functions stdout_func and stderr_func are called whenever
401 The functions stdout_func and stderr_func are called whenever
402 something is printed to stdout or stderr, respectively.
402 something is printed to stdout or stderr, respectively.
403 These functions are called from different threads (but not
403 These functions are called from different threads (but not
404 concurrently, because of the GIL).
404 concurrently, because of the GIL).
405 """
405 """
406 if stdout_func == None and stdin_func == None and stderr_func == None:
406 if stdout_func == None and stdin_func == None and stderr_func == None:
407 return self._run_stdio()
407 return self._run_stdio()
408
408
409 if stderr_func != None and self.mergeout:
409 if stderr_func != None and self.mergeout:
410 raise RuntimeError("Shell command was initiated with "
410 raise RuntimeError("Shell command was initiated with "
411 "merged stdin/stdout, but a separate stderr_func "
411 "merged stdin/stdout, but a separate stderr_func "
412 "was provided to the run() method")
412 "was provided to the run() method")
413
413
414 # Create a thread for each input/output handle
414 # Create a thread for each input/output handle
415 stdin_thread = None
415 stdin_thread = None
416 threads = []
416 threads = []
417 if stdin_func:
417 if stdin_func:
418 stdin_thread = threading.Thread(target=self._stdin_thread,
418 stdin_thread = threading.Thread(target=self._stdin_thread,
419 args=(self.hstdin, self.piProcInfo.hProcess,
419 args=(self.hstdin, self.piProcInfo.hProcess,
420 stdin_func, stdout_func))
420 stdin_func, stdout_func))
421 threads.append(threading.Thread(target=self._stdout_thread,
421 threads.append(threading.Thread(target=self._stdout_thread,
422 args=(self.hstdout, stdout_func)))
422 args=(self.hstdout, stdout_func)))
423 if not self.mergeout:
423 if not self.mergeout:
424 if stderr_func == None:
424 if stderr_func == None:
425 stderr_func = stdout_func
425 stderr_func = stdout_func
426 threads.append(threading.Thread(target=self._stdout_thread,
426 threads.append(threading.Thread(target=self._stdout_thread,
427 args=(self.hstderr, stderr_func)))
427 args=(self.hstderr, stderr_func)))
428 # Start the I/O threads and the process
428 # Start the I/O threads and the process
429 if ResumeThread(self.piProcInfo.hThread) == 0xFFFFFFFF:
429 if ResumeThread(self.piProcInfo.hThread) == 0xFFFFFFFF:
430 raise ctypes.WinError()
430 raise ctypes.WinError()
431 if stdin_thread is not None:
431 if stdin_thread is not None:
432 stdin_thread.start()
432 stdin_thread.start()
433 for thread in threads:
433 for thread in threads:
434 thread.start()
434 thread.start()
435 # Wait for the process to complete
435 # Wait for the process to complete
436 if WaitForSingleObject(self.piProcInfo.hProcess, INFINITE) == \
436 if WaitForSingleObject(self.piProcInfo.hProcess, INFINITE) == \
437 WAIT_FAILED:
437 WAIT_FAILED:
438 raise ctypes.WinError()
438 raise ctypes.WinError()
439 # Wait for the I/O threads to complete
439 # Wait for the I/O threads to complete
440 for thread in threads:
440 for thread in threads:
441 thread.join()
441 thread.join()
442
442
443 # Wait for the stdin thread to complete
443 # Wait for the stdin thread to complete
444 if stdin_thread is not None:
444 if stdin_thread is not None:
445 stdin_thread.join()
445 stdin_thread.join()
446
446
447 def _stdin_raw_nonblock(self):
447 def _stdin_raw_nonblock(self):
448 """Use the raw Win32 handle of sys.stdin to do non-blocking reads"""
448 """Use the raw Win32 handle of sys.stdin to do non-blocking reads"""
449 # WARNING: This is experimental, and produces inconsistent results.
449 # WARNING: This is experimental, and produces inconsistent results.
450 # It's possible for the handle not to be appropriate for use
450 # It's possible for the handle not to be appropriate for use
451 # with WaitForSingleObject, among other things.
451 # with WaitForSingleObject, among other things.
452 handle = msvcrt.get_osfhandle(sys.stdin.fileno())
452 handle = msvcrt.get_osfhandle(sys.stdin.fileno())
453 result = WaitForSingleObject(handle, 100)
453 result = WaitForSingleObject(handle, 100)
454 if result == WAIT_FAILED:
454 if result == WAIT_FAILED:
455 raise ctypes.WinError()
455 raise ctypes.WinError()
456 elif result == WAIT_TIMEOUT:
456 elif result == WAIT_TIMEOUT:
457 print(".", end='')
457 print(".", end='')
458 return None
458 return None
459 else:
459 else:
460 data = ctypes.create_string_buffer(256)
460 data = ctypes.create_string_buffer(256)
461 bytesRead = DWORD(0)
461 bytesRead = DWORD(0)
462 print('?', end='')
462 print('?', end='')
463
463
464 if not ReadFile(handle, data, 256,
464 if not ReadFile(handle, data, 256,
465 ctypes.byref(bytesRead), None):
465 ctypes.byref(bytesRead), None):
466 raise ctypes.WinError()
466 raise ctypes.WinError()
467 # This ensures the non-blocking works with an actual console
467 # This ensures the non-blocking works with an actual console
468 # Not checking the error, so the processing will still work with
468 # Not checking the error, so the processing will still work with
469 # other handle types
469 # other handle types
470 FlushConsoleInputBuffer(handle)
470 FlushConsoleInputBuffer(handle)
471
471
472 data = data.value
472 data = data.value
473 data = data.replace('\r\n', '\n')
473 data = data.replace('\r\n', '\n')
474 data = data.replace('\r', '\n')
474 data = data.replace('\r', '\n')
475 print(repr(data) + " ", end='')
475 print(repr(data) + " ", end='')
476 return data
476 return data
477
477
478 def _stdin_raw_block(self):
478 def _stdin_raw_block(self):
479 """Use a blocking stdin read"""
479 """Use a blocking stdin read"""
480 # The big problem with the blocking read is that it doesn't
480 # The big problem with the blocking read is that it doesn't
481 # exit when it's supposed to in all contexts. An extra
481 # exit when it's supposed to in all contexts. An extra
482 # key-press may be required to trigger the exit.
482 # key-press may be required to trigger the exit.
483 try:
483 try:
484 data = sys.stdin.read(1)
484 data = sys.stdin.read(1)
485 data = data.replace('\r', '\n')
485 data = data.replace('\r', '\n')
486 return data
486 return data
487 except WindowsError as we:
487 except WindowsError as we:
488 if we.winerror == ERROR_NO_DATA:
488 if we.winerror == ERROR_NO_DATA:
489 # This error occurs when the pipe is closed
489 # This error occurs when the pipe is closed
490 return None
490 return None
491 else:
491 else:
492 # Otherwise let the error propagate
492 # Otherwise let the error propagate
493 raise we
493 raise we
494
494
495 def _stdout_raw(self, s):
495 def _stdout_raw(self, s):
496 """Writes the string to stdout"""
496 """Writes the string to stdout"""
497 print(s, end='', file=sys.stdout)
497 print(s, end='', file=sys.stdout)
498 sys.stdout.flush()
498 sys.stdout.flush()
499
499
500 def _stderr_raw(self, s):
500 def _stderr_raw(self, s):
501 """Writes the string to stdout"""
501 """Writes the string to stdout"""
502 print(s, end='', file=sys.stderr)
502 print(s, end='', file=sys.stderr)
503 sys.stderr.flush()
503 sys.stderr.flush()
504
504
505 def _run_stdio(self):
505 def _run_stdio(self):
506 """Runs the process using the system standard I/O.
506 """Runs the process using the system standard I/O.
507
507
508 IMPORTANT: stdin needs to be asynchronous, so the Python
508 IMPORTANT: stdin needs to be asynchronous, so the Python
509 sys.stdin object is not used. Instead,
509 sys.stdin object is not used. Instead,
510 msvcrt.kbhit/getwch are used asynchronously.
510 msvcrt.kbhit/getwch are used asynchronously.
511 """
511 """
512 # Disable Line and Echo mode
512 # Disable Line and Echo mode
513 #lpMode = DWORD()
513 #lpMode = DWORD()
514 #handle = msvcrt.get_osfhandle(sys.stdin.fileno())
514 #handle = msvcrt.get_osfhandle(sys.stdin.fileno())
515 #if GetConsoleMode(handle, ctypes.byref(lpMode)):
515 #if GetConsoleMode(handle, ctypes.byref(lpMode)):
516 # set_console_mode = True
516 # set_console_mode = True
517 # if not SetConsoleMode(handle, lpMode.value &
517 # if not SetConsoleMode(handle, lpMode.value &
518 # ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT)):
518 # ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT)):
519 # raise ctypes.WinError()
519 # raise ctypes.WinError()
520
520
521 if self.mergeout:
521 if self.mergeout:
522 return self.run(stdout_func = self._stdout_raw,
522 return self.run(stdout_func = self._stdout_raw,
523 stdin_func = self._stdin_raw_block)
523 stdin_func = self._stdin_raw_block)
524 else:
524 else:
525 return self.run(stdout_func = self._stdout_raw,
525 return self.run(stdout_func = self._stdout_raw,
526 stdin_func = self._stdin_raw_block,
526 stdin_func = self._stdin_raw_block,
527 stderr_func = self._stderr_raw)
527 stderr_func = self._stderr_raw)
528
528
529 # Restore the previous console mode
529 # Restore the previous console mode
530 #if set_console_mode:
530 #if set_console_mode:
531 # if not SetConsoleMode(handle, lpMode.value):
531 # if not SetConsoleMode(handle, lpMode.value):
532 # raise ctypes.WinError()
532 # raise ctypes.WinError()
533
533
534 def __exit__(self, exc_type, exc_value, traceback):
534 def __exit__(self, exc_type, exc_value, traceback):
535 if self.hstdin:
535 if self.hstdin:
536 CloseHandle(self.hstdin)
536 CloseHandle(self.hstdin)
537 self.hstdin = None
537 self.hstdin = None
538 if self.hstdout:
538 if self.hstdout:
539 CloseHandle(self.hstdout)
539 CloseHandle(self.hstdout)
540 self.hstdout = None
540 self.hstdout = None
541 if self.hstderr:
541 if self.hstderr:
542 CloseHandle(self.hstderr)
542 CloseHandle(self.hstderr)
543 self.hstderr = None
543 self.hstderr = None
544 if self.piProcInfo != None:
544 if self.piProcInfo != None:
545 CloseHandle(self.piProcInfo.hProcess)
545 CloseHandle(self.piProcInfo.hProcess)
546 CloseHandle(self.piProcInfo.hThread)
546 CloseHandle(self.piProcInfo.hThread)
547 self.piProcInfo = None
547 self.piProcInfo = None
548
548
549
549
550 def system(cmd):
550 def system(cmd):
551 """Win32 version of os.system() that works with network shares.
551 """Win32 version of os.system() that works with network shares.
552
552
553 Note that this implementation returns None, as meant for use in IPython.
553 Note that this implementation returns None, as meant for use in IPython.
554
554
555 Parameters
555 Parameters
556 ----------
556 ----------
557 cmd : str
557 cmd : str
558 A command to be executed in the system shell.
558 A command to be executed in the system shell.
559
559
560 Returns
560 Returns
561 -------
561 -------
562 None : we explicitly do NOT return the subprocess status code, as this
562 None : we explicitly do NOT return the subprocess status code, as this
563 utility is meant to be used extensively in IPython, where any return value
563 utility is meant to be used extensively in IPython, where any return value
564 would trigger :func:`sys.displayhook` calls.
564 would trigger :func:`sys.displayhook` calls.
565 """
565 """
566 with AvoidUNCPath() as path:
566 with AvoidUNCPath() as path:
567 if path is not None:
567 if path is not None:
568 cmd = '"pushd %s &&"%s' % (path, cmd)
568 cmd = '"pushd %s &&"%s' % (path, cmd)
569 with Win32ShellCommandController(cmd) as scc:
569 with Win32ShellCommandController(cmd) as scc:
570 scc.run()
570 scc.run()
571
571
572
572
573 if __name__ == "__main__":
573 if __name__ == "__main__":
574 print("Test starting!")
574 print("Test starting!")
575 #system("cmd")
575 #system("cmd")
576 system("python -i")
576 system("python -i")
577 print("Test finished!")
577 print("Test finished!")
@@ -1,574 +1,574 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for path handling.
3 Utilities for path handling.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import os
17 import os
18 import sys
18 import sys
19 import errno
19 import errno
20 import shutil
20 import shutil
21 import random
21 import random
22 import tempfile
22 import tempfile
23 import warnings
23 import warnings
24 from hashlib import md5
24 from hashlib import md5
25 import glob
25 import glob
26
26
27 import IPython
27 import IPython
28 from IPython.testing.skipdoctest import skip_doctest
28 from IPython.testing.skipdoctest import skip_doctest
29 from IPython.utils.process import system
29 from IPython.utils.process import system
30 from IPython.utils.importstring import import_item
30 from IPython.utils.importstring import import_item
31 from IPython.utils import py3compat
31 from IPython.utils import py3compat
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33 # Code
33 # Code
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35
35
36 fs_encoding = sys.getfilesystemencoding()
36 fs_encoding = sys.getfilesystemencoding()
37
37
38 def _get_long_path_name(path):
38 def _get_long_path_name(path):
39 """Dummy no-op."""
39 """Dummy no-op."""
40 return path
40 return path
41
41
42 def _writable_dir(path):
42 def _writable_dir(path):
43 """Whether `path` is a directory, to which the user has write access."""
43 """Whether `path` is a directory, to which the user has write access."""
44 return os.path.isdir(path) and os.access(path, os.W_OK)
44 return os.path.isdir(path) and os.access(path, os.W_OK)
45
45
46 if sys.platform == 'win32':
46 if sys.platform == 'win32':
47 @skip_doctest
47 @skip_doctest
48 def _get_long_path_name(path):
48 def _get_long_path_name(path):
49 """Get a long path name (expand ~) on Windows using ctypes.
49 """Get a long path name (expand ~) on Windows using ctypes.
50
50
51 Examples
51 Examples
52 --------
52 --------
53
53
54 >>> get_long_path_name('c:\\docume~1')
54 >>> get_long_path_name('c:\\docume~1')
55 u'c:\\\\Documents and Settings'
55 u'c:\\\\Documents and Settings'
56
56
57 """
57 """
58 try:
58 try:
59 import ctypes
59 import ctypes
60 except ImportError:
60 except ImportError:
61 raise ImportError('you need to have ctypes installed for this to work')
61 raise ImportError('you need to have ctypes installed for this to work')
62 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
62 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
63 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
63 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
64 ctypes.c_uint ]
64 ctypes.c_uint ]
65
65
66 buf = ctypes.create_unicode_buffer(260)
66 buf = ctypes.create_unicode_buffer(260)
67 rv = _GetLongPathName(path, buf, 260)
67 rv = _GetLongPathName(path, buf, 260)
68 if rv == 0 or rv > 260:
68 if rv == 0 or rv > 260:
69 return path
69 return path
70 else:
70 else:
71 return buf.value
71 return buf.value
72
72
73
73
74 def get_long_path_name(path):
74 def get_long_path_name(path):
75 """Expand a path into its long form.
75 """Expand a path into its long form.
76
76
77 On Windows this expands any ~ in the paths. On other platforms, it is
77 On Windows this expands any ~ in the paths. On other platforms, it is
78 a null operation.
78 a null operation.
79 """
79 """
80 return _get_long_path_name(path)
80 return _get_long_path_name(path)
81
81
82
82
83 def unquote_filename(name, win32=(sys.platform=='win32')):
83 def unquote_filename(name, win32=(sys.platform=='win32')):
84 """ On Windows, remove leading and trailing quotes from filenames.
84 """ On Windows, remove leading and trailing quotes from filenames.
85 """
85 """
86 if win32:
86 if win32:
87 if name.startswith(("'", '"')) and name.endswith(("'", '"')):
87 if name.startswith(("'", '"')) and name.endswith(("'", '"')):
88 name = name[1:-1]
88 name = name[1:-1]
89 return name
89 return name
90
90
91 def compress_user(path):
91 def compress_user(path):
92 """Reverse of :func:`os.path.expanduser`
92 """Reverse of :func:`os.path.expanduser`
93 """
93 """
94 home = os.path.expanduser('~')
94 home = os.path.expanduser('~')
95 if path.startswith(home):
95 if path.startswith(home):
96 path = "~" + path[len(home):]
96 path = "~" + path[len(home):]
97 return path
97 return path
98
98
99 def get_py_filename(name, force_win32=None):
99 def get_py_filename(name, force_win32=None):
100 """Return a valid python filename in the current directory.
100 """Return a valid python filename in the current directory.
101
101
102 If the given name is not a file, it adds '.py' and searches again.
102 If the given name is not a file, it adds '.py' and searches again.
103 Raises IOError with an informative message if the file isn't found.
103 Raises IOError with an informative message if the file isn't found.
104
104
105 On Windows, apply Windows semantics to the filename. In particular, remove
105 On Windows, apply Windows semantics to the filename. In particular, remove
106 any quoting that has been applied to it. This option can be forced for
106 any quoting that has been applied to it. This option can be forced for
107 testing purposes.
107 testing purposes.
108 """
108 """
109
109
110 name = os.path.expanduser(name)
110 name = os.path.expanduser(name)
111 if force_win32 is None:
111 if force_win32 is None:
112 win32 = (sys.platform == 'win32')
112 win32 = (sys.platform == 'win32')
113 else:
113 else:
114 win32 = force_win32
114 win32 = force_win32
115 name = unquote_filename(name, win32=win32)
115 name = unquote_filename(name, win32=win32)
116 if not os.path.isfile(name) and not name.endswith('.py'):
116 if not os.path.isfile(name) and not name.endswith('.py'):
117 name += '.py'
117 name += '.py'
118 if os.path.isfile(name):
118 if os.path.isfile(name):
119 return name
119 return name
120 else:
120 else:
121 raise IOError('File `%r` not found.' % name)
121 raise IOError('File `%r` not found.' % name)
122
122
123
123
124 def filefind(filename, path_dirs=None):
124 def filefind(filename, path_dirs=None):
125 """Find a file by looking through a sequence of paths.
125 """Find a file by looking through a sequence of paths.
126
126
127 This iterates through a sequence of paths looking for a file and returns
127 This iterates through a sequence of paths looking for a file and returns
128 the full, absolute path of the first occurence of the file. If no set of
128 the full, absolute path of the first occurence of the file. If no set of
129 path dirs is given, the filename is tested as is, after running through
129 path dirs is given, the filename is tested as is, after running through
130 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
130 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
131
131
132 filefind('myfile.txt')
132 filefind('myfile.txt')
133
133
134 will find the file in the current working dir, but::
134 will find the file in the current working dir, but::
135
135
136 filefind('~/myfile.txt')
136 filefind('~/myfile.txt')
137
137
138 Will find the file in the users home directory. This function does not
138 Will find the file in the users home directory. This function does not
139 automatically try any paths, such as the cwd or the user's home directory.
139 automatically try any paths, such as the cwd or the user's home directory.
140
140
141 Parameters
141 Parameters
142 ----------
142 ----------
143 filename : str
143 filename : str
144 The filename to look for.
144 The filename to look for.
145 path_dirs : str, None or sequence of str
145 path_dirs : str, None or sequence of str
146 The sequence of paths to look for the file in. If None, the filename
146 The sequence of paths to look for the file in. If None, the filename
147 need to be absolute or be in the cwd. If a string, the string is
147 need to be absolute or be in the cwd. If a string, the string is
148 put into a sequence and the searched. If a sequence, walk through
148 put into a sequence and the searched. If a sequence, walk through
149 each element and join with ``filename``, calling :func:`expandvars`
149 each element and join with ``filename``, calling :func:`expandvars`
150 and :func:`expanduser` before testing for existence.
150 and :func:`expanduser` before testing for existence.
151
151
152 Returns
152 Returns
153 -------
153 -------
154 Raises :exc:`IOError` or returns absolute path to file.
154 Raises :exc:`IOError` or returns absolute path to file.
155 """
155 """
156
156
157 # If paths are quoted, abspath gets confused, strip them...
157 # If paths are quoted, abspath gets confused, strip them...
158 filename = filename.strip('"').strip("'")
158 filename = filename.strip('"').strip("'")
159 # If the input is an absolute path, just check it exists
159 # If the input is an absolute path, just check it exists
160 if os.path.isabs(filename) and os.path.isfile(filename):
160 if os.path.isabs(filename) and os.path.isfile(filename):
161 return filename
161 return filename
162
162
163 if path_dirs is None:
163 if path_dirs is None:
164 path_dirs = ("",)
164 path_dirs = ("",)
165 elif isinstance(path_dirs, py3compat.string_types):
165 elif isinstance(path_dirs, py3compat.string_types):
166 path_dirs = (path_dirs,)
166 path_dirs = (path_dirs,)
167
167
168 for path in path_dirs:
168 for path in path_dirs:
169 if path == '.': path = os.getcwdu()
169 if path == '.': path = py3compat.getcwd()
170 testname = expand_path(os.path.join(path, filename))
170 testname = expand_path(os.path.join(path, filename))
171 if os.path.isfile(testname):
171 if os.path.isfile(testname):
172 return os.path.abspath(testname)
172 return os.path.abspath(testname)
173
173
174 raise IOError("File %r does not exist in any of the search paths: %r" %
174 raise IOError("File %r does not exist in any of the search paths: %r" %
175 (filename, path_dirs) )
175 (filename, path_dirs) )
176
176
177
177
178 class HomeDirError(Exception):
178 class HomeDirError(Exception):
179 pass
179 pass
180
180
181
181
182 def get_home_dir(require_writable=False):
182 def get_home_dir(require_writable=False):
183 """Return the 'home' directory, as a unicode string.
183 """Return the 'home' directory, as a unicode string.
184
184
185 Uses os.path.expanduser('~'), and checks for writability.
185 Uses os.path.expanduser('~'), and checks for writability.
186
186
187 See stdlib docs for how this is determined.
187 See stdlib docs for how this is determined.
188 $HOME is first priority on *ALL* platforms.
188 $HOME is first priority on *ALL* platforms.
189
189
190 Parameters
190 Parameters
191 ----------
191 ----------
192
192
193 require_writable : bool [default: False]
193 require_writable : bool [default: False]
194 if True:
194 if True:
195 guarantees the return value is a writable directory, otherwise
195 guarantees the return value is a writable directory, otherwise
196 raises HomeDirError
196 raises HomeDirError
197 if False:
197 if False:
198 The path is resolved, but it is not guaranteed to exist or be writable.
198 The path is resolved, but it is not guaranteed to exist or be writable.
199 """
199 """
200
200
201 homedir = os.path.expanduser('~')
201 homedir = os.path.expanduser('~')
202 # Next line will make things work even when /home/ is a symlink to
202 # Next line will make things work even when /home/ is a symlink to
203 # /usr/home as it is on FreeBSD, for example
203 # /usr/home as it is on FreeBSD, for example
204 homedir = os.path.realpath(homedir)
204 homedir = os.path.realpath(homedir)
205
205
206 if not _writable_dir(homedir) and os.name == 'nt':
206 if not _writable_dir(homedir) and os.name == 'nt':
207 # expanduser failed, use the registry to get the 'My Documents' folder.
207 # expanduser failed, use the registry to get the 'My Documents' folder.
208 try:
208 try:
209 try:
209 try:
210 import winreg as wreg # Py 3
210 import winreg as wreg # Py 3
211 except ImportError:
211 except ImportError:
212 import _winreg as wreg # Py 2
212 import _winreg as wreg # Py 2
213 key = wreg.OpenKey(
213 key = wreg.OpenKey(
214 wreg.HKEY_CURRENT_USER,
214 wreg.HKEY_CURRENT_USER,
215 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
215 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
216 )
216 )
217 homedir = wreg.QueryValueEx(key,'Personal')[0]
217 homedir = wreg.QueryValueEx(key,'Personal')[0]
218 key.Close()
218 key.Close()
219 except:
219 except:
220 pass
220 pass
221
221
222 if (not require_writable) or _writable_dir(homedir):
222 if (not require_writable) or _writable_dir(homedir):
223 return py3compat.cast_unicode(homedir, fs_encoding)
223 return py3compat.cast_unicode(homedir, fs_encoding)
224 else:
224 else:
225 raise HomeDirError('%s is not a writable dir, '
225 raise HomeDirError('%s is not a writable dir, '
226 'set $HOME environment variable to override' % homedir)
226 'set $HOME environment variable to override' % homedir)
227
227
228 def get_xdg_dir():
228 def get_xdg_dir():
229 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
229 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
230
230
231 This is only for non-OS X posix (Linux,Unix,etc.) systems.
231 This is only for non-OS X posix (Linux,Unix,etc.) systems.
232 """
232 """
233
233
234 env = os.environ
234 env = os.environ
235
235
236 if os.name == 'posix' and sys.platform != 'darwin':
236 if os.name == 'posix' and sys.platform != 'darwin':
237 # Linux, Unix, AIX, etc.
237 # Linux, Unix, AIX, etc.
238 # use ~/.config if empty OR not set
238 # use ~/.config if empty OR not set
239 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
239 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
240 if xdg and _writable_dir(xdg):
240 if xdg and _writable_dir(xdg):
241 return py3compat.cast_unicode(xdg, fs_encoding)
241 return py3compat.cast_unicode(xdg, fs_encoding)
242
242
243 return None
243 return None
244
244
245
245
246 def get_xdg_cache_dir():
246 def get_xdg_cache_dir():
247 """Return the XDG_CACHE_HOME, if it is defined and exists, else None.
247 """Return the XDG_CACHE_HOME, if it is defined and exists, else None.
248
248
249 This is only for non-OS X posix (Linux,Unix,etc.) systems.
249 This is only for non-OS X posix (Linux,Unix,etc.) systems.
250 """
250 """
251
251
252 env = os.environ
252 env = os.environ
253
253
254 if os.name == 'posix' and sys.platform != 'darwin':
254 if os.name == 'posix' and sys.platform != 'darwin':
255 # Linux, Unix, AIX, etc.
255 # Linux, Unix, AIX, etc.
256 # use ~/.cache if empty OR not set
256 # use ~/.cache if empty OR not set
257 xdg = env.get("XDG_CACHE_HOME", None) or os.path.join(get_home_dir(), '.cache')
257 xdg = env.get("XDG_CACHE_HOME", None) or os.path.join(get_home_dir(), '.cache')
258 if xdg and _writable_dir(xdg):
258 if xdg and _writable_dir(xdg):
259 return py3compat.cast_unicode(xdg, fs_encoding)
259 return py3compat.cast_unicode(xdg, fs_encoding)
260
260
261 return None
261 return None
262
262
263
263
264 def get_ipython_dir():
264 def get_ipython_dir():
265 """Get the IPython directory for this platform and user.
265 """Get the IPython directory for this platform and user.
266
266
267 This uses the logic in `get_home_dir` to find the home directory
267 This uses the logic in `get_home_dir` to find the home directory
268 and then adds .ipython to the end of the path.
268 and then adds .ipython to the end of the path.
269 """
269 """
270
270
271 env = os.environ
271 env = os.environ
272 pjoin = os.path.join
272 pjoin = os.path.join
273
273
274
274
275 ipdir_def = '.ipython'
275 ipdir_def = '.ipython'
276 xdg_def = 'ipython'
276 xdg_def = 'ipython'
277
277
278 home_dir = get_home_dir()
278 home_dir = get_home_dir()
279 xdg_dir = get_xdg_dir()
279 xdg_dir = get_xdg_dir()
280
280
281 # import pdb; pdb.set_trace() # dbg
281 # import pdb; pdb.set_trace() # dbg
282 if 'IPYTHON_DIR' in env:
282 if 'IPYTHON_DIR' in env:
283 warnings.warn('The environment variable IPYTHON_DIR is deprecated. '
283 warnings.warn('The environment variable IPYTHON_DIR is deprecated. '
284 'Please use IPYTHONDIR instead.')
284 'Please use IPYTHONDIR instead.')
285 ipdir = env.get('IPYTHONDIR', env.get('IPYTHON_DIR', None))
285 ipdir = env.get('IPYTHONDIR', env.get('IPYTHON_DIR', None))
286 if ipdir is None:
286 if ipdir is None:
287 # not set explicitly, use XDG_CONFIG_HOME or HOME
287 # not set explicitly, use XDG_CONFIG_HOME or HOME
288 home_ipdir = pjoin(home_dir, ipdir_def)
288 home_ipdir = pjoin(home_dir, ipdir_def)
289 if xdg_dir:
289 if xdg_dir:
290 # use XDG, as long as the user isn't already
290 # use XDG, as long as the user isn't already
291 # using $HOME/.ipython and *not* XDG/ipython
291 # using $HOME/.ipython and *not* XDG/ipython
292
292
293 xdg_ipdir = pjoin(xdg_dir, xdg_def)
293 xdg_ipdir = pjoin(xdg_dir, xdg_def)
294
294
295 if _writable_dir(xdg_ipdir) or not _writable_dir(home_ipdir):
295 if _writable_dir(xdg_ipdir) or not _writable_dir(home_ipdir):
296 ipdir = xdg_ipdir
296 ipdir = xdg_ipdir
297
297
298 if ipdir is None:
298 if ipdir is None:
299 # not using XDG
299 # not using XDG
300 ipdir = home_ipdir
300 ipdir = home_ipdir
301
301
302 ipdir = os.path.normpath(os.path.expanduser(ipdir))
302 ipdir = os.path.normpath(os.path.expanduser(ipdir))
303
303
304 if os.path.exists(ipdir) and not _writable_dir(ipdir):
304 if os.path.exists(ipdir) and not _writable_dir(ipdir):
305 # ipdir exists, but is not writable
305 # ipdir exists, but is not writable
306 warnings.warn("IPython dir '%s' is not a writable location,"
306 warnings.warn("IPython dir '%s' is not a writable location,"
307 " using a temp directory."%ipdir)
307 " using a temp directory."%ipdir)
308 ipdir = tempfile.mkdtemp()
308 ipdir = tempfile.mkdtemp()
309 elif not os.path.exists(ipdir):
309 elif not os.path.exists(ipdir):
310 parent = os.path.dirname(ipdir)
310 parent = os.path.dirname(ipdir)
311 if not _writable_dir(parent):
311 if not _writable_dir(parent):
312 # ipdir does not exist and parent isn't writable
312 # ipdir does not exist and parent isn't writable
313 warnings.warn("IPython parent '%s' is not a writable location,"
313 warnings.warn("IPython parent '%s' is not a writable location,"
314 " using a temp directory."%parent)
314 " using a temp directory."%parent)
315 ipdir = tempfile.mkdtemp()
315 ipdir = tempfile.mkdtemp()
316
316
317 return py3compat.cast_unicode(ipdir, fs_encoding)
317 return py3compat.cast_unicode(ipdir, fs_encoding)
318
318
319
319
320 def get_ipython_cache_dir():
320 def get_ipython_cache_dir():
321 """Get the cache directory it is created if it does not exist."""
321 """Get the cache directory it is created if it does not exist."""
322 xdgdir = get_xdg_cache_dir()
322 xdgdir = get_xdg_cache_dir()
323 if xdgdir is None:
323 if xdgdir is None:
324 return get_ipython_dir()
324 return get_ipython_dir()
325 ipdir = os.path.join(xdgdir, "ipython")
325 ipdir = os.path.join(xdgdir, "ipython")
326 if not os.path.exists(ipdir) and _writable_dir(xdgdir):
326 if not os.path.exists(ipdir) and _writable_dir(xdgdir):
327 os.makedirs(ipdir)
327 os.makedirs(ipdir)
328 elif not _writable_dir(xdgdir):
328 elif not _writable_dir(xdgdir):
329 return get_ipython_dir()
329 return get_ipython_dir()
330
330
331 return py3compat.cast_unicode(ipdir, fs_encoding)
331 return py3compat.cast_unicode(ipdir, fs_encoding)
332
332
333
333
334 def get_ipython_package_dir():
334 def get_ipython_package_dir():
335 """Get the base directory where IPython itself is installed."""
335 """Get the base directory where IPython itself is installed."""
336 ipdir = os.path.dirname(IPython.__file__)
336 ipdir = os.path.dirname(IPython.__file__)
337 return py3compat.cast_unicode(ipdir, fs_encoding)
337 return py3compat.cast_unicode(ipdir, fs_encoding)
338
338
339
339
340 def get_ipython_module_path(module_str):
340 def get_ipython_module_path(module_str):
341 """Find the path to an IPython module in this version of IPython.
341 """Find the path to an IPython module in this version of IPython.
342
342
343 This will always find the version of the module that is in this importable
343 This will always find the version of the module that is in this importable
344 IPython package. This will always return the path to the ``.py``
344 IPython package. This will always return the path to the ``.py``
345 version of the module.
345 version of the module.
346 """
346 """
347 if module_str == 'IPython':
347 if module_str == 'IPython':
348 return os.path.join(get_ipython_package_dir(), '__init__.py')
348 return os.path.join(get_ipython_package_dir(), '__init__.py')
349 mod = import_item(module_str)
349 mod = import_item(module_str)
350 the_path = mod.__file__.replace('.pyc', '.py')
350 the_path = mod.__file__.replace('.pyc', '.py')
351 the_path = the_path.replace('.pyo', '.py')
351 the_path = the_path.replace('.pyo', '.py')
352 return py3compat.cast_unicode(the_path, fs_encoding)
352 return py3compat.cast_unicode(the_path, fs_encoding)
353
353
354 def locate_profile(profile='default'):
354 def locate_profile(profile='default'):
355 """Find the path to the folder associated with a given profile.
355 """Find the path to the folder associated with a given profile.
356
356
357 I.e. find $IPYTHONDIR/profile_whatever.
357 I.e. find $IPYTHONDIR/profile_whatever.
358 """
358 """
359 from IPython.core.profiledir import ProfileDir, ProfileDirError
359 from IPython.core.profiledir import ProfileDir, ProfileDirError
360 try:
360 try:
361 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
361 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
362 except ProfileDirError:
362 except ProfileDirError:
363 # IOError makes more sense when people are expecting a path
363 # IOError makes more sense when people are expecting a path
364 raise IOError("Couldn't find profile %r" % profile)
364 raise IOError("Couldn't find profile %r" % profile)
365 return pd.location
365 return pd.location
366
366
367 def expand_path(s):
367 def expand_path(s):
368 """Expand $VARS and ~names in a string, like a shell
368 """Expand $VARS and ~names in a string, like a shell
369
369
370 :Examples:
370 :Examples:
371
371
372 In [2]: os.environ['FOO']='test'
372 In [2]: os.environ['FOO']='test'
373
373
374 In [3]: expand_path('variable FOO is $FOO')
374 In [3]: expand_path('variable FOO is $FOO')
375 Out[3]: 'variable FOO is test'
375 Out[3]: 'variable FOO is test'
376 """
376 """
377 # This is a pretty subtle hack. When expand user is given a UNC path
377 # This is a pretty subtle hack. When expand user is given a UNC path
378 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
378 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
379 # the $ to get (\\server\share\%username%). I think it considered $
379 # the $ to get (\\server\share\%username%). I think it considered $
380 # alone an empty var. But, we need the $ to remains there (it indicates
380 # alone an empty var. But, we need the $ to remains there (it indicates
381 # a hidden share).
381 # a hidden share).
382 if os.name=='nt':
382 if os.name=='nt':
383 s = s.replace('$\\', 'IPYTHON_TEMP')
383 s = s.replace('$\\', 'IPYTHON_TEMP')
384 s = os.path.expandvars(os.path.expanduser(s))
384 s = os.path.expandvars(os.path.expanduser(s))
385 if os.name=='nt':
385 if os.name=='nt':
386 s = s.replace('IPYTHON_TEMP', '$\\')
386 s = s.replace('IPYTHON_TEMP', '$\\')
387 return s
387 return s
388
388
389
389
390 def unescape_glob(string):
390 def unescape_glob(string):
391 """Unescape glob pattern in `string`."""
391 """Unescape glob pattern in `string`."""
392 def unescape(s):
392 def unescape(s):
393 for pattern in '*[]!?':
393 for pattern in '*[]!?':
394 s = s.replace(r'\{0}'.format(pattern), pattern)
394 s = s.replace(r'\{0}'.format(pattern), pattern)
395 return s
395 return s
396 return '\\'.join(map(unescape, string.split('\\\\')))
396 return '\\'.join(map(unescape, string.split('\\\\')))
397
397
398
398
399 def shellglob(args):
399 def shellglob(args):
400 """
400 """
401 Do glob expansion for each element in `args` and return a flattened list.
401 Do glob expansion for each element in `args` and return a flattened list.
402
402
403 Unmatched glob pattern will remain as-is in the returned list.
403 Unmatched glob pattern will remain as-is in the returned list.
404
404
405 """
405 """
406 expanded = []
406 expanded = []
407 # Do not unescape backslash in Windows as it is interpreted as
407 # Do not unescape backslash in Windows as it is interpreted as
408 # path separator:
408 # path separator:
409 unescape = unescape_glob if sys.platform != 'win32' else lambda x: x
409 unescape = unescape_glob if sys.platform != 'win32' else lambda x: x
410 for a in args:
410 for a in args:
411 expanded.extend(glob.glob(a) or [unescape(a)])
411 expanded.extend(glob.glob(a) or [unescape(a)])
412 return expanded
412 return expanded
413
413
414
414
415 def target_outdated(target,deps):
415 def target_outdated(target,deps):
416 """Determine whether a target is out of date.
416 """Determine whether a target is out of date.
417
417
418 target_outdated(target,deps) -> 1/0
418 target_outdated(target,deps) -> 1/0
419
419
420 deps: list of filenames which MUST exist.
420 deps: list of filenames which MUST exist.
421 target: single filename which may or may not exist.
421 target: single filename which may or may not exist.
422
422
423 If target doesn't exist or is older than any file listed in deps, return
423 If target doesn't exist or is older than any file listed in deps, return
424 true, otherwise return false.
424 true, otherwise return false.
425 """
425 """
426 try:
426 try:
427 target_time = os.path.getmtime(target)
427 target_time = os.path.getmtime(target)
428 except os.error:
428 except os.error:
429 return 1
429 return 1
430 for dep in deps:
430 for dep in deps:
431 dep_time = os.path.getmtime(dep)
431 dep_time = os.path.getmtime(dep)
432 if dep_time > target_time:
432 if dep_time > target_time:
433 #print "For target",target,"Dep failed:",dep # dbg
433 #print "For target",target,"Dep failed:",dep # dbg
434 #print "times (dep,tar):",dep_time,target_time # dbg
434 #print "times (dep,tar):",dep_time,target_time # dbg
435 return 1
435 return 1
436 return 0
436 return 0
437
437
438
438
439 def target_update(target,deps,cmd):
439 def target_update(target,deps,cmd):
440 """Update a target with a given command given a list of dependencies.
440 """Update a target with a given command given a list of dependencies.
441
441
442 target_update(target,deps,cmd) -> runs cmd if target is outdated.
442 target_update(target,deps,cmd) -> runs cmd if target is outdated.
443
443
444 This is just a wrapper around target_outdated() which calls the given
444 This is just a wrapper around target_outdated() which calls the given
445 command if target is outdated."""
445 command if target is outdated."""
446
446
447 if target_outdated(target,deps):
447 if target_outdated(target,deps):
448 system(cmd)
448 system(cmd)
449
449
450 def filehash(path):
450 def filehash(path):
451 """Make an MD5 hash of a file, ignoring any differences in line
451 """Make an MD5 hash of a file, ignoring any differences in line
452 ending characters."""
452 ending characters."""
453 with open(path, "rU") as f:
453 with open(path, "rU") as f:
454 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
454 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
455
455
456 # If the config is unmodified from the default, we'll just delete it.
456 # If the config is unmodified from the default, we'll just delete it.
457 # These are consistent for 0.10.x, thankfully. We're not going to worry about
457 # These are consistent for 0.10.x, thankfully. We're not going to worry about
458 # older versions.
458 # older versions.
459 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
459 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
460 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
460 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
461
461
462 def check_for_old_config(ipython_dir=None):
462 def check_for_old_config(ipython_dir=None):
463 """Check for old config files, and present a warning if they exist.
463 """Check for old config files, and present a warning if they exist.
464
464
465 A link to the docs of the new config is included in the message.
465 A link to the docs of the new config is included in the message.
466
466
467 This should mitigate confusion with the transition to the new
467 This should mitigate confusion with the transition to the new
468 config system in 0.11.
468 config system in 0.11.
469 """
469 """
470 if ipython_dir is None:
470 if ipython_dir is None:
471 ipython_dir = get_ipython_dir()
471 ipython_dir = get_ipython_dir()
472
472
473 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
473 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
474 warned = False
474 warned = False
475 for cfg in old_configs:
475 for cfg in old_configs:
476 f = os.path.join(ipython_dir, cfg)
476 f = os.path.join(ipython_dir, cfg)
477 if os.path.exists(f):
477 if os.path.exists(f):
478 if filehash(f) == old_config_md5.get(cfg, ''):
478 if filehash(f) == old_config_md5.get(cfg, ''):
479 os.unlink(f)
479 os.unlink(f)
480 else:
480 else:
481 warnings.warn("Found old IPython config file %r (modified by user)"%f)
481 warnings.warn("Found old IPython config file %r (modified by user)"%f)
482 warned = True
482 warned = True
483
483
484 if warned:
484 if warned:
485 warnings.warn("""
485 warnings.warn("""
486 The IPython configuration system has changed as of 0.11, and these files will
486 The IPython configuration system has changed as of 0.11, and these files will
487 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
487 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
488 of the new config system.
488 of the new config system.
489 To start configuring IPython, do `ipython profile create`, and edit
489 To start configuring IPython, do `ipython profile create`, and edit
490 `ipython_config.py` in <ipython_dir>/profile_default.
490 `ipython_config.py` in <ipython_dir>/profile_default.
491 If you need to leave the old config files in place for an older version of
491 If you need to leave the old config files in place for an older version of
492 IPython and want to suppress this warning message, set
492 IPython and want to suppress this warning message, set
493 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
493 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
494
494
495 def get_security_file(filename, profile='default'):
495 def get_security_file(filename, profile='default'):
496 """Return the absolute path of a security file given by filename and profile
496 """Return the absolute path of a security file given by filename and profile
497
497
498 This allows users and developers to find security files without
498 This allows users and developers to find security files without
499 knowledge of the IPython directory structure. The search path
499 knowledge of the IPython directory structure. The search path
500 will be ['.', profile.security_dir]
500 will be ['.', profile.security_dir]
501
501
502 Parameters
502 Parameters
503 ----------
503 ----------
504
504
505 filename : str
505 filename : str
506 The file to be found. If it is passed as an absolute path, it will
506 The file to be found. If it is passed as an absolute path, it will
507 simply be returned.
507 simply be returned.
508 profile : str [default: 'default']
508 profile : str [default: 'default']
509 The name of the profile to search. Leaving this unspecified
509 The name of the profile to search. Leaving this unspecified
510 The file to be found. If it is passed as an absolute path, fname will
510 The file to be found. If it is passed as an absolute path, fname will
511 simply be returned.
511 simply be returned.
512
512
513 Returns
513 Returns
514 -------
514 -------
515 Raises :exc:`IOError` if file not found or returns absolute path to file.
515 Raises :exc:`IOError` if file not found or returns absolute path to file.
516 """
516 """
517 # import here, because profiledir also imports from utils.path
517 # import here, because profiledir also imports from utils.path
518 from IPython.core.profiledir import ProfileDir
518 from IPython.core.profiledir import ProfileDir
519 try:
519 try:
520 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
520 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
521 except Exception:
521 except Exception:
522 # will raise ProfileDirError if no such profile
522 # will raise ProfileDirError if no such profile
523 raise IOError("Profile %r not found")
523 raise IOError("Profile %r not found")
524 return filefind(filename, ['.', pd.security_dir])
524 return filefind(filename, ['.', pd.security_dir])
525
525
526
526
527 ENOLINK = 1998
527 ENOLINK = 1998
528
528
529 def link(src, dst):
529 def link(src, dst):
530 """Hard links ``src`` to ``dst``, returning 0 or errno.
530 """Hard links ``src`` to ``dst``, returning 0 or errno.
531
531
532 Note that the special errno ``ENOLINK`` will be returned if ``os.link`` isn't
532 Note that the special errno ``ENOLINK`` will be returned if ``os.link`` isn't
533 supported by the operating system.
533 supported by the operating system.
534 """
534 """
535
535
536 if not hasattr(os, "link"):
536 if not hasattr(os, "link"):
537 return ENOLINK
537 return ENOLINK
538 link_errno = 0
538 link_errno = 0
539 try:
539 try:
540 os.link(src, dst)
540 os.link(src, dst)
541 except OSError as e:
541 except OSError as e:
542 link_errno = e.errno
542 link_errno = e.errno
543 return link_errno
543 return link_errno
544
544
545
545
546 def link_or_copy(src, dst):
546 def link_or_copy(src, dst):
547 """Attempts to hardlink ``src`` to ``dst``, copying if the link fails.
547 """Attempts to hardlink ``src`` to ``dst``, copying if the link fails.
548
548
549 Attempts to maintain the semantics of ``shutil.copy``.
549 Attempts to maintain the semantics of ``shutil.copy``.
550
550
551 Because ``os.link`` does not overwrite files, a unique temporary file
551 Because ``os.link`` does not overwrite files, a unique temporary file
552 will be used if the target already exists, then that file will be moved
552 will be used if the target already exists, then that file will be moved
553 into place.
553 into place.
554 """
554 """
555
555
556 if os.path.isdir(dst):
556 if os.path.isdir(dst):
557 dst = os.path.join(dst, os.path.basename(src))
557 dst = os.path.join(dst, os.path.basename(src))
558
558
559 link_errno = link(src, dst)
559 link_errno = link(src, dst)
560 if link_errno == errno.EEXIST:
560 if link_errno == errno.EEXIST:
561 new_dst = dst + "-temp-%04X" %(random.randint(1, 16**4), )
561 new_dst = dst + "-temp-%04X" %(random.randint(1, 16**4), )
562 try:
562 try:
563 link_or_copy(src, new_dst)
563 link_or_copy(src, new_dst)
564 except:
564 except:
565 try:
565 try:
566 os.remove(new_dst)
566 os.remove(new_dst)
567 except OSError:
567 except OSError:
568 pass
568 pass
569 raise
569 raise
570 os.rename(new_dst, dst)
570 os.rename(new_dst, dst)
571 elif link_errno != 0:
571 elif link_errno != 0:
572 # Either link isn't supported, or the filesystem doesn't support
572 # Either link isn't supported, or the filesystem doesn't support
573 # linking, or 'src' and 'dst' are on different filesystems.
573 # linking, or 'src' and 'dst' are on different filesystems.
574 shutil.copy(src, dst)
574 shutil.copy(src, dst)
@@ -1,122 +1,123 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for working with external processes.
3 Utilities for working with external processes.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Stdlib
18 # Stdlib
19 import os
19 import os
20 import sys
20 import sys
21 import shlex
21 import shlex
22
22
23 # Our own
23 # Our own
24 if sys.platform == 'win32':
24 if sys.platform == 'win32':
25 from ._process_win32 import _find_cmd, system, getoutput, AvoidUNCPath, arg_split
25 from ._process_win32 import _find_cmd, system, getoutput, AvoidUNCPath, arg_split
26 else:
26 else:
27 from ._process_posix import _find_cmd, system, getoutput, arg_split
27 from ._process_posix import _find_cmd, system, getoutput, arg_split
28
28
29
29
30 from ._process_common import getoutputerror, get_output_error_code
30 from ._process_common import getoutputerror, get_output_error_code
31 from . import py3compat
31
32
32 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
33 # Code
34 # Code
34 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
35
36
36
37
37 class FindCmdError(Exception):
38 class FindCmdError(Exception):
38 pass
39 pass
39
40
40
41
41 def find_cmd(cmd):
42 def find_cmd(cmd):
42 """Find absolute path to executable cmd in a cross platform manner.
43 """Find absolute path to executable cmd in a cross platform manner.
43
44
44 This function tries to determine the full path to a command line program
45 This function tries to determine the full path to a command line program
45 using `which` on Unix/Linux/OS X and `win32api` on Windows. Most of the
46 using `which` on Unix/Linux/OS X and `win32api` on Windows. Most of the
46 time it will use the version that is first on the users `PATH`.
47 time it will use the version that is first on the users `PATH`.
47
48
48 Warning, don't use this to find IPython command line programs as there
49 Warning, don't use this to find IPython command line programs as there
49 is a risk you will find the wrong one. Instead find those using the
50 is a risk you will find the wrong one. Instead find those using the
50 following code and looking for the application itself::
51 following code and looking for the application itself::
51
52
52 from IPython.utils.path import get_ipython_module_path
53 from IPython.utils.path import get_ipython_module_path
53 from IPython.utils.process import pycmd2argv
54 from IPython.utils.process import pycmd2argv
54 argv = pycmd2argv(get_ipython_module_path('IPython.terminal.ipapp'))
55 argv = pycmd2argv(get_ipython_module_path('IPython.terminal.ipapp'))
55
56
56 Parameters
57 Parameters
57 ----------
58 ----------
58 cmd : str
59 cmd : str
59 The command line program to look for.
60 The command line program to look for.
60 """
61 """
61 try:
62 try:
62 path = _find_cmd(cmd).rstrip()
63 path = _find_cmd(cmd).rstrip()
63 except OSError:
64 except OSError:
64 raise FindCmdError('command could not be found: %s' % cmd)
65 raise FindCmdError('command could not be found: %s' % cmd)
65 # which returns empty if not found
66 # which returns empty if not found
66 if path == '':
67 if path == '':
67 raise FindCmdError('command could not be found: %s' % cmd)
68 raise FindCmdError('command could not be found: %s' % cmd)
68 return os.path.abspath(path)
69 return os.path.abspath(path)
69
70
70
71
71 def is_cmd_found(cmd):
72 def is_cmd_found(cmd):
72 """Check whether executable `cmd` exists or not and return a bool."""
73 """Check whether executable `cmd` exists or not and return a bool."""
73 try:
74 try:
74 find_cmd(cmd)
75 find_cmd(cmd)
75 return True
76 return True
76 except FindCmdError:
77 except FindCmdError:
77 return False
78 return False
78
79
79
80
80 def pycmd2argv(cmd):
81 def pycmd2argv(cmd):
81 r"""Take the path of a python command and return a list (argv-style).
82 r"""Take the path of a python command and return a list (argv-style).
82
83
83 This only works on Python based command line programs and will find the
84 This only works on Python based command line programs and will find the
84 location of the ``python`` executable using ``sys.executable`` to make
85 location of the ``python`` executable using ``sys.executable`` to make
85 sure the right version is used.
86 sure the right version is used.
86
87
87 For a given path ``cmd``, this returns [cmd] if cmd's extension is .exe,
88 For a given path ``cmd``, this returns [cmd] if cmd's extension is .exe,
88 .com or .bat, and [, cmd] otherwise.
89 .com or .bat, and [, cmd] otherwise.
89
90
90 Parameters
91 Parameters
91 ----------
92 ----------
92 cmd : string
93 cmd : string
93 The path of the command.
94 The path of the command.
94
95
95 Returns
96 Returns
96 -------
97 -------
97 argv-style list.
98 argv-style list.
98 """
99 """
99 ext = os.path.splitext(cmd)[1]
100 ext = os.path.splitext(cmd)[1]
100 if ext in ['.exe', '.com', '.bat']:
101 if ext in ['.exe', '.com', '.bat']:
101 return [cmd]
102 return [cmd]
102 else:
103 else:
103 return [sys.executable, cmd]
104 return [sys.executable, cmd]
104
105
105
106
106 def abbrev_cwd():
107 def abbrev_cwd():
107 """ Return abbreviated version of cwd, e.g. d:mydir """
108 """ Return abbreviated version of cwd, e.g. d:mydir """
108 cwd = os.getcwdu().replace('\\','/')
109 cwd = py3compat.getcwd().replace('\\','/')
109 drivepart = ''
110 drivepart = ''
110 tail = cwd
111 tail = cwd
111 if sys.platform == 'win32':
112 if sys.platform == 'win32':
112 if len(cwd) < 4:
113 if len(cwd) < 4:
113 return cwd
114 return cwd
114 drivepart,tail = os.path.splitdrive(cwd)
115 drivepart,tail = os.path.splitdrive(cwd)
115
116
116
117
117 parts = tail.split('/')
118 parts = tail.split('/')
118 if len(parts) > 2:
119 if len(parts) > 2:
119 tail = '/'.join(parts[-2:])
120 tail = '/'.join(parts[-2:])
120
121
121 return (drivepart + (
122 return (drivepart + (
122 cwd == '/' and '/' or tail))
123 cwd == '/' and '/' or tail))
@@ -1,239 +1,242 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Compatibility tricks for Python 3. Mainly to do with unicode."""
2 """Compatibility tricks for Python 3. Mainly to do with unicode."""
3 import functools
3 import functools
4 import os
4 import sys
5 import sys
5 import re
6 import re
6 import types
7 import types
7
8
8 from .encoding import DEFAULT_ENCODING
9 from .encoding import DEFAULT_ENCODING
9
10
10 orig_open = open
11 orig_open = open
11
12
12 def no_code(x, encoding=None):
13 def no_code(x, encoding=None):
13 return x
14 return x
14
15
15 def decode(s, encoding=None):
16 def decode(s, encoding=None):
16 encoding = encoding or DEFAULT_ENCODING
17 encoding = encoding or DEFAULT_ENCODING
17 return s.decode(encoding, "replace")
18 return s.decode(encoding, "replace")
18
19
19 def encode(u, encoding=None):
20 def encode(u, encoding=None):
20 encoding = encoding or DEFAULT_ENCODING
21 encoding = encoding or DEFAULT_ENCODING
21 return u.encode(encoding, "replace")
22 return u.encode(encoding, "replace")
22
23
23
24
24 def cast_unicode(s, encoding=None):
25 def cast_unicode(s, encoding=None):
25 if isinstance(s, bytes):
26 if isinstance(s, bytes):
26 return decode(s, encoding)
27 return decode(s, encoding)
27 return s
28 return s
28
29
29 def cast_bytes(s, encoding=None):
30 def cast_bytes(s, encoding=None):
30 if not isinstance(s, bytes):
31 if not isinstance(s, bytes):
31 return encode(s, encoding)
32 return encode(s, encoding)
32 return s
33 return s
33
34
34 def _modify_str_or_docstring(str_change_func):
35 def _modify_str_or_docstring(str_change_func):
35 @functools.wraps(str_change_func)
36 @functools.wraps(str_change_func)
36 def wrapper(func_or_str):
37 def wrapper(func_or_str):
37 if isinstance(func_or_str, string_types):
38 if isinstance(func_or_str, string_types):
38 func = None
39 func = None
39 doc = func_or_str
40 doc = func_or_str
40 else:
41 else:
41 func = func_or_str
42 func = func_or_str
42 doc = func.__doc__
43 doc = func.__doc__
43
44
44 doc = str_change_func(doc)
45 doc = str_change_func(doc)
45
46
46 if func:
47 if func:
47 func.__doc__ = doc
48 func.__doc__ = doc
48 return func
49 return func
49 return doc
50 return doc
50 return wrapper
51 return wrapper
51
52
52 def safe_unicode(e):
53 def safe_unicode(e):
53 """unicode(e) with various fallbacks. Used for exceptions, which may not be
54 """unicode(e) with various fallbacks. Used for exceptions, which may not be
54 safe to call unicode() on.
55 safe to call unicode() on.
55 """
56 """
56 try:
57 try:
57 return unicode_type(e)
58 return unicode_type(e)
58 except UnicodeError:
59 except UnicodeError:
59 pass
60 pass
60
61
61 try:
62 try:
62 return str_to_unicode(str(e))
63 return str_to_unicode(str(e))
63 except UnicodeError:
64 except UnicodeError:
64 pass
65 pass
65
66
66 try:
67 try:
67 return str_to_unicode(repr(e))
68 return str_to_unicode(repr(e))
68 except UnicodeError:
69 except UnicodeError:
69 pass
70 pass
70
71
71 return u'Unrecoverably corrupt evalue'
72 return u'Unrecoverably corrupt evalue'
72
73
73 if sys.version_info[0] >= 3:
74 if sys.version_info[0] >= 3:
74 PY3 = True
75 PY3 = True
75
76
76 input = input
77 input = input
77 builtin_mod_name = "builtins"
78 builtin_mod_name = "builtins"
78 import builtins as builtin_mod
79 import builtins as builtin_mod
79
80
80 str_to_unicode = no_code
81 str_to_unicode = no_code
81 unicode_to_str = no_code
82 unicode_to_str = no_code
82 str_to_bytes = encode
83 str_to_bytes = encode
83 bytes_to_str = decode
84 bytes_to_str = decode
84 cast_bytes_py2 = no_code
85 cast_bytes_py2 = no_code
85
86
86 string_types = (str,)
87 string_types = (str,)
87 unicode_type = str
88 unicode_type = str
88
89
89 def isidentifier(s, dotted=False):
90 def isidentifier(s, dotted=False):
90 if dotted:
91 if dotted:
91 return all(isidentifier(a) for a in s.split("."))
92 return all(isidentifier(a) for a in s.split("."))
92 return s.isidentifier()
93 return s.isidentifier()
93
94
94 open = orig_open
95 open = orig_open
95 xrange = range
96 xrange = range
96 def iteritems(d): return iter(d.items())
97 def iteritems(d): return iter(d.items())
97 def itervalues(d): return iter(d.values())
98 def itervalues(d): return iter(d.values())
99 getcwd = os.getcwd
98
100
99 MethodType = types.MethodType
101 MethodType = types.MethodType
100
102
101 def execfile(fname, glob, loc=None):
103 def execfile(fname, glob, loc=None):
102 loc = loc if (loc is not None) else glob
104 loc = loc if (loc is not None) else glob
103 with open(fname, 'rb') as f:
105 with open(fname, 'rb') as f:
104 exec(compile(f.read(), fname, 'exec'), glob, loc)
106 exec(compile(f.read(), fname, 'exec'), glob, loc)
105
107
106 # Refactor print statements in doctests.
108 # Refactor print statements in doctests.
107 _print_statement_re = re.compile(r"\bprint (?P<expr>.*)$", re.MULTILINE)
109 _print_statement_re = re.compile(r"\bprint (?P<expr>.*)$", re.MULTILINE)
108 def _print_statement_sub(match):
110 def _print_statement_sub(match):
109 expr = match.groups('expr')
111 expr = match.groups('expr')
110 return "print(%s)" % expr
112 return "print(%s)" % expr
111
113
112 @_modify_str_or_docstring
114 @_modify_str_or_docstring
113 def doctest_refactor_print(doc):
115 def doctest_refactor_print(doc):
114 """Refactor 'print x' statements in a doctest to print(x) style. 2to3
116 """Refactor 'print x' statements in a doctest to print(x) style. 2to3
115 unfortunately doesn't pick up on our doctests.
117 unfortunately doesn't pick up on our doctests.
116
118
117 Can accept a string or a function, so it can be used as a decorator."""
119 Can accept a string or a function, so it can be used as a decorator."""
118 return _print_statement_re.sub(_print_statement_sub, doc)
120 return _print_statement_re.sub(_print_statement_sub, doc)
119
121
120 # Abstract u'abc' syntax:
122 # Abstract u'abc' syntax:
121 @_modify_str_or_docstring
123 @_modify_str_or_docstring
122 def u_format(s):
124 def u_format(s):
123 """"{u}'abc'" --> "'abc'" (Python 3)
125 """"{u}'abc'" --> "'abc'" (Python 3)
124
126
125 Accepts a string or a function, so it can be used as a decorator."""
127 Accepts a string or a function, so it can be used as a decorator."""
126 return s.format(u='')
128 return s.format(u='')
127
129
128 else:
130 else:
129 PY3 = False
131 PY3 = False
130
132
131 input = raw_input
133 input = raw_input
132 builtin_mod_name = "__builtin__"
134 builtin_mod_name = "__builtin__"
133 import __builtin__ as builtin_mod
135 import __builtin__ as builtin_mod
134
136
135 str_to_unicode = decode
137 str_to_unicode = decode
136 unicode_to_str = encode
138 unicode_to_str = encode
137 str_to_bytes = no_code
139 str_to_bytes = no_code
138 bytes_to_str = no_code
140 bytes_to_str = no_code
139 cast_bytes_py2 = cast_bytes
141 cast_bytes_py2 = cast_bytes
140
142
141 string_types = (str, unicode)
143 string_types = (str, unicode)
142 unicode_type = unicode
144 unicode_type = unicode
143
145
144 import re
146 import re
145 _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
147 _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
146 def isidentifier(s, dotted=False):
148 def isidentifier(s, dotted=False):
147 if dotted:
149 if dotted:
148 return all(isidentifier(a) for a in s.split("."))
150 return all(isidentifier(a) for a in s.split("."))
149 return bool(_name_re.match(s))
151 return bool(_name_re.match(s))
150
152
151 class open(object):
153 class open(object):
152 """Wrapper providing key part of Python 3 open() interface."""
154 """Wrapper providing key part of Python 3 open() interface."""
153 def __init__(self, fname, mode="r", encoding="utf-8"):
155 def __init__(self, fname, mode="r", encoding="utf-8"):
154 self.f = orig_open(fname, mode)
156 self.f = orig_open(fname, mode)
155 self.enc = encoding
157 self.enc = encoding
156
158
157 def write(self, s):
159 def write(self, s):
158 return self.f.write(s.encode(self.enc))
160 return self.f.write(s.encode(self.enc))
159
161
160 def read(self, size=-1):
162 def read(self, size=-1):
161 return self.f.read(size).decode(self.enc)
163 return self.f.read(size).decode(self.enc)
162
164
163 def close(self):
165 def close(self):
164 return self.f.close()
166 return self.f.close()
165
167
166 def __enter__(self):
168 def __enter__(self):
167 return self
169 return self
168
170
169 def __exit__(self, etype, value, traceback):
171 def __exit__(self, etype, value, traceback):
170 self.f.close()
172 self.f.close()
171
173
172 xrange = xrange
174 xrange = xrange
173 def iteritems(d): return d.iteritems()
175 def iteritems(d): return d.iteritems()
174 def itervalues(d): return d.itervalues()
176 def itervalues(d): return d.itervalues()
177 getcwd = os.getcwdu
175
178
176 def MethodType(func, instance):
179 def MethodType(func, instance):
177 return types.MethodType(func, instance, type(instance))
180 return types.MethodType(func, instance, type(instance))
178
181
179 # don't override system execfile on 2.x:
182 # don't override system execfile on 2.x:
180 execfile = execfile
183 execfile = execfile
181
184
182 def doctest_refactor_print(func_or_str):
185 def doctest_refactor_print(func_or_str):
183 return func_or_str
186 return func_or_str
184
187
185
188
186 # Abstract u'abc' syntax:
189 # Abstract u'abc' syntax:
187 @_modify_str_or_docstring
190 @_modify_str_or_docstring
188 def u_format(s):
191 def u_format(s):
189 """"{u}'abc'" --> "u'abc'" (Python 2)
192 """"{u}'abc'" --> "u'abc'" (Python 2)
190
193
191 Accepts a string or a function, so it can be used as a decorator."""
194 Accepts a string or a function, so it can be used as a decorator."""
192 return s.format(u='u')
195 return s.format(u='u')
193
196
194 if sys.platform == 'win32':
197 if sys.platform == 'win32':
195 def execfile(fname, glob=None, loc=None):
198 def execfile(fname, glob=None, loc=None):
196 loc = loc if (loc is not None) else glob
199 loc = loc if (loc is not None) else glob
197 # The rstrip() is necessary b/c trailing whitespace in files will
200 # The rstrip() is necessary b/c trailing whitespace in files will
198 # cause an IndentationError in Python 2.6 (this was fixed in 2.7,
201 # cause an IndentationError in Python 2.6 (this was fixed in 2.7,
199 # but we still support 2.6). See issue 1027.
202 # but we still support 2.6). See issue 1027.
200 scripttext = builtin_mod.open(fname).read().rstrip() + '\n'
203 scripttext = builtin_mod.open(fname).read().rstrip() + '\n'
201 # compile converts unicode filename to str assuming
204 # compile converts unicode filename to str assuming
202 # ascii. Let's do the conversion before calling compile
205 # ascii. Let's do the conversion before calling compile
203 if isinstance(fname, unicode):
206 if isinstance(fname, unicode):
204 filename = unicode_to_str(fname)
207 filename = unicode_to_str(fname)
205 else:
208 else:
206 filename = fname
209 filename = fname
207 exec(compile(scripttext, filename, 'exec'), glob, loc)
210 exec(compile(scripttext, filename, 'exec'), glob, loc)
208 else:
211 else:
209 def execfile(fname, *where):
212 def execfile(fname, *where):
210 if isinstance(fname, unicode):
213 if isinstance(fname, unicode):
211 filename = fname.encode(sys.getfilesystemencoding())
214 filename = fname.encode(sys.getfilesystemencoding())
212 else:
215 else:
213 filename = fname
216 filename = fname
214 builtin_mod.execfile(filename, *where)
217 builtin_mod.execfile(filename, *where)
215
218
216 # Parts below taken from six:
219 # Parts below taken from six:
217 # Copyright (c) 2010-2013 Benjamin Peterson
220 # Copyright (c) 2010-2013 Benjamin Peterson
218 #
221 #
219 # Permission is hereby granted, free of charge, to any person obtaining a copy
222 # Permission is hereby granted, free of charge, to any person obtaining a copy
220 # of this software and associated documentation files (the "Software"), to deal
223 # of this software and associated documentation files (the "Software"), to deal
221 # in the Software without restriction, including without limitation the rights
224 # in the Software without restriction, including without limitation the rights
222 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
225 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
223 # copies of the Software, and to permit persons to whom the Software is
226 # copies of the Software, and to permit persons to whom the Software is
224 # furnished to do so, subject to the following conditions:
227 # furnished to do so, subject to the following conditions:
225 #
228 #
226 # The above copyright notice and this permission notice shall be included in all
229 # The above copyright notice and this permission notice shall be included in all
227 # copies or substantial portions of the Software.
230 # copies or substantial portions of the Software.
228 #
231 #
229 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
232 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
230 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
233 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
231 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
234 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
232 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
235 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
233 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
236 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
234 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
237 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
235 # SOFTWARE.
238 # SOFTWARE.
236
239
237 def with_metaclass(meta, *bases):
240 def with_metaclass(meta, *bases):
238 """Create a base class with a metaclass."""
241 """Create a base class with a metaclass."""
239 return meta("NewBase", bases, {})
242 return meta("NewBase", bases, {})
@@ -1,162 +1,164 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for working with terminals.
3 Utilities for working with terminals.
4
4
5 Authors:
5 Authors:
6
6
7 * Brian E. Granger
7 * Brian E. Granger
8 * Fernando Perez
8 * Fernando Perez
9 * Alexander Belchenko (e-mail: bialix AT ukr.net)
9 * Alexander Belchenko (e-mail: bialix AT ukr.net)
10 """
10 """
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2011 The IPython Development Team
13 # Copyright (C) 2008-2011 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import os
23 import os
24 import struct
24 import struct
25 import sys
25 import sys
26 import warnings
26 import warnings
27
27
28 from . import py3compat
29
28 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
29 # Code
31 # Code
30 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
31
33
32 # This variable is part of the expected API of the module:
34 # This variable is part of the expected API of the module:
33 ignore_termtitle = True
35 ignore_termtitle = True
34
36
35
37
36 def _term_clear():
38 def _term_clear():
37 pass
39 pass
38
40
39
41
40 if os.name == 'posix':
42 if os.name == 'posix':
41 def _term_clear():
43 def _term_clear():
42 os.system('clear')
44 os.system('clear')
43
45
44
46
45 if sys.platform == 'win32':
47 if sys.platform == 'win32':
46 def _term_clear():
48 def _term_clear():
47 os.system('cls')
49 os.system('cls')
48
50
49
51
50 def term_clear():
52 def term_clear():
51 _term_clear()
53 _term_clear()
52
54
53
55
54 def toggle_set_term_title(val):
56 def toggle_set_term_title(val):
55 """Control whether set_term_title is active or not.
57 """Control whether set_term_title is active or not.
56
58
57 set_term_title() allows writing to the console titlebar. In embedded
59 set_term_title() allows writing to the console titlebar. In embedded
58 widgets this can cause problems, so this call can be used to toggle it on
60 widgets this can cause problems, so this call can be used to toggle it on
59 or off as needed.
61 or off as needed.
60
62
61 The default state of the module is for the function to be disabled.
63 The default state of the module is for the function to be disabled.
62
64
63 Parameters
65 Parameters
64 ----------
66 ----------
65 val : bool
67 val : bool
66 If True, set_term_title() actually writes to the terminal (using the
68 If True, set_term_title() actually writes to the terminal (using the
67 appropriate platform-specific module). If False, it is a no-op.
69 appropriate platform-specific module). If False, it is a no-op.
68 """
70 """
69 global ignore_termtitle
71 global ignore_termtitle
70 ignore_termtitle = not(val)
72 ignore_termtitle = not(val)
71
73
72
74
73 def _set_term_title(*args,**kw):
75 def _set_term_title(*args,**kw):
74 """Dummy no-op."""
76 """Dummy no-op."""
75 pass
77 pass
76
78
77
79
78 def _set_term_title_xterm(title):
80 def _set_term_title_xterm(title):
79 """ Change virtual terminal title in xterm-workalikes """
81 """ Change virtual terminal title in xterm-workalikes """
80 sys.stdout.write('\033]0;%s\007' % title)
82 sys.stdout.write('\033]0;%s\007' % title)
81
83
82 if os.name == 'posix':
84 if os.name == 'posix':
83 TERM = os.environ.get('TERM','')
85 TERM = os.environ.get('TERM','')
84 if TERM.startswith('xterm'):
86 if TERM.startswith('xterm'):
85 _set_term_title = _set_term_title_xterm
87 _set_term_title = _set_term_title_xterm
86
88
87
89
88 if sys.platform == 'win32':
90 if sys.platform == 'win32':
89 try:
91 try:
90 import ctypes
92 import ctypes
91
93
92 SetConsoleTitleW = ctypes.windll.kernel32.SetConsoleTitleW
94 SetConsoleTitleW = ctypes.windll.kernel32.SetConsoleTitleW
93 SetConsoleTitleW.argtypes = [ctypes.c_wchar_p]
95 SetConsoleTitleW.argtypes = [ctypes.c_wchar_p]
94
96
95 def _set_term_title(title):
97 def _set_term_title(title):
96 """Set terminal title using ctypes to access the Win32 APIs."""
98 """Set terminal title using ctypes to access the Win32 APIs."""
97 SetConsoleTitleW(title)
99 SetConsoleTitleW(title)
98 except ImportError:
100 except ImportError:
99 def _set_term_title(title):
101 def _set_term_title(title):
100 """Set terminal title using the 'title' command."""
102 """Set terminal title using the 'title' command."""
101 global ignore_termtitle
103 global ignore_termtitle
102
104
103 try:
105 try:
104 # Cannot be on network share when issuing system commands
106 # Cannot be on network share when issuing system commands
105 curr = os.getcwdu()
107 curr = py3compat.getcwd()
106 os.chdir("C:")
108 os.chdir("C:")
107 ret = os.system("title " + title)
109 ret = os.system("title " + title)
108 finally:
110 finally:
109 os.chdir(curr)
111 os.chdir(curr)
110 if ret:
112 if ret:
111 # non-zero return code signals error, don't try again
113 # non-zero return code signals error, don't try again
112 ignore_termtitle = True
114 ignore_termtitle = True
113
115
114
116
115 def set_term_title(title):
117 def set_term_title(title):
116 """Set terminal title using the necessary platform-dependent calls."""
118 """Set terminal title using the necessary platform-dependent calls."""
117 if ignore_termtitle:
119 if ignore_termtitle:
118 return
120 return
119 _set_term_title(title)
121 _set_term_title(title)
120
122
121
123
122 def freeze_term_title():
124 def freeze_term_title():
123 warnings.warn("This function is deprecated, use toggle_set_term_title()")
125 warnings.warn("This function is deprecated, use toggle_set_term_title()")
124 global ignore_termtitle
126 global ignore_termtitle
125 ignore_termtitle = True
127 ignore_termtitle = True
126
128
127
129
128 def get_terminal_size(defaultx=80, defaulty=25):
130 def get_terminal_size(defaultx=80, defaulty=25):
129 return defaultx, defaulty
131 return defaultx, defaulty
130
132
131
133
132 if sys.platform == 'win32':
134 if sys.platform == 'win32':
133 def get_terminal_size(defaultx=80, defaulty=25):
135 def get_terminal_size(defaultx=80, defaulty=25):
134 """Return size of current terminal console.
136 """Return size of current terminal console.
135
137
136 This function try to determine actual size of current working
138 This function try to determine actual size of current working
137 console window and return tuple (sizex, sizey) if success,
139 console window and return tuple (sizex, sizey) if success,
138 or default size (defaultx, defaulty) otherwise.
140 or default size (defaultx, defaulty) otherwise.
139
141
140 Dependencies: ctypes should be installed.
142 Dependencies: ctypes should be installed.
141
143
142 Author: Alexander Belchenko (e-mail: bialix AT ukr.net)
144 Author: Alexander Belchenko (e-mail: bialix AT ukr.net)
143 """
145 """
144 try:
146 try:
145 import ctypes
147 import ctypes
146 except ImportError:
148 except ImportError:
147 return defaultx, defaulty
149 return defaultx, defaulty
148
150
149 h = ctypes.windll.kernel32.GetStdHandle(-11)
151 h = ctypes.windll.kernel32.GetStdHandle(-11)
150 csbi = ctypes.create_string_buffer(22)
152 csbi = ctypes.create_string_buffer(22)
151 res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
153 res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
152
154
153 if res:
155 if res:
154 (bufx, bufy, curx, cury, wattr,
156 (bufx, bufy, curx, cury, wattr,
155 left, top, right, bottom, maxx, maxy) = struct.unpack(
157 left, top, right, bottom, maxx, maxy) = struct.unpack(
156 "hhhhHhhhhhh", csbi.raw)
158 "hhhhHhhhhhh", csbi.raw)
157 sizex = right - left + 1
159 sizex = right - left + 1
158 sizey = bottom - top + 1
160 sizey = bottom - top + 1
159 return (sizex, sizey)
161 return (sizex, sizey)
160 else:
162 else:
161 return (defaultx, defaulty)
163 return (defaultx, defaulty)
162
164
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now