##// END OF EJS Templates
rm cast_bytes_py2
Srinivas Reddy Thatiparthy -
Show More

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

@@ -1,458 +1,454 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
11
12 # Copyright (c) IPython Development Team.
12 # Copyright (c) IPython Development Team.
13 # Distributed under the terms of the Modified BSD License.
13 # Distributed under the terms of the Modified BSD License.
14
14
15 import atexit
15 import atexit
16 from copy import deepcopy
16 from copy import deepcopy
17 import glob
17 import glob
18 import logging
18 import logging
19 import os
19 import os
20 import shutil
20 import shutil
21 import sys
21 import sys
22
22
23 from traitlets.config.application import Application, catch_config_error
23 from traitlets.config.application import Application, catch_config_error
24 from traitlets.config.loader import ConfigFileNotFound, PyFileConfigLoader
24 from traitlets.config.loader import ConfigFileNotFound, PyFileConfigLoader
25 from IPython.core import release, crashhandler
25 from IPython.core import release, crashhandler
26 from IPython.core.profiledir import ProfileDir, ProfileDirError
26 from IPython.core.profiledir import ProfileDir, ProfileDirError
27 from IPython.paths import get_ipython_dir, get_ipython_package_dir
27 from IPython.paths import get_ipython_dir, get_ipython_package_dir
28 from IPython.utils.path import ensure_dir_exists
28 from IPython.utils.path import ensure_dir_exists
29 from IPython.utils import py3compat
29 from IPython.utils import py3compat
30 from traitlets import (
30 from traitlets import (
31 List, Unicode, Type, Bool, Dict, Set, Instance, Undefined,
31 List, Unicode, Type, Bool, Dict, Set, Instance, Undefined,
32 default, observe,
32 default, observe,
33 )
33 )
34
34
35 if os.name == 'nt':
35 if os.name == 'nt':
36 programdata = os.environ.get('PROGRAMDATA', None)
36 programdata = os.environ.get('PROGRAMDATA', None)
37 if programdata:
37 if programdata:
38 SYSTEM_CONFIG_DIRS = [os.path.join(programdata, 'ipython')]
38 SYSTEM_CONFIG_DIRS = [os.path.join(programdata, 'ipython')]
39 else: # PROGRAMDATA is not defined by default on XP.
39 else: # PROGRAMDATA is not defined by default on XP.
40 SYSTEM_CONFIG_DIRS = []
40 SYSTEM_CONFIG_DIRS = []
41 else:
41 else:
42 SYSTEM_CONFIG_DIRS = [
42 SYSTEM_CONFIG_DIRS = [
43 "/usr/local/etc/ipython",
43 "/usr/local/etc/ipython",
44 "/etc/ipython",
44 "/etc/ipython",
45 ]
45 ]
46
46
47 _envvar = os.environ.get('IPYTHON_SUPPRESS_CONFIG_ERRORS')
47 _envvar = os.environ.get('IPYTHON_SUPPRESS_CONFIG_ERRORS')
48 if _envvar in {None, ''}:
48 if _envvar in {None, ''}:
49 IPYTHON_SUPPRESS_CONFIG_ERRORS = None
49 IPYTHON_SUPPRESS_CONFIG_ERRORS = None
50 else:
50 else:
51 if _envvar.lower() in {'1','true'}:
51 if _envvar.lower() in {'1','true'}:
52 IPYTHON_SUPPRESS_CONFIG_ERRORS = True
52 IPYTHON_SUPPRESS_CONFIG_ERRORS = True
53 elif _envvar.lower() in {'0','false'} :
53 elif _envvar.lower() in {'0','false'} :
54 IPYTHON_SUPPRESS_CONFIG_ERRORS = False
54 IPYTHON_SUPPRESS_CONFIG_ERRORS = False
55 else:
55 else:
56 sys.exit("Unsupported value for environment variable: 'IPYTHON_SUPPRESS_CONFIG_ERRORS' is set to '%s' which is none of {'0', '1', 'false', 'true', ''}."% _envvar )
56 sys.exit("Unsupported value for environment variable: 'IPYTHON_SUPPRESS_CONFIG_ERRORS' is set to '%s' which is none of {'0', '1', 'false', 'true', ''}."% _envvar )
57
57
58 # aliases and flags
58 # aliases and flags
59
59
60 base_aliases = {
60 base_aliases = {
61 'profile-dir' : 'ProfileDir.location',
61 'profile-dir' : 'ProfileDir.location',
62 'profile' : 'BaseIPythonApplication.profile',
62 'profile' : 'BaseIPythonApplication.profile',
63 'ipython-dir' : 'BaseIPythonApplication.ipython_dir',
63 'ipython-dir' : 'BaseIPythonApplication.ipython_dir',
64 'log-level' : 'Application.log_level',
64 'log-level' : 'Application.log_level',
65 'config' : 'BaseIPythonApplication.extra_config_file',
65 'config' : 'BaseIPythonApplication.extra_config_file',
66 }
66 }
67
67
68 base_flags = dict(
68 base_flags = dict(
69 debug = ({'Application' : {'log_level' : logging.DEBUG}},
69 debug = ({'Application' : {'log_level' : logging.DEBUG}},
70 "set log level to logging.DEBUG (maximize logging output)"),
70 "set log level to logging.DEBUG (maximize logging output)"),
71 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
71 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
72 "set log level to logging.CRITICAL (minimize logging output)"),
72 "set log level to logging.CRITICAL (minimize logging output)"),
73 init = ({'BaseIPythonApplication' : {
73 init = ({'BaseIPythonApplication' : {
74 'copy_config_files' : True,
74 'copy_config_files' : True,
75 'auto_create' : True}
75 'auto_create' : True}
76 }, """Initialize profile with default config files. This is equivalent
76 }, """Initialize profile with default config files. This is equivalent
77 to running `ipython profile create <profile>` prior to startup.
77 to running `ipython profile create <profile>` prior to startup.
78 """)
78 """)
79 )
79 )
80
80
81 class ProfileAwareConfigLoader(PyFileConfigLoader):
81 class ProfileAwareConfigLoader(PyFileConfigLoader):
82 """A Python file config loader that is aware of IPython profiles."""
82 """A Python file config loader that is aware of IPython profiles."""
83 def load_subconfig(self, fname, path=None, profile=None):
83 def load_subconfig(self, fname, path=None, profile=None):
84 if profile is not None:
84 if profile is not None:
85 try:
85 try:
86 profile_dir = ProfileDir.find_profile_dir_by_name(
86 profile_dir = ProfileDir.find_profile_dir_by_name(
87 get_ipython_dir(),
87 get_ipython_dir(),
88 profile,
88 profile,
89 )
89 )
90 except ProfileDirError:
90 except ProfileDirError:
91 return
91 return
92 path = profile_dir.location
92 path = profile_dir.location
93 return super(ProfileAwareConfigLoader, self).load_subconfig(fname, path=path)
93 return super(ProfileAwareConfigLoader, self).load_subconfig(fname, path=path)
94
94
95 class BaseIPythonApplication(Application):
95 class BaseIPythonApplication(Application):
96
96
97 name = Unicode(u'ipython')
97 name = Unicode(u'ipython')
98 description = Unicode(u'IPython: an enhanced interactive Python shell.')
98 description = Unicode(u'IPython: an enhanced interactive Python shell.')
99 version = Unicode(release.version)
99 version = Unicode(release.version)
100
100
101 aliases = Dict(base_aliases)
101 aliases = Dict(base_aliases)
102 flags = Dict(base_flags)
102 flags = Dict(base_flags)
103 classes = List([ProfileDir])
103 classes = List([ProfileDir])
104
104
105 # enable `load_subconfig('cfg.py', profile='name')`
105 # enable `load_subconfig('cfg.py', profile='name')`
106 python_config_loader_class = ProfileAwareConfigLoader
106 python_config_loader_class = ProfileAwareConfigLoader
107
107
108 # Track whether the config_file has changed,
108 # Track whether the config_file has changed,
109 # because some logic happens only if we aren't using the default.
109 # because some logic happens only if we aren't using the default.
110 config_file_specified = Set()
110 config_file_specified = Set()
111
111
112 config_file_name = Unicode()
112 config_file_name = Unicode()
113 @default('config_file_name')
113 @default('config_file_name')
114 def _config_file_name_default(self):
114 def _config_file_name_default(self):
115 return self.name.replace('-','_') + u'_config.py'
115 return self.name.replace('-','_') + u'_config.py'
116 @observe('config_file_name')
116 @observe('config_file_name')
117 def _config_file_name_changed(self, change):
117 def _config_file_name_changed(self, change):
118 if change['new'] != change['old']:
118 if change['new'] != change['old']:
119 self.config_file_specified.add(change['new'])
119 self.config_file_specified.add(change['new'])
120
120
121 # The directory that contains IPython's builtin profiles.
121 # The directory that contains IPython's builtin profiles.
122 builtin_profile_dir = Unicode(
122 builtin_profile_dir = Unicode(
123 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
123 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
124 )
124 )
125
125
126 config_file_paths = List(Unicode())
126 config_file_paths = List(Unicode())
127 @default('config_file_paths')
127 @default('config_file_paths')
128 def _config_file_paths_default(self):
128 def _config_file_paths_default(self):
129 return [os.getcwd()]
129 return [os.getcwd()]
130
130
131 extra_config_file = Unicode(
131 extra_config_file = Unicode(
132 help="""Path to an extra config file to load.
132 help="""Path to an extra config file to load.
133
133
134 If specified, load this config file in addition to any other IPython config.
134 If specified, load this config file in addition to any other IPython config.
135 """).tag(config=True)
135 """).tag(config=True)
136 @observe('extra_config_file')
136 @observe('extra_config_file')
137 def _extra_config_file_changed(self, change):
137 def _extra_config_file_changed(self, change):
138 old = change['old']
138 old = change['old']
139 new = change['new']
139 new = change['new']
140 try:
140 try:
141 self.config_files.remove(old)
141 self.config_files.remove(old)
142 except ValueError:
142 except ValueError:
143 pass
143 pass
144 self.config_file_specified.add(new)
144 self.config_file_specified.add(new)
145 self.config_files.append(new)
145 self.config_files.append(new)
146
146
147 profile = Unicode(u'default',
147 profile = Unicode(u'default',
148 help="""The IPython profile to use."""
148 help="""The IPython profile to use."""
149 ).tag(config=True)
149 ).tag(config=True)
150
150
151 @observe('profile')
151 @observe('profile')
152 def _profile_changed(self, change):
152 def _profile_changed(self, change):
153 self.builtin_profile_dir = os.path.join(
153 self.builtin_profile_dir = os.path.join(
154 get_ipython_package_dir(), u'config', u'profile', change['new']
154 get_ipython_package_dir(), u'config', u'profile', change['new']
155 )
155 )
156
156
157 ipython_dir = Unicode(
157 ipython_dir = Unicode(
158 help="""
158 help="""
159 The name of the IPython directory. This directory is used for logging
159 The name of the IPython directory. This directory is used for logging
160 configuration (through profiles), history storage, etc. The default
160 configuration (through profiles), history storage, etc. The default
161 is usually $HOME/.ipython. This option can also be specified through
161 is usually $HOME/.ipython. This option can also be specified through
162 the environment variable IPYTHONDIR.
162 the environment variable IPYTHONDIR.
163 """
163 """
164 ).tag(config=True)
164 ).tag(config=True)
165 @default('ipython_dir')
165 @default('ipython_dir')
166 def _ipython_dir_default(self):
166 def _ipython_dir_default(self):
167 d = get_ipython_dir()
167 d = get_ipython_dir()
168 self._ipython_dir_changed({
168 self._ipython_dir_changed({
169 'name': 'ipython_dir',
169 'name': 'ipython_dir',
170 'old': d,
170 'old': d,
171 'new': d,
171 'new': d,
172 })
172 })
173 return d
173 return d
174
174
175 _in_init_profile_dir = False
175 _in_init_profile_dir = False
176 profile_dir = Instance(ProfileDir, allow_none=True)
176 profile_dir = Instance(ProfileDir, allow_none=True)
177 @default('profile_dir')
177 @default('profile_dir')
178 def _profile_dir_default(self):
178 def _profile_dir_default(self):
179 # avoid recursion
179 # avoid recursion
180 if self._in_init_profile_dir:
180 if self._in_init_profile_dir:
181 return
181 return
182 # profile_dir requested early, force initialization
182 # profile_dir requested early, force initialization
183 self.init_profile_dir()
183 self.init_profile_dir()
184 return self.profile_dir
184 return self.profile_dir
185
185
186 overwrite = Bool(False,
186 overwrite = Bool(False,
187 help="""Whether to overwrite existing config files when copying"""
187 help="""Whether to overwrite existing config files when copying"""
188 ).tag(config=True)
188 ).tag(config=True)
189 auto_create = Bool(False,
189 auto_create = Bool(False,
190 help="""Whether to create profile dir if it doesn't exist"""
190 help="""Whether to create profile dir if it doesn't exist"""
191 ).tag(config=True)
191 ).tag(config=True)
192
192
193 config_files = List(Unicode())
193 config_files = List(Unicode())
194 @default('config_files')
194 @default('config_files')
195 def _config_files_default(self):
195 def _config_files_default(self):
196 return [self.config_file_name]
196 return [self.config_file_name]
197
197
198 copy_config_files = Bool(False,
198 copy_config_files = Bool(False,
199 help="""Whether to install the default config files into the profile dir.
199 help="""Whether to install the default config files into the profile dir.
200 If a new profile is being created, and IPython contains config files for that
200 If a new profile is being created, and IPython contains config files for that
201 profile, then they will be staged into the new directory. Otherwise,
201 profile, then they will be staged into the new directory. Otherwise,
202 default config files will be automatically generated.
202 default config files will be automatically generated.
203 """).tag(config=True)
203 """).tag(config=True)
204
204
205 verbose_crash = Bool(False,
205 verbose_crash = Bool(False,
206 help="""Create a massive crash report when IPython encounters what may be an
206 help="""Create a massive crash report when IPython encounters what may be an
207 internal error. The default is to append a short message to the
207 internal error. The default is to append a short message to the
208 usual traceback""").tag(config=True)
208 usual traceback""").tag(config=True)
209
209
210 # The class to use as the crash handler.
210 # The class to use as the crash handler.
211 crash_handler_class = Type(crashhandler.CrashHandler)
211 crash_handler_class = Type(crashhandler.CrashHandler)
212
212
213 @catch_config_error
213 @catch_config_error
214 def __init__(self, **kwargs):
214 def __init__(self, **kwargs):
215 super(BaseIPythonApplication, self).__init__(**kwargs)
215 super(BaseIPythonApplication, self).__init__(**kwargs)
216 # ensure current working directory exists
216 # ensure current working directory exists
217 try:
217 try:
218 os.getcwd()
218 os.getcwd()
219 except:
219 except:
220 # exit if cwd doesn't exist
220 # exit if cwd doesn't exist
221 self.log.error("Current working directory doesn't exist.")
221 self.log.error("Current working directory doesn't exist.")
222 self.exit(1)
222 self.exit(1)
223
223
224 #-------------------------------------------------------------------------
224 #-------------------------------------------------------------------------
225 # Various stages of Application creation
225 # Various stages of Application creation
226 #-------------------------------------------------------------------------
226 #-------------------------------------------------------------------------
227
227
228 deprecated_subcommands = {}
228 deprecated_subcommands = {}
229
229
230 def initialize_subcommand(self, subc, argv=None):
230 def initialize_subcommand(self, subc, argv=None):
231 if subc in self.deprecated_subcommands:
231 if subc in self.deprecated_subcommands:
232 self.log.warning("Subcommand `ipython {sub}` is deprecated and will be removed "
232 self.log.warning("Subcommand `ipython {sub}` is deprecated and will be removed "
233 "in future versions.".format(sub=subc))
233 "in future versions.".format(sub=subc))
234 self.log.warning("You likely want to use `jupyter {sub}` in the "
234 self.log.warning("You likely want to use `jupyter {sub}` in the "
235 "future".format(sub=subc))
235 "future".format(sub=subc))
236 return super(BaseIPythonApplication, self).initialize_subcommand(subc, argv)
236 return super(BaseIPythonApplication, self).initialize_subcommand(subc, argv)
237
237
238 def init_crash_handler(self):
238 def init_crash_handler(self):
239 """Create a crash handler, typically setting sys.excepthook to it."""
239 """Create a crash handler, typically setting sys.excepthook to it."""
240 self.crash_handler = self.crash_handler_class(self)
240 self.crash_handler = self.crash_handler_class(self)
241 sys.excepthook = self.excepthook
241 sys.excepthook = self.excepthook
242 def unset_crashhandler():
242 def unset_crashhandler():
243 sys.excepthook = sys.__excepthook__
243 sys.excepthook = sys.__excepthook__
244 atexit.register(unset_crashhandler)
244 atexit.register(unset_crashhandler)
245
245
246 def excepthook(self, etype, evalue, tb):
246 def excepthook(self, etype, evalue, tb):
247 """this is sys.excepthook after init_crashhandler
247 """this is sys.excepthook after init_crashhandler
248
248
249 set self.verbose_crash=True to use our full crashhandler, instead of
249 set self.verbose_crash=True to use our full crashhandler, instead of
250 a regular traceback with a short message (crash_handler_lite)
250 a regular traceback with a short message (crash_handler_lite)
251 """
251 """
252
252
253 if self.verbose_crash:
253 if self.verbose_crash:
254 return self.crash_handler(etype, evalue, tb)
254 return self.crash_handler(etype, evalue, tb)
255 else:
255 else:
256 return crashhandler.crash_handler_lite(etype, evalue, tb)
256 return crashhandler.crash_handler_lite(etype, evalue, tb)
257
257
258 @observe('ipython_dir')
258 @observe('ipython_dir')
259 def _ipython_dir_changed(self, change):
259 def _ipython_dir_changed(self, change):
260 old = change['old']
260 old = change['old']
261 new = change['new']
261 new = change['new']
262 if old is not Undefined:
262 if old is not Undefined:
263 str_old = py3compat.cast_bytes_py2(os.path.abspath(old),
263 str_old = os.path.abspath(old)
264 sys.getfilesystemencoding()
265 )
266 if str_old in sys.path:
264 if str_old in sys.path:
267 sys.path.remove(str_old)
265 sys.path.remove(str_old)
268 str_path = py3compat.cast_bytes_py2(os.path.abspath(new),
266 str_path = os.path.abspath(new)
269 sys.getfilesystemencoding()
270 )
271 sys.path.append(str_path)
267 sys.path.append(str_path)
272 ensure_dir_exists(new)
268 ensure_dir_exists(new)
273 readme = os.path.join(new, 'README')
269 readme = os.path.join(new, 'README')
274 readme_src = os.path.join(get_ipython_package_dir(), u'config', u'profile', 'README')
270 readme_src = os.path.join(get_ipython_package_dir(), u'config', u'profile', 'README')
275 if not os.path.exists(readme) and os.path.exists(readme_src):
271 if not os.path.exists(readme) and os.path.exists(readme_src):
276 shutil.copy(readme_src, readme)
272 shutil.copy(readme_src, readme)
277 for d in ('extensions', 'nbextensions'):
273 for d in ('extensions', 'nbextensions'):
278 path = os.path.join(new, d)
274 path = os.path.join(new, d)
279 try:
275 try:
280 ensure_dir_exists(path)
276 ensure_dir_exists(path)
281 except OSError as e:
277 except OSError as e:
282 # this will not be EEXIST
278 # this will not be EEXIST
283 self.log.error("couldn't create path %s: %s", path, e)
279 self.log.error("couldn't create path %s: %s", path, e)
284 self.log.debug("IPYTHONDIR set to: %s" % new)
280 self.log.debug("IPYTHONDIR set to: %s" % new)
285
281
286 def load_config_file(self, suppress_errors=IPYTHON_SUPPRESS_CONFIG_ERRORS):
282 def load_config_file(self, suppress_errors=IPYTHON_SUPPRESS_CONFIG_ERRORS):
287 """Load the config file.
283 """Load the config file.
288
284
289 By default, errors in loading config are handled, and a warning
285 By default, errors in loading config are handled, and a warning
290 printed on screen. For testing, the suppress_errors option is set
286 printed on screen. For testing, the suppress_errors option is set
291 to False, so errors will make tests fail.
287 to False, so errors will make tests fail.
292
288
293 `supress_errors` default value is to be `None` in which case the
289 `supress_errors` default value is to be `None` in which case the
294 behavior default to the one of `traitlets.Application`.
290 behavior default to the one of `traitlets.Application`.
295
291
296 The default value can be set :
292 The default value can be set :
297 - to `False` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '0', or 'false' (case insensitive).
293 - to `False` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '0', or 'false' (case insensitive).
298 - to `True` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '1' or 'true' (case insensitive).
294 - to `True` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '1' or 'true' (case insensitive).
299 - to `None` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '' (empty string) or leaving it unset.
295 - to `None` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '' (empty string) or leaving it unset.
300
296
301 Any other value are invalid, and will make IPython exit with a non-zero return code.
297 Any other value are invalid, and will make IPython exit with a non-zero return code.
302 """
298 """
303
299
304
300
305 self.log.debug("Searching path %s for config files", self.config_file_paths)
301 self.log.debug("Searching path %s for config files", self.config_file_paths)
306 base_config = 'ipython_config.py'
302 base_config = 'ipython_config.py'
307 self.log.debug("Attempting to load config file: %s" %
303 self.log.debug("Attempting to load config file: %s" %
308 base_config)
304 base_config)
309 try:
305 try:
310 if suppress_errors is not None:
306 if suppress_errors is not None:
311 old_value = Application.raise_config_file_errors
307 old_value = Application.raise_config_file_errors
312 Application.raise_config_file_errors = not suppress_errors;
308 Application.raise_config_file_errors = not suppress_errors;
313 Application.load_config_file(
309 Application.load_config_file(
314 self,
310 self,
315 base_config,
311 base_config,
316 path=self.config_file_paths
312 path=self.config_file_paths
317 )
313 )
318 except ConfigFileNotFound:
314 except ConfigFileNotFound:
319 # ignore errors loading parent
315 # ignore errors loading parent
320 self.log.debug("Config file %s not found", base_config)
316 self.log.debug("Config file %s not found", base_config)
321 pass
317 pass
322 if suppress_errors is not None:
318 if suppress_errors is not None:
323 Application.raise_config_file_errors = old_value
319 Application.raise_config_file_errors = old_value
324
320
325 for config_file_name in self.config_files:
321 for config_file_name in self.config_files:
326 if not config_file_name or config_file_name == base_config:
322 if not config_file_name or config_file_name == base_config:
327 continue
323 continue
328 self.log.debug("Attempting to load config file: %s" %
324 self.log.debug("Attempting to load config file: %s" %
329 self.config_file_name)
325 self.config_file_name)
330 try:
326 try:
331 Application.load_config_file(
327 Application.load_config_file(
332 self,
328 self,
333 config_file_name,
329 config_file_name,
334 path=self.config_file_paths
330 path=self.config_file_paths
335 )
331 )
336 except ConfigFileNotFound:
332 except ConfigFileNotFound:
337 # Only warn if the default config file was NOT being used.
333 # Only warn if the default config file was NOT being used.
338 if config_file_name in self.config_file_specified:
334 if config_file_name in self.config_file_specified:
339 msg = self.log.warning
335 msg = self.log.warning
340 else:
336 else:
341 msg = self.log.debug
337 msg = self.log.debug
342 msg("Config file not found, skipping: %s", config_file_name)
338 msg("Config file not found, skipping: %s", config_file_name)
343 except Exception:
339 except Exception:
344 # For testing purposes.
340 # For testing purposes.
345 if not suppress_errors:
341 if not suppress_errors:
346 raise
342 raise
347 self.log.warning("Error loading config file: %s" %
343 self.log.warning("Error loading config file: %s" %
348 self.config_file_name, exc_info=True)
344 self.config_file_name, exc_info=True)
349
345
350 def init_profile_dir(self):
346 def init_profile_dir(self):
351 """initialize the profile dir"""
347 """initialize the profile dir"""
352 self._in_init_profile_dir = True
348 self._in_init_profile_dir = True
353 if self.profile_dir is not None:
349 if self.profile_dir is not None:
354 # already ran
350 # already ran
355 return
351 return
356 if 'ProfileDir.location' not in self.config:
352 if 'ProfileDir.location' not in self.config:
357 # location not specified, find by profile name
353 # location not specified, find by profile name
358 try:
354 try:
359 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
355 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
360 except ProfileDirError:
356 except ProfileDirError:
361 # not found, maybe create it (always create default profile)
357 # not found, maybe create it (always create default profile)
362 if self.auto_create or self.profile == 'default':
358 if self.auto_create or self.profile == 'default':
363 try:
359 try:
364 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
360 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
365 except ProfileDirError:
361 except ProfileDirError:
366 self.log.fatal("Could not create profile: %r"%self.profile)
362 self.log.fatal("Could not create profile: %r"%self.profile)
367 self.exit(1)
363 self.exit(1)
368 else:
364 else:
369 self.log.info("Created profile dir: %r"%p.location)
365 self.log.info("Created profile dir: %r"%p.location)
370 else:
366 else:
371 self.log.fatal("Profile %r not found."%self.profile)
367 self.log.fatal("Profile %r not found."%self.profile)
372 self.exit(1)
368 self.exit(1)
373 else:
369 else:
374 self.log.debug("Using existing profile dir: %r"%p.location)
370 self.log.debug("Using existing profile dir: %r"%p.location)
375 else:
371 else:
376 location = self.config.ProfileDir.location
372 location = self.config.ProfileDir.location
377 # location is fully specified
373 # location is fully specified
378 try:
374 try:
379 p = ProfileDir.find_profile_dir(location, self.config)
375 p = ProfileDir.find_profile_dir(location, self.config)
380 except ProfileDirError:
376 except ProfileDirError:
381 # not found, maybe create it
377 # not found, maybe create it
382 if self.auto_create:
378 if self.auto_create:
383 try:
379 try:
384 p = ProfileDir.create_profile_dir(location, self.config)
380 p = ProfileDir.create_profile_dir(location, self.config)
385 except ProfileDirError:
381 except ProfileDirError:
386 self.log.fatal("Could not create profile directory: %r"%location)
382 self.log.fatal("Could not create profile directory: %r"%location)
387 self.exit(1)
383 self.exit(1)
388 else:
384 else:
389 self.log.debug("Creating new profile dir: %r"%location)
385 self.log.debug("Creating new profile dir: %r"%location)
390 else:
386 else:
391 self.log.fatal("Profile directory %r not found."%location)
387 self.log.fatal("Profile directory %r not found."%location)
392 self.exit(1)
388 self.exit(1)
393 else:
389 else:
394 self.log.info("Using existing profile dir: %r"%location)
390 self.log.info("Using existing profile dir: %r"%location)
395 # if profile_dir is specified explicitly, set profile name
391 # if profile_dir is specified explicitly, set profile name
396 dir_name = os.path.basename(p.location)
392 dir_name = os.path.basename(p.location)
397 if dir_name.startswith('profile_'):
393 if dir_name.startswith('profile_'):
398 self.profile = dir_name[8:]
394 self.profile = dir_name[8:]
399
395
400 self.profile_dir = p
396 self.profile_dir = p
401 self.config_file_paths.append(p.location)
397 self.config_file_paths.append(p.location)
402 self._in_init_profile_dir = False
398 self._in_init_profile_dir = False
403
399
404 def init_config_files(self):
400 def init_config_files(self):
405 """[optionally] copy default config files into profile dir."""
401 """[optionally] copy default config files into profile dir."""
406 self.config_file_paths.extend(SYSTEM_CONFIG_DIRS)
402 self.config_file_paths.extend(SYSTEM_CONFIG_DIRS)
407 # copy config files
403 # copy config files
408 path = self.builtin_profile_dir
404 path = self.builtin_profile_dir
409 if self.copy_config_files:
405 if self.copy_config_files:
410 src = self.profile
406 src = self.profile
411
407
412 cfg = self.config_file_name
408 cfg = self.config_file_name
413 if path and os.path.exists(os.path.join(path, cfg)):
409 if path and os.path.exists(os.path.join(path, cfg)):
414 self.log.warning("Staging %r from %s into %r [overwrite=%s]"%(
410 self.log.warning("Staging %r from %s into %r [overwrite=%s]"%(
415 cfg, src, self.profile_dir.location, self.overwrite)
411 cfg, src, self.profile_dir.location, self.overwrite)
416 )
412 )
417 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
413 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
418 else:
414 else:
419 self.stage_default_config_file()
415 self.stage_default_config_file()
420 else:
416 else:
421 # Still stage *bundled* config files, but not generated ones
417 # Still stage *bundled* config files, but not generated ones
422 # This is necessary for `ipython profile=sympy` to load the profile
418 # This is necessary for `ipython profile=sympy` to load the profile
423 # on the first go
419 # on the first go
424 files = glob.glob(os.path.join(path, '*.py'))
420 files = glob.glob(os.path.join(path, '*.py'))
425 for fullpath in files:
421 for fullpath in files:
426 cfg = os.path.basename(fullpath)
422 cfg = os.path.basename(fullpath)
427 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
423 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
428 # file was copied
424 # file was copied
429 self.log.warning("Staging bundled %s from %s into %r"%(
425 self.log.warning("Staging bundled %s from %s into %r"%(
430 cfg, self.profile, self.profile_dir.location)
426 cfg, self.profile, self.profile_dir.location)
431 )
427 )
432
428
433
429
434 def stage_default_config_file(self):
430 def stage_default_config_file(self):
435 """auto generate default config file, and stage it into the profile."""
431 """auto generate default config file, and stage it into the profile."""
436 s = self.generate_config_file()
432 s = self.generate_config_file()
437 fname = os.path.join(self.profile_dir.location, self.config_file_name)
433 fname = os.path.join(self.profile_dir.location, self.config_file_name)
438 if self.overwrite or not os.path.exists(fname):
434 if self.overwrite or not os.path.exists(fname):
439 self.log.warning("Generating default config file: %r"%(fname))
435 self.log.warning("Generating default config file: %r"%(fname))
440 with open(fname, 'w') as f:
436 with open(fname, 'w') as f:
441 f.write(s)
437 f.write(s)
442
438
443 @catch_config_error
439 @catch_config_error
444 def initialize(self, argv=None):
440 def initialize(self, argv=None):
445 # don't hook up crash handler before parsing command-line
441 # don't hook up crash handler before parsing command-line
446 self.parse_command_line(argv)
442 self.parse_command_line(argv)
447 self.init_crash_handler()
443 self.init_crash_handler()
448 if self.subapp is not None:
444 if self.subapp is not None:
449 # stop here if subapp is taking over
445 # stop here if subapp is taking over
450 return
446 return
451 # save a copy of CLI config to re-load after config files
447 # save a copy of CLI config to re-load after config files
452 # so that it has highest priority
448 # so that it has highest priority
453 cl_config = deepcopy(self.config)
449 cl_config = deepcopy(self.config)
454 self.init_profile_dir()
450 self.init_profile_dir()
455 self.init_config_files()
451 self.init_config_files()
456 self.load_config_file()
452 self.load_config_file()
457 # enforce cl-opts override configfile opts:
453 # enforce cl-opts override configfile opts:
458 self.update_config(cl_config)
454 self.update_config(cl_config)
@@ -1,1204 +1,1203 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Top-level display functions for displaying object in different formats."""
2 """Top-level display functions for displaying object in different formats."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7
7
8 try:
8 try:
9 from base64 import encodebytes as base64_encode
9 from base64 import encodebytes as base64_encode
10 except ImportError:
10 except ImportError:
11 from base64 import encodestring as base64_encode
11 from base64 import encodestring as base64_encode
12
12
13 from binascii import b2a_hex
13 from binascii import b2a_hex
14 import json
14 import json
15 import mimetypes
15 import mimetypes
16 import os
16 import os
17 import struct
17 import struct
18 import sys
18 import sys
19 import warnings
19 import warnings
20
20
21 from IPython.utils.py3compat import cast_bytes_py2, cast_unicode
21 from IPython.utils.py3compat import cast_unicode
22 from IPython.testing.skipdoctest import skip_doctest
22 from IPython.testing.skipdoctest import skip_doctest
23
23
24 __all__ = ['display', 'display_pretty', 'display_html', 'display_markdown',
24 __all__ = ['display', 'display_pretty', 'display_html', 'display_markdown',
25 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
25 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
26 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
26 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
27 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'JSON', 'GeoJSON', 'Javascript',
27 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'JSON', 'GeoJSON', 'Javascript',
28 'Image', 'clear_output', 'set_matplotlib_formats', 'set_matplotlib_close',
28 'Image', 'clear_output', 'set_matplotlib_formats', 'set_matplotlib_close',
29 'publish_display_data', 'update_display', 'DisplayHandle', 'Video']
29 'publish_display_data', 'update_display', 'DisplayHandle', 'Video']
30
30
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32 # utility functions
32 # utility functions
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34
34
35 def _safe_exists(path):
35 def _safe_exists(path):
36 """Check path, but don't let exceptions raise"""
36 """Check path, but don't let exceptions raise"""
37 try:
37 try:
38 return os.path.exists(path)
38 return os.path.exists(path)
39 except Exception:
39 except Exception:
40 return False
40 return False
41
41
42 def _merge(d1, d2):
42 def _merge(d1, d2):
43 """Like update, but merges sub-dicts instead of clobbering at the top level.
43 """Like update, but merges sub-dicts instead of clobbering at the top level.
44
44
45 Updates d1 in-place
45 Updates d1 in-place
46 """
46 """
47
47
48 if not isinstance(d2, dict) or not isinstance(d1, dict):
48 if not isinstance(d2, dict) or not isinstance(d1, dict):
49 return d2
49 return d2
50 for key, value in d2.items():
50 for key, value in d2.items():
51 d1[key] = _merge(d1.get(key), value)
51 d1[key] = _merge(d1.get(key), value)
52 return d1
52 return d1
53
53
54 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
54 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
55 """internal implementation of all display_foo methods
55 """internal implementation of all display_foo methods
56
56
57 Parameters
57 Parameters
58 ----------
58 ----------
59 mimetype : str
59 mimetype : str
60 The mimetype to be published (e.g. 'image/png')
60 The mimetype to be published (e.g. 'image/png')
61 objs : tuple of objects
61 objs : tuple of objects
62 The Python objects to display, or if raw=True raw text data to
62 The Python objects to display, or if raw=True raw text data to
63 display.
63 display.
64 raw : bool
64 raw : bool
65 Are the data objects raw data or Python objects that need to be
65 Are the data objects raw data or Python objects that need to be
66 formatted before display? [default: False]
66 formatted before display? [default: False]
67 metadata : dict (optional)
67 metadata : dict (optional)
68 Metadata to be associated with the specific mimetype output.
68 Metadata to be associated with the specific mimetype output.
69 """
69 """
70 if metadata:
70 if metadata:
71 metadata = {mimetype: metadata}
71 metadata = {mimetype: metadata}
72 if raw:
72 if raw:
73 # turn list of pngdata into list of { 'image/png': pngdata }
73 # turn list of pngdata into list of { 'image/png': pngdata }
74 objs = [ {mimetype: obj} for obj in objs ]
74 objs = [ {mimetype: obj} for obj in objs ]
75 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
75 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
76
76
77 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
78 # Main functions
78 # Main functions
79 #-----------------------------------------------------------------------------
79 #-----------------------------------------------------------------------------
80
80
81 # use * to indicate transient is keyword-only
81 # use * to indicate transient is keyword-only
82 def publish_display_data(data, metadata=None, source=None, *, transient=None, **kwargs):
82 def publish_display_data(data, metadata=None, source=None, *, transient=None, **kwargs):
83 """Publish data and metadata to all frontends.
83 """Publish data and metadata to all frontends.
84
84
85 See the ``display_data`` message in the messaging documentation for
85 See the ``display_data`` message in the messaging documentation for
86 more details about this message type.
86 more details about this message type.
87
87
88 The following MIME types are currently implemented:
88 The following MIME types are currently implemented:
89
89
90 * text/plain
90 * text/plain
91 * text/html
91 * text/html
92 * text/markdown
92 * text/markdown
93 * text/latex
93 * text/latex
94 * application/json
94 * application/json
95 * application/javascript
95 * application/javascript
96 * image/png
96 * image/png
97 * image/jpeg
97 * image/jpeg
98 * image/svg+xml
98 * image/svg+xml
99
99
100 Parameters
100 Parameters
101 ----------
101 ----------
102 data : dict
102 data : dict
103 A dictionary having keys that are valid MIME types (like
103 A dictionary having keys that are valid MIME types (like
104 'text/plain' or 'image/svg+xml') and values that are the data for
104 'text/plain' or 'image/svg+xml') and values that are the data for
105 that MIME type. The data itself must be a JSON'able data
105 that MIME type. The data itself must be a JSON'able data
106 structure. Minimally all data should have the 'text/plain' data,
106 structure. Minimally all data should have the 'text/plain' data,
107 which can be displayed by all frontends. If more than the plain
107 which can be displayed by all frontends. If more than the plain
108 text is given, it is up to the frontend to decide which
108 text is given, it is up to the frontend to decide which
109 representation to use.
109 representation to use.
110 metadata : dict
110 metadata : dict
111 A dictionary for metadata related to the data. This can contain
111 A dictionary for metadata related to the data. This can contain
112 arbitrary key, value pairs that frontends can use to interpret
112 arbitrary key, value pairs that frontends can use to interpret
113 the data. mime-type keys matching those in data can be used
113 the data. mime-type keys matching those in data can be used
114 to specify metadata about particular representations.
114 to specify metadata about particular representations.
115 source : str, deprecated
115 source : str, deprecated
116 Unused.
116 Unused.
117 transient : dict, keyword-only
117 transient : dict, keyword-only
118 A dictionary of transient data, such as display_id.
118 A dictionary of transient data, such as display_id.
119 """
119 """
120 from IPython.core.interactiveshell import InteractiveShell
120 from IPython.core.interactiveshell import InteractiveShell
121
121
122 display_pub = InteractiveShell.instance().display_pub
122 display_pub = InteractiveShell.instance().display_pub
123
123
124 # only pass transient if supplied,
124 # only pass transient if supplied,
125 # to avoid errors with older ipykernel.
125 # to avoid errors with older ipykernel.
126 # TODO: We could check for ipykernel version and provide a detailed upgrade message.
126 # TODO: We could check for ipykernel version and provide a detailed upgrade message.
127 if transient:
127 if transient:
128 kwargs['transient'] = transient
128 kwargs['transient'] = transient
129
129
130 display_pub.publish(
130 display_pub.publish(
131 data=data,
131 data=data,
132 metadata=metadata,
132 metadata=metadata,
133 **kwargs
133 **kwargs
134 )
134 )
135
135
136
136
137 def _new_id():
137 def _new_id():
138 """Generate a new random text id with urandom"""
138 """Generate a new random text id with urandom"""
139 return b2a_hex(os.urandom(16)).decode('ascii')
139 return b2a_hex(os.urandom(16)).decode('ascii')
140
140
141
141
142 def display(*objs, include=None, exclude=None, metadata=None, transient=None, display_id=None, **kwargs):
142 def display(*objs, include=None, exclude=None, metadata=None, transient=None, display_id=None, **kwargs):
143 """Display a Python object in all frontends.
143 """Display a Python object in all frontends.
144
144
145 By default all representations will be computed and sent to the frontends.
145 By default all representations will be computed and sent to the frontends.
146 Frontends can decide which representation is used and how.
146 Frontends can decide which representation is used and how.
147
147
148 Parameters
148 Parameters
149 ----------
149 ----------
150 objs : tuple of objects
150 objs : tuple of objects
151 The Python objects to display.
151 The Python objects to display.
152 raw : bool, optional
152 raw : bool, optional
153 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
153 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
154 or Python objects that need to be formatted before display? [default: False]
154 or Python objects that need to be formatted before display? [default: False]
155 include : list or tuple, optional
155 include : list or tuple, optional
156 A list of format type strings (MIME types) to include in the
156 A list of format type strings (MIME types) to include in the
157 format data dict. If this is set *only* the format types included
157 format data dict. If this is set *only* the format types included
158 in this list will be computed.
158 in this list will be computed.
159 exclude : list or tuple, optional
159 exclude : list or tuple, optional
160 A list of format type strings (MIME types) to exclude in the format
160 A list of format type strings (MIME types) to exclude in the format
161 data dict. If this is set all format types will be computed,
161 data dict. If this is set all format types will be computed,
162 except for those included in this argument.
162 except for those included in this argument.
163 metadata : dict, optional
163 metadata : dict, optional
164 A dictionary of metadata to associate with the output.
164 A dictionary of metadata to associate with the output.
165 mime-type keys in this dictionary will be associated with the individual
165 mime-type keys in this dictionary will be associated with the individual
166 representation formats, if they exist.
166 representation formats, if they exist.
167 transient : dict, optional
167 transient : dict, optional
168 A dictionary of transient data to associate with the output.
168 A dictionary of transient data to associate with the output.
169 Data in this dict should not be persisted to files (e.g. notebooks).
169 Data in this dict should not be persisted to files (e.g. notebooks).
170 display_id : str, optional
170 display_id : str, optional
171 Set an id for the display.
171 Set an id for the display.
172 This id can be used for updating this display area later via update_display.
172 This id can be used for updating this display area later via update_display.
173 If given as True, generate a new display_id
173 If given as True, generate a new display_id
174 kwargs: additional keyword-args, optional
174 kwargs: additional keyword-args, optional
175 Additional keyword-arguments are passed through to the display publisher.
175 Additional keyword-arguments are passed through to the display publisher.
176
176
177 Returns
177 Returns
178 -------
178 -------
179
179
180 handle: DisplayHandle
180 handle: DisplayHandle
181 Returns a handle on updatable displays, if display_id is given.
181 Returns a handle on updatable displays, if display_id is given.
182 Returns None if no display_id is given (default).
182 Returns None if no display_id is given (default).
183 """
183 """
184 raw = kwargs.pop('raw', False)
184 raw = kwargs.pop('raw', False)
185 if transient is None:
185 if transient is None:
186 transient = {}
186 transient = {}
187 if display_id:
187 if display_id:
188 if display_id == True:
188 if display_id == True:
189 display_id = _new_id()
189 display_id = _new_id()
190 transient['display_id'] = display_id
190 transient['display_id'] = display_id
191 if kwargs.get('update') and 'display_id' not in transient:
191 if kwargs.get('update') and 'display_id' not in transient:
192 raise TypeError('display_id required for update_display')
192 raise TypeError('display_id required for update_display')
193 if transient:
193 if transient:
194 kwargs['transient'] = transient
194 kwargs['transient'] = transient
195
195
196 from IPython.core.interactiveshell import InteractiveShell
196 from IPython.core.interactiveshell import InteractiveShell
197
197
198 if not raw:
198 if not raw:
199 format = InteractiveShell.instance().display_formatter.format
199 format = InteractiveShell.instance().display_formatter.format
200
200
201 for obj in objs:
201 for obj in objs:
202 if raw:
202 if raw:
203 publish_display_data(data=obj, metadata=metadata, **kwargs)
203 publish_display_data(data=obj, metadata=metadata, **kwargs)
204 else:
204 else:
205 format_dict, md_dict = format(obj, include=include, exclude=exclude)
205 format_dict, md_dict = format(obj, include=include, exclude=exclude)
206 if not format_dict:
206 if not format_dict:
207 # nothing to display (e.g. _ipython_display_ took over)
207 # nothing to display (e.g. _ipython_display_ took over)
208 continue
208 continue
209 if metadata:
209 if metadata:
210 # kwarg-specified metadata gets precedence
210 # kwarg-specified metadata gets precedence
211 _merge(md_dict, metadata)
211 _merge(md_dict, metadata)
212 publish_display_data(data=format_dict, metadata=md_dict, **kwargs)
212 publish_display_data(data=format_dict, metadata=md_dict, **kwargs)
213 if display_id:
213 if display_id:
214 return DisplayHandle(display_id)
214 return DisplayHandle(display_id)
215
215
216
216
217 # use * for keyword-only display_id arg
217 # use * for keyword-only display_id arg
218 def update_display(obj, *, display_id, **kwargs):
218 def update_display(obj, *, display_id, **kwargs):
219 """Update an existing display by id
219 """Update an existing display by id
220
220
221 Parameters
221 Parameters
222 ----------
222 ----------
223
223
224 obj:
224 obj:
225 The object with which to update the display
225 The object with which to update the display
226 display_id: keyword-only
226 display_id: keyword-only
227 The id of the display to update
227 The id of the display to update
228 """
228 """
229 kwargs['update'] = True
229 kwargs['update'] = True
230 display(obj, display_id=display_id, **kwargs)
230 display(obj, display_id=display_id, **kwargs)
231
231
232
232
233 class DisplayHandle(object):
233 class DisplayHandle(object):
234 """A handle on an updatable display
234 """A handle on an updatable display
235
235
236 Call .update(obj) to display a new object.
236 Call .update(obj) to display a new object.
237
237
238 Call .display(obj) to add a new instance of this display,
238 Call .display(obj) to add a new instance of this display,
239 and update existing instances.
239 and update existing instances.
240 """
240 """
241
241
242 def __init__(self, display_id=None):
242 def __init__(self, display_id=None):
243 if display_id is None:
243 if display_id is None:
244 display_id = _new_id()
244 display_id = _new_id()
245 self.display_id = display_id
245 self.display_id = display_id
246
246
247 def __repr__(self):
247 def __repr__(self):
248 return "<%s display_id=%s>" % (self.__class__.__name__, self.display_id)
248 return "<%s display_id=%s>" % (self.__class__.__name__, self.display_id)
249
249
250 def display(self, obj, **kwargs):
250 def display(self, obj, **kwargs):
251 """Make a new display with my id, updating existing instances.
251 """Make a new display with my id, updating existing instances.
252
252
253 Parameters
253 Parameters
254 ----------
254 ----------
255
255
256 obj:
256 obj:
257 object to display
257 object to display
258 **kwargs:
258 **kwargs:
259 additional keyword arguments passed to display
259 additional keyword arguments passed to display
260 """
260 """
261 display(obj, display_id=self.display_id, **kwargs)
261 display(obj, display_id=self.display_id, **kwargs)
262
262
263 def update(self, obj, **kwargs):
263 def update(self, obj, **kwargs):
264 """Update existing displays with my id
264 """Update existing displays with my id
265
265
266 Parameters
266 Parameters
267 ----------
267 ----------
268
268
269 obj:
269 obj:
270 object to display
270 object to display
271 **kwargs:
271 **kwargs:
272 additional keyword arguments passed to update_display
272 additional keyword arguments passed to update_display
273 """
273 """
274 update_display(obj, display_id=self.display_id, **kwargs)
274 update_display(obj, display_id=self.display_id, **kwargs)
275
275
276
276
277 def display_pretty(*objs, **kwargs):
277 def display_pretty(*objs, **kwargs):
278 """Display the pretty (default) representation of an object.
278 """Display the pretty (default) representation of an object.
279
279
280 Parameters
280 Parameters
281 ----------
281 ----------
282 objs : tuple of objects
282 objs : tuple of objects
283 The Python objects to display, or if raw=True raw text data to
283 The Python objects to display, or if raw=True raw text data to
284 display.
284 display.
285 raw : bool
285 raw : bool
286 Are the data objects raw data or Python objects that need to be
286 Are the data objects raw data or Python objects that need to be
287 formatted before display? [default: False]
287 formatted before display? [default: False]
288 metadata : dict (optional)
288 metadata : dict (optional)
289 Metadata to be associated with the specific mimetype output.
289 Metadata to be associated with the specific mimetype output.
290 """
290 """
291 _display_mimetype('text/plain', objs, **kwargs)
291 _display_mimetype('text/plain', objs, **kwargs)
292
292
293
293
294 def display_html(*objs, **kwargs):
294 def display_html(*objs, **kwargs):
295 """Display the HTML representation of an object.
295 """Display the HTML representation of an object.
296
296
297 Note: If raw=False and the object does not have a HTML
297 Note: If raw=False and the object does not have a HTML
298 representation, no HTML will be shown.
298 representation, no HTML will be shown.
299
299
300 Parameters
300 Parameters
301 ----------
301 ----------
302 objs : tuple of objects
302 objs : tuple of objects
303 The Python objects to display, or if raw=True raw HTML data to
303 The Python objects to display, or if raw=True raw HTML data to
304 display.
304 display.
305 raw : bool
305 raw : bool
306 Are the data objects raw data or Python objects that need to be
306 Are the data objects raw data or Python objects that need to be
307 formatted before display? [default: False]
307 formatted before display? [default: False]
308 metadata : dict (optional)
308 metadata : dict (optional)
309 Metadata to be associated with the specific mimetype output.
309 Metadata to be associated with the specific mimetype output.
310 """
310 """
311 _display_mimetype('text/html', objs, **kwargs)
311 _display_mimetype('text/html', objs, **kwargs)
312
312
313
313
314 def display_markdown(*objs, **kwargs):
314 def display_markdown(*objs, **kwargs):
315 """Displays the Markdown representation of an object.
315 """Displays the Markdown representation of an object.
316
316
317 Parameters
317 Parameters
318 ----------
318 ----------
319 objs : tuple of objects
319 objs : tuple of objects
320 The Python objects to display, or if raw=True raw markdown data to
320 The Python objects to display, or if raw=True raw markdown data to
321 display.
321 display.
322 raw : bool
322 raw : bool
323 Are the data objects raw data or Python objects that need to be
323 Are the data objects raw data or Python objects that need to be
324 formatted before display? [default: False]
324 formatted before display? [default: False]
325 metadata : dict (optional)
325 metadata : dict (optional)
326 Metadata to be associated with the specific mimetype output.
326 Metadata to be associated with the specific mimetype output.
327 """
327 """
328
328
329 _display_mimetype('text/markdown', objs, **kwargs)
329 _display_mimetype('text/markdown', objs, **kwargs)
330
330
331
331
332 def display_svg(*objs, **kwargs):
332 def display_svg(*objs, **kwargs):
333 """Display the SVG representation of an object.
333 """Display the SVG representation of an object.
334
334
335 Parameters
335 Parameters
336 ----------
336 ----------
337 objs : tuple of objects
337 objs : tuple of objects
338 The Python objects to display, or if raw=True raw svg data to
338 The Python objects to display, or if raw=True raw svg data to
339 display.
339 display.
340 raw : bool
340 raw : bool
341 Are the data objects raw data or Python objects that need to be
341 Are the data objects raw data or Python objects that need to be
342 formatted before display? [default: False]
342 formatted before display? [default: False]
343 metadata : dict (optional)
343 metadata : dict (optional)
344 Metadata to be associated with the specific mimetype output.
344 Metadata to be associated with the specific mimetype output.
345 """
345 """
346 _display_mimetype('image/svg+xml', objs, **kwargs)
346 _display_mimetype('image/svg+xml', objs, **kwargs)
347
347
348
348
349 def display_png(*objs, **kwargs):
349 def display_png(*objs, **kwargs):
350 """Display the PNG representation of an object.
350 """Display the PNG representation of an object.
351
351
352 Parameters
352 Parameters
353 ----------
353 ----------
354 objs : tuple of objects
354 objs : tuple of objects
355 The Python objects to display, or if raw=True raw png data to
355 The Python objects to display, or if raw=True raw png data to
356 display.
356 display.
357 raw : bool
357 raw : bool
358 Are the data objects raw data or Python objects that need to be
358 Are the data objects raw data or Python objects that need to be
359 formatted before display? [default: False]
359 formatted before display? [default: False]
360 metadata : dict (optional)
360 metadata : dict (optional)
361 Metadata to be associated with the specific mimetype output.
361 Metadata to be associated with the specific mimetype output.
362 """
362 """
363 _display_mimetype('image/png', objs, **kwargs)
363 _display_mimetype('image/png', objs, **kwargs)
364
364
365
365
366 def display_jpeg(*objs, **kwargs):
366 def display_jpeg(*objs, **kwargs):
367 """Display the JPEG representation of an object.
367 """Display the JPEG representation of an object.
368
368
369 Parameters
369 Parameters
370 ----------
370 ----------
371 objs : tuple of objects
371 objs : tuple of objects
372 The Python objects to display, or if raw=True raw JPEG data to
372 The Python objects to display, or if raw=True raw JPEG data to
373 display.
373 display.
374 raw : bool
374 raw : bool
375 Are the data objects raw data or Python objects that need to be
375 Are the data objects raw data or Python objects that need to be
376 formatted before display? [default: False]
376 formatted before display? [default: False]
377 metadata : dict (optional)
377 metadata : dict (optional)
378 Metadata to be associated with the specific mimetype output.
378 Metadata to be associated with the specific mimetype output.
379 """
379 """
380 _display_mimetype('image/jpeg', objs, **kwargs)
380 _display_mimetype('image/jpeg', objs, **kwargs)
381
381
382
382
383 def display_latex(*objs, **kwargs):
383 def display_latex(*objs, **kwargs):
384 """Display the LaTeX representation of an object.
384 """Display the LaTeX representation of an object.
385
385
386 Parameters
386 Parameters
387 ----------
387 ----------
388 objs : tuple of objects
388 objs : tuple of objects
389 The Python objects to display, or if raw=True raw latex data to
389 The Python objects to display, or if raw=True raw latex data to
390 display.
390 display.
391 raw : bool
391 raw : bool
392 Are the data objects raw data or Python objects that need to be
392 Are the data objects raw data or Python objects that need to be
393 formatted before display? [default: False]
393 formatted before display? [default: False]
394 metadata : dict (optional)
394 metadata : dict (optional)
395 Metadata to be associated with the specific mimetype output.
395 Metadata to be associated with the specific mimetype output.
396 """
396 """
397 _display_mimetype('text/latex', objs, **kwargs)
397 _display_mimetype('text/latex', objs, **kwargs)
398
398
399
399
400 def display_json(*objs, **kwargs):
400 def display_json(*objs, **kwargs):
401 """Display the JSON representation of an object.
401 """Display the JSON representation of an object.
402
402
403 Note that not many frontends support displaying JSON.
403 Note that not many frontends support displaying JSON.
404
404
405 Parameters
405 Parameters
406 ----------
406 ----------
407 objs : tuple of objects
407 objs : tuple of objects
408 The Python objects to display, or if raw=True raw json data to
408 The Python objects to display, or if raw=True raw json data to
409 display.
409 display.
410 raw : bool
410 raw : bool
411 Are the data objects raw data or Python objects that need to be
411 Are the data objects raw data or Python objects that need to be
412 formatted before display? [default: False]
412 formatted before display? [default: False]
413 metadata : dict (optional)
413 metadata : dict (optional)
414 Metadata to be associated with the specific mimetype output.
414 Metadata to be associated with the specific mimetype output.
415 """
415 """
416 _display_mimetype('application/json', objs, **kwargs)
416 _display_mimetype('application/json', objs, **kwargs)
417
417
418
418
419 def display_javascript(*objs, **kwargs):
419 def display_javascript(*objs, **kwargs):
420 """Display the Javascript representation of an object.
420 """Display the Javascript representation of an object.
421
421
422 Parameters
422 Parameters
423 ----------
423 ----------
424 objs : tuple of objects
424 objs : tuple of objects
425 The Python objects to display, or if raw=True raw javascript data to
425 The Python objects to display, or if raw=True raw javascript data to
426 display.
426 display.
427 raw : bool
427 raw : bool
428 Are the data objects raw data or Python objects that need to be
428 Are the data objects raw data or Python objects that need to be
429 formatted before display? [default: False]
429 formatted before display? [default: False]
430 metadata : dict (optional)
430 metadata : dict (optional)
431 Metadata to be associated with the specific mimetype output.
431 Metadata to be associated with the specific mimetype output.
432 """
432 """
433 _display_mimetype('application/javascript', objs, **kwargs)
433 _display_mimetype('application/javascript', objs, **kwargs)
434
434
435
435
436 def display_pdf(*objs, **kwargs):
436 def display_pdf(*objs, **kwargs):
437 """Display the PDF representation of an object.
437 """Display the PDF representation of an object.
438
438
439 Parameters
439 Parameters
440 ----------
440 ----------
441 objs : tuple of objects
441 objs : tuple of objects
442 The Python objects to display, or if raw=True raw javascript data to
442 The Python objects to display, or if raw=True raw javascript data to
443 display.
443 display.
444 raw : bool
444 raw : bool
445 Are the data objects raw data or Python objects that need to be
445 Are the data objects raw data or Python objects that need to be
446 formatted before display? [default: False]
446 formatted before display? [default: False]
447 metadata : dict (optional)
447 metadata : dict (optional)
448 Metadata to be associated with the specific mimetype output.
448 Metadata to be associated with the specific mimetype output.
449 """
449 """
450 _display_mimetype('application/pdf', objs, **kwargs)
450 _display_mimetype('application/pdf', objs, **kwargs)
451
451
452
452
453 #-----------------------------------------------------------------------------
453 #-----------------------------------------------------------------------------
454 # Smart classes
454 # Smart classes
455 #-----------------------------------------------------------------------------
455 #-----------------------------------------------------------------------------
456
456
457
457
458 class DisplayObject(object):
458 class DisplayObject(object):
459 """An object that wraps data to be displayed."""
459 """An object that wraps data to be displayed."""
460
460
461 _read_flags = 'r'
461 _read_flags = 'r'
462 _show_mem_addr = False
462 _show_mem_addr = False
463
463
464 def __init__(self, data=None, url=None, filename=None):
464 def __init__(self, data=None, url=None, filename=None):
465 """Create a display object given raw data.
465 """Create a display object given raw data.
466
466
467 When this object is returned by an expression or passed to the
467 When this object is returned by an expression or passed to the
468 display function, it will result in the data being displayed
468 display function, it will result in the data being displayed
469 in the frontend. The MIME type of the data should match the
469 in the frontend. The MIME type of the data should match the
470 subclasses used, so the Png subclass should be used for 'image/png'
470 subclasses used, so the Png subclass should be used for 'image/png'
471 data. If the data is a URL, the data will first be downloaded
471 data. If the data is a URL, the data will first be downloaded
472 and then displayed. If
472 and then displayed. If
473
473
474 Parameters
474 Parameters
475 ----------
475 ----------
476 data : unicode, str or bytes
476 data : unicode, str or bytes
477 The raw data or a URL or file to load the data from
477 The raw data or a URL or file to load the data from
478 url : unicode
478 url : unicode
479 A URL to download the data from.
479 A URL to download the data from.
480 filename : unicode
480 filename : unicode
481 Path to a local file to load the data from.
481 Path to a local file to load the data from.
482 """
482 """
483 if data is not None and isinstance(data, str):
483 if data is not None and isinstance(data, str):
484 if data.startswith('http') and url is None:
484 if data.startswith('http') and url is None:
485 url = data
485 url = data
486 filename = None
486 filename = None
487 data = None
487 data = None
488 elif _safe_exists(data) and filename is None:
488 elif _safe_exists(data) and filename is None:
489 url = None
489 url = None
490 filename = data
490 filename = data
491 data = None
491 data = None
492
492
493 self.data = data
493 self.data = data
494 self.url = url
494 self.url = url
495 self.filename = filename
495 self.filename = filename
496
496
497 self.reload()
497 self.reload()
498 self._check_data()
498 self._check_data()
499
499
500 def __repr__(self):
500 def __repr__(self):
501 if not self._show_mem_addr:
501 if not self._show_mem_addr:
502 cls = self.__class__
502 cls = self.__class__
503 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
503 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
504 else:
504 else:
505 r = super(DisplayObject, self).__repr__()
505 r = super(DisplayObject, self).__repr__()
506 return r
506 return r
507
507
508 def _check_data(self):
508 def _check_data(self):
509 """Override in subclasses if there's something to check."""
509 """Override in subclasses if there's something to check."""
510 pass
510 pass
511
511
512 def reload(self):
512 def reload(self):
513 """Reload the raw data from file or URL."""
513 """Reload the raw data from file or URL."""
514 if self.filename is not None:
514 if self.filename is not None:
515 with open(self.filename, self._read_flags) as f:
515 with open(self.filename, self._read_flags) as f:
516 self.data = f.read()
516 self.data = f.read()
517 elif self.url is not None:
517 elif self.url is not None:
518 try:
518 try:
519 # Deferred import
519 # Deferred import
520 from urllib.request import urlopen
520 from urllib.request import urlopen
521 response = urlopen(self.url)
521 response = urlopen(self.url)
522 self.data = response.read()
522 self.data = response.read()
523 # extract encoding from header, if there is one:
523 # extract encoding from header, if there is one:
524 encoding = None
524 encoding = None
525 for sub in response.headers['content-type'].split(';'):
525 for sub in response.headers['content-type'].split(';'):
526 sub = sub.strip()
526 sub = sub.strip()
527 if sub.startswith('charset'):
527 if sub.startswith('charset'):
528 encoding = sub.split('=')[-1].strip()
528 encoding = sub.split('=')[-1].strip()
529 break
529 break
530 # decode data, if an encoding was specified
530 # decode data, if an encoding was specified
531 if encoding:
531 if encoding:
532 self.data = self.data.decode(encoding, 'replace')
532 self.data = self.data.decode(encoding, 'replace')
533 except:
533 except:
534 self.data = None
534 self.data = None
535
535
536 class TextDisplayObject(DisplayObject):
536 class TextDisplayObject(DisplayObject):
537 """Validate that display data is text"""
537 """Validate that display data is text"""
538 def _check_data(self):
538 def _check_data(self):
539 if self.data is not None and not isinstance(self.data, str):
539 if self.data is not None and not isinstance(self.data, str):
540 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
540 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
541
541
542 class Pretty(TextDisplayObject):
542 class Pretty(TextDisplayObject):
543
543
544 def _repr_pretty_(self):
544 def _repr_pretty_(self):
545 return self.data
545 return self.data
546
546
547
547
548 class HTML(TextDisplayObject):
548 class HTML(TextDisplayObject):
549
549
550 def _repr_html_(self):
550 def _repr_html_(self):
551 return self.data
551 return self.data
552
552
553 def __html__(self):
553 def __html__(self):
554 """
554 """
555 This method exists to inform other HTML-using modules (e.g. Markupsafe,
555 This method exists to inform other HTML-using modules (e.g. Markupsafe,
556 htmltag, etc) that this object is HTML and does not need things like
556 htmltag, etc) that this object is HTML and does not need things like
557 special characters (<>&) escaped.
557 special characters (<>&) escaped.
558 """
558 """
559 return self._repr_html_()
559 return self._repr_html_()
560
560
561
561
562 class Markdown(TextDisplayObject):
562 class Markdown(TextDisplayObject):
563
563
564 def _repr_markdown_(self):
564 def _repr_markdown_(self):
565 return self.data
565 return self.data
566
566
567
567
568 class Math(TextDisplayObject):
568 class Math(TextDisplayObject):
569
569
570 def _repr_latex_(self):
570 def _repr_latex_(self):
571 s = self.data.strip('$')
571 s = self.data.strip('$')
572 return "$$%s$$" % s
572 return "$$%s$$" % s
573
573
574
574
575 class Latex(TextDisplayObject):
575 class Latex(TextDisplayObject):
576
576
577 def _repr_latex_(self):
577 def _repr_latex_(self):
578 return self.data
578 return self.data
579
579
580
580
581 class SVG(DisplayObject):
581 class SVG(DisplayObject):
582
582
583 _read_flags = 'rb'
583 _read_flags = 'rb'
584 # wrap data in a property, which extracts the <svg> tag, discarding
584 # wrap data in a property, which extracts the <svg> tag, discarding
585 # document headers
585 # document headers
586 _data = None
586 _data = None
587
587
588 @property
588 @property
589 def data(self):
589 def data(self):
590 return self._data
590 return self._data
591
591
592 @data.setter
592 @data.setter
593 def data(self, svg):
593 def data(self, svg):
594 if svg is None:
594 if svg is None:
595 self._data = None
595 self._data = None
596 return
596 return
597 # parse into dom object
597 # parse into dom object
598 from xml.dom import minidom
598 from xml.dom import minidom
599 svg = cast_bytes_py2(svg)
600 x = minidom.parseString(svg)
599 x = minidom.parseString(svg)
601 # get svg tag (should be 1)
600 # get svg tag (should be 1)
602 found_svg = x.getElementsByTagName('svg')
601 found_svg = x.getElementsByTagName('svg')
603 if found_svg:
602 if found_svg:
604 svg = found_svg[0].toxml()
603 svg = found_svg[0].toxml()
605 else:
604 else:
606 # fallback on the input, trust the user
605 # fallback on the input, trust the user
607 # but this is probably an error.
606 # but this is probably an error.
608 pass
607 pass
609 svg = cast_unicode(svg)
608 svg = cast_unicode(svg)
610 self._data = svg
609 self._data = svg
611
610
612 def _repr_svg_(self):
611 def _repr_svg_(self):
613 return self.data
612 return self.data
614
613
615
614
616 class JSON(DisplayObject):
615 class JSON(DisplayObject):
617 """JSON expects a JSON-able dict or list
616 """JSON expects a JSON-able dict or list
618
617
619 not an already-serialized JSON string.
618 not an already-serialized JSON string.
620
619
621 Scalar types (None, number, string) are not allowed, only dict or list containers.
620 Scalar types (None, number, string) are not allowed, only dict or list containers.
622 """
621 """
623 # wrap data in a property, which warns about passing already-serialized JSON
622 # wrap data in a property, which warns about passing already-serialized JSON
624 _data = None
623 _data = None
625 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, **kwargs):
624 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, **kwargs):
626 """Create a JSON display object given raw data.
625 """Create a JSON display object given raw data.
627
626
628 Parameters
627 Parameters
629 ----------
628 ----------
630 data : dict or list
629 data : dict or list
631 JSON data to display. Not an already-serialized JSON string.
630 JSON data to display. Not an already-serialized JSON string.
632 Scalar types (None, number, string) are not allowed, only dict
631 Scalar types (None, number, string) are not allowed, only dict
633 or list containers.
632 or list containers.
634 url : unicode
633 url : unicode
635 A URL to download the data from.
634 A URL to download the data from.
636 filename : unicode
635 filename : unicode
637 Path to a local file to load the data from.
636 Path to a local file to load the data from.
638 expanded : boolean
637 expanded : boolean
639 Metadata to control whether a JSON display component is expanded.
638 Metadata to control whether a JSON display component is expanded.
640 metadata: dict
639 metadata: dict
641 Specify extra metadata to attach to the json display object.
640 Specify extra metadata to attach to the json display object.
642 """
641 """
643 self.metadata = {'expanded': expanded}
642 self.metadata = {'expanded': expanded}
644 if metadata:
643 if metadata:
645 self.metadata.update(metadata)
644 self.metadata.update(metadata)
646 if kwargs:
645 if kwargs:
647 self.metadata.update(kwargs)
646 self.metadata.update(kwargs)
648 super(JSON, self).__init__(data=data, url=url, filename=filename)
647 super(JSON, self).__init__(data=data, url=url, filename=filename)
649
648
650 def _check_data(self):
649 def _check_data(self):
651 if self.data is not None and not isinstance(self.data, (dict, list)):
650 if self.data is not None and not isinstance(self.data, (dict, list)):
652 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
651 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
653
652
654 @property
653 @property
655 def data(self):
654 def data(self):
656 return self._data
655 return self._data
657
656
658 @data.setter
657 @data.setter
659 def data(self, data):
658 def data(self, data):
660 if isinstance(data, str):
659 if isinstance(data, str):
661 if getattr(self, 'filename', None) is None:
660 if getattr(self, 'filename', None) is None:
662 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
661 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
663 data = json.loads(data)
662 data = json.loads(data)
664 self._data = data
663 self._data = data
665
664
666 def _data_and_metadata(self):
665 def _data_and_metadata(self):
667 return self.data, self.metadata
666 return self.data, self.metadata
668
667
669 def _repr_json_(self):
668 def _repr_json_(self):
670 return self._data_and_metadata()
669 return self._data_and_metadata()
671
670
672 _css_t = """$("head").append($("<link/>").attr({
671 _css_t = """$("head").append($("<link/>").attr({
673 rel: "stylesheet",
672 rel: "stylesheet",
674 type: "text/css",
673 type: "text/css",
675 href: "%s"
674 href: "%s"
676 }));
675 }));
677 """
676 """
678
677
679 _lib_t1 = """$.getScript("%s", function () {
678 _lib_t1 = """$.getScript("%s", function () {
680 """
679 """
681 _lib_t2 = """});
680 _lib_t2 = """});
682 """
681 """
683
682
684 class GeoJSON(JSON):
683 class GeoJSON(JSON):
685 """GeoJSON expects JSON-able dict
684 """GeoJSON expects JSON-able dict
686
685
687 not an already-serialized JSON string.
686 not an already-serialized JSON string.
688
687
689 Scalar types (None, number, string) are not allowed, only dict containers.
688 Scalar types (None, number, string) are not allowed, only dict containers.
690 """
689 """
691
690
692 def __init__(self, *args, **kwargs):
691 def __init__(self, *args, **kwargs):
693 """Create a GeoJSON display object given raw data.
692 """Create a GeoJSON display object given raw data.
694
693
695 Parameters
694 Parameters
696 ----------
695 ----------
697 data : dict or list
696 data : dict or list
698 VegaLite data. Not an already-serialized JSON string.
697 VegaLite data. Not an already-serialized JSON string.
699 Scalar types (None, number, string) are not allowed, only dict
698 Scalar types (None, number, string) are not allowed, only dict
700 or list containers.
699 or list containers.
701 url_template : string
700 url_template : string
702 Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
701 Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
703 layer_options : dict
702 layer_options : dict
704 Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
703 Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
705 url : unicode
704 url : unicode
706 A URL to download the data from.
705 A URL to download the data from.
707 filename : unicode
706 filename : unicode
708 Path to a local file to load the data from.
707 Path to a local file to load the data from.
709 metadata: dict
708 metadata: dict
710 Specify extra metadata to attach to the json display object.
709 Specify extra metadata to attach to the json display object.
711
710
712 Examples
711 Examples
713 --------
712 --------
714
713
715 The following will display an interactive map of Mars with a point of
714 The following will display an interactive map of Mars with a point of
716 interest on frontend that do support GeoJSON display.
715 interest on frontend that do support GeoJSON display.
717
716
718 >>> from IPython.display import GeoJSON
717 >>> from IPython.display import GeoJSON
719
718
720 >>> GeoJSON(data={
719 >>> GeoJSON(data={
721 ... "type": "Feature",
720 ... "type": "Feature",
722 ... "geometry": {
721 ... "geometry": {
723 ... "type": "Point",
722 ... "type": "Point",
724 ... "coordinates": [-81.327, 296.038]
723 ... "coordinates": [-81.327, 296.038]
725 ... }
724 ... }
726 ... },
725 ... },
727 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
726 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
728 ... layer_options={
727 ... layer_options={
729 ... "basemap_id": "celestia_mars-shaded-16k_global",
728 ... "basemap_id": "celestia_mars-shaded-16k_global",
730 ... "attribution" : "Celestia/praesepe",
729 ... "attribution" : "Celestia/praesepe",
731 ... "minZoom" : 0,
730 ... "minZoom" : 0,
732 ... "maxZoom" : 18,
731 ... "maxZoom" : 18,
733 ... })
732 ... })
734 <IPython.core.display.GeoJSON object>
733 <IPython.core.display.GeoJSON object>
735
734
736 In the terminal IPython, you will only see the text representation of
735 In the terminal IPython, you will only see the text representation of
737 the GeoJSON object.
736 the GeoJSON object.
738
737
739 """
738 """
740
739
741 super(GeoJSON, self).__init__(*args, **kwargs)
740 super(GeoJSON, self).__init__(*args, **kwargs)
742
741
743
742
744 def _ipython_display_(self):
743 def _ipython_display_(self):
745 bundle = {
744 bundle = {
746 'application/geo+json': self.data,
745 'application/geo+json': self.data,
747 'text/plain': '<IPython.display.GeoJSON object>'
746 'text/plain': '<IPython.display.GeoJSON object>'
748 }
747 }
749 metadata = {
748 metadata = {
750 'application/geo+json': self.metadata
749 'application/geo+json': self.metadata
751 }
750 }
752 display(bundle, metadata=metadata, raw=True)
751 display(bundle, metadata=metadata, raw=True)
753
752
754 class Javascript(TextDisplayObject):
753 class Javascript(TextDisplayObject):
755
754
756 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
755 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
757 """Create a Javascript display object given raw data.
756 """Create a Javascript display object given raw data.
758
757
759 When this object is returned by an expression or passed to the
758 When this object is returned by an expression or passed to the
760 display function, it will result in the data being displayed
759 display function, it will result in the data being displayed
761 in the frontend. If the data is a URL, the data will first be
760 in the frontend. If the data is a URL, the data will first be
762 downloaded and then displayed.
761 downloaded and then displayed.
763
762
764 In the Notebook, the containing element will be available as `element`,
763 In the Notebook, the containing element will be available as `element`,
765 and jQuery will be available. Content appended to `element` will be
764 and jQuery will be available. Content appended to `element` will be
766 visible in the output area.
765 visible in the output area.
767
766
768 Parameters
767 Parameters
769 ----------
768 ----------
770 data : unicode, str or bytes
769 data : unicode, str or bytes
771 The Javascript source code or a URL to download it from.
770 The Javascript source code or a URL to download it from.
772 url : unicode
771 url : unicode
773 A URL to download the data from.
772 A URL to download the data from.
774 filename : unicode
773 filename : unicode
775 Path to a local file to load the data from.
774 Path to a local file to load the data from.
776 lib : list or str
775 lib : list or str
777 A sequence of Javascript library URLs to load asynchronously before
776 A sequence of Javascript library URLs to load asynchronously before
778 running the source code. The full URLs of the libraries should
777 running the source code. The full URLs of the libraries should
779 be given. A single Javascript library URL can also be given as a
778 be given. A single Javascript library URL can also be given as a
780 string.
779 string.
781 css: : list or str
780 css: : list or str
782 A sequence of css files to load before running the source code.
781 A sequence of css files to load before running the source code.
783 The full URLs of the css files should be given. A single css URL
782 The full URLs of the css files should be given. A single css URL
784 can also be given as a string.
783 can also be given as a string.
785 """
784 """
786 if isinstance(lib, str):
785 if isinstance(lib, str):
787 lib = [lib]
786 lib = [lib]
788 elif lib is None:
787 elif lib is None:
789 lib = []
788 lib = []
790 if isinstance(css, str):
789 if isinstance(css, str):
791 css = [css]
790 css = [css]
792 elif css is None:
791 elif css is None:
793 css = []
792 css = []
794 if not isinstance(lib, (list,tuple)):
793 if not isinstance(lib, (list,tuple)):
795 raise TypeError('expected sequence, got: %r' % lib)
794 raise TypeError('expected sequence, got: %r' % lib)
796 if not isinstance(css, (list,tuple)):
795 if not isinstance(css, (list,tuple)):
797 raise TypeError('expected sequence, got: %r' % css)
796 raise TypeError('expected sequence, got: %r' % css)
798 self.lib = lib
797 self.lib = lib
799 self.css = css
798 self.css = css
800 super(Javascript, self).__init__(data=data, url=url, filename=filename)
799 super(Javascript, self).__init__(data=data, url=url, filename=filename)
801
800
802 def _repr_javascript_(self):
801 def _repr_javascript_(self):
803 r = ''
802 r = ''
804 for c in self.css:
803 for c in self.css:
805 r += _css_t % c
804 r += _css_t % c
806 for l in self.lib:
805 for l in self.lib:
807 r += _lib_t1 % l
806 r += _lib_t1 % l
808 r += self.data
807 r += self.data
809 r += _lib_t2*len(self.lib)
808 r += _lib_t2*len(self.lib)
810 return r
809 return r
811
810
812 # constants for identifying png/jpeg data
811 # constants for identifying png/jpeg data
813 _PNG = b'\x89PNG\r\n\x1a\n'
812 _PNG = b'\x89PNG\r\n\x1a\n'
814 _JPEG = b'\xff\xd8'
813 _JPEG = b'\xff\xd8'
815
814
816 def _pngxy(data):
815 def _pngxy(data):
817 """read the (width, height) from a PNG header"""
816 """read the (width, height) from a PNG header"""
818 ihdr = data.index(b'IHDR')
817 ihdr = data.index(b'IHDR')
819 # next 8 bytes are width/height
818 # next 8 bytes are width/height
820 w4h4 = data[ihdr+4:ihdr+12]
819 w4h4 = data[ihdr+4:ihdr+12]
821 return struct.unpack('>ii', w4h4)
820 return struct.unpack('>ii', w4h4)
822
821
823 def _jpegxy(data):
822 def _jpegxy(data):
824 """read the (width, height) from a JPEG header"""
823 """read the (width, height) from a JPEG header"""
825 # adapted from http://www.64lines.com/jpeg-width-height
824 # adapted from http://www.64lines.com/jpeg-width-height
826
825
827 idx = 4
826 idx = 4
828 while True:
827 while True:
829 block_size = struct.unpack('>H', data[idx:idx+2])[0]
828 block_size = struct.unpack('>H', data[idx:idx+2])[0]
830 idx = idx + block_size
829 idx = idx + block_size
831 if data[idx:idx+2] == b'\xFF\xC0':
830 if data[idx:idx+2] == b'\xFF\xC0':
832 # found Start of Frame
831 # found Start of Frame
833 iSOF = idx
832 iSOF = idx
834 break
833 break
835 else:
834 else:
836 # read another block
835 # read another block
837 idx += 2
836 idx += 2
838
837
839 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
838 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
840 return w, h
839 return w, h
841
840
842 class Image(DisplayObject):
841 class Image(DisplayObject):
843
842
844 _read_flags = 'rb'
843 _read_flags = 'rb'
845 _FMT_JPEG = u'jpeg'
844 _FMT_JPEG = u'jpeg'
846 _FMT_PNG = u'png'
845 _FMT_PNG = u'png'
847 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
846 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
848
847
849 def __init__(self, data=None, url=None, filename=None, format=None,
848 def __init__(self, data=None, url=None, filename=None, format=None,
850 embed=None, width=None, height=None, retina=False,
849 embed=None, width=None, height=None, retina=False,
851 unconfined=False, metadata=None):
850 unconfined=False, metadata=None):
852 """Create a PNG/JPEG image object given raw data.
851 """Create a PNG/JPEG image object given raw data.
853
852
854 When this object is returned by an input cell or passed to the
853 When this object is returned by an input cell or passed to the
855 display function, it will result in the image being displayed
854 display function, it will result in the image being displayed
856 in the frontend.
855 in the frontend.
857
856
858 Parameters
857 Parameters
859 ----------
858 ----------
860 data : unicode, str or bytes
859 data : unicode, str or bytes
861 The raw image data or a URL or filename to load the data from.
860 The raw image data or a URL or filename to load the data from.
862 This always results in embedded image data.
861 This always results in embedded image data.
863 url : unicode
862 url : unicode
864 A URL to download the data from. If you specify `url=`,
863 A URL to download the data from. If you specify `url=`,
865 the image data will not be embedded unless you also specify `embed=True`.
864 the image data will not be embedded unless you also specify `embed=True`.
866 filename : unicode
865 filename : unicode
867 Path to a local file to load the data from.
866 Path to a local file to load the data from.
868 Images from a file are always embedded.
867 Images from a file are always embedded.
869 format : unicode
868 format : unicode
870 The format of the image data (png/jpeg/jpg). If a filename or URL is given
869 The format of the image data (png/jpeg/jpg). If a filename or URL is given
871 for format will be inferred from the filename extension.
870 for format will be inferred from the filename extension.
872 embed : bool
871 embed : bool
873 Should the image data be embedded using a data URI (True) or be
872 Should the image data be embedded using a data URI (True) or be
874 loaded using an <img> tag. Set this to True if you want the image
873 loaded using an <img> tag. Set this to True if you want the image
875 to be viewable later with no internet connection in the notebook.
874 to be viewable later with no internet connection in the notebook.
876
875
877 Default is `True`, unless the keyword argument `url` is set, then
876 Default is `True`, unless the keyword argument `url` is set, then
878 default value is `False`.
877 default value is `False`.
879
878
880 Note that QtConsole is not able to display images if `embed` is set to `False`
879 Note that QtConsole is not able to display images if `embed` is set to `False`
881 width : int
880 width : int
882 Width in pixels to which to constrain the image in html
881 Width in pixels to which to constrain the image in html
883 height : int
882 height : int
884 Height in pixels to which to constrain the image in html
883 Height in pixels to which to constrain the image in html
885 retina : bool
884 retina : bool
886 Automatically set the width and height to half of the measured
885 Automatically set the width and height to half of the measured
887 width and height.
886 width and height.
888 This only works for embedded images because it reads the width/height
887 This only works for embedded images because it reads the width/height
889 from image data.
888 from image data.
890 For non-embedded images, you can just set the desired display width
889 For non-embedded images, you can just set the desired display width
891 and height directly.
890 and height directly.
892 unconfined: bool
891 unconfined: bool
893 Set unconfined=True to disable max-width confinement of the image.
892 Set unconfined=True to disable max-width confinement of the image.
894 metadata: dict
893 metadata: dict
895 Specify extra metadata to attach to the image.
894 Specify extra metadata to attach to the image.
896
895
897 Examples
896 Examples
898 --------
897 --------
899 # embedded image data, works in qtconsole and notebook
898 # embedded image data, works in qtconsole and notebook
900 # when passed positionally, the first arg can be any of raw image data,
899 # when passed positionally, the first arg can be any of raw image data,
901 # a URL, or a filename from which to load image data.
900 # a URL, or a filename from which to load image data.
902 # The result is always embedding image data for inline images.
901 # The result is always embedding image data for inline images.
903 Image('http://www.google.fr/images/srpr/logo3w.png')
902 Image('http://www.google.fr/images/srpr/logo3w.png')
904 Image('/path/to/image.jpg')
903 Image('/path/to/image.jpg')
905 Image(b'RAW_PNG_DATA...')
904 Image(b'RAW_PNG_DATA...')
906
905
907 # Specifying Image(url=...) does not embed the image data,
906 # Specifying Image(url=...) does not embed the image data,
908 # it only generates `<img>` tag with a link to the source.
907 # it only generates `<img>` tag with a link to the source.
909 # This will not work in the qtconsole or offline.
908 # This will not work in the qtconsole or offline.
910 Image(url='http://www.google.fr/images/srpr/logo3w.png')
909 Image(url='http://www.google.fr/images/srpr/logo3w.png')
911
910
912 """
911 """
913 if filename is not None:
912 if filename is not None:
914 ext = self._find_ext(filename)
913 ext = self._find_ext(filename)
915 elif url is not None:
914 elif url is not None:
916 ext = self._find_ext(url)
915 ext = self._find_ext(url)
917 elif data is None:
916 elif data is None:
918 raise ValueError("No image data found. Expecting filename, url, or data.")
917 raise ValueError("No image data found. Expecting filename, url, or data.")
919 elif isinstance(data, str) and (
918 elif isinstance(data, str) and (
920 data.startswith('http') or _safe_exists(data)
919 data.startswith('http') or _safe_exists(data)
921 ):
920 ):
922 ext = self._find_ext(data)
921 ext = self._find_ext(data)
923 else:
922 else:
924 ext = None
923 ext = None
925
924
926 if format is None:
925 if format is None:
927 if ext is not None:
926 if ext is not None:
928 if ext == u'jpg' or ext == u'jpeg':
927 if ext == u'jpg' or ext == u'jpeg':
929 format = self._FMT_JPEG
928 format = self._FMT_JPEG
930 if ext == u'png':
929 if ext == u'png':
931 format = self._FMT_PNG
930 format = self._FMT_PNG
932 else:
931 else:
933 format = ext.lower()
932 format = ext.lower()
934 elif isinstance(data, bytes):
933 elif isinstance(data, bytes):
935 # infer image type from image data header,
934 # infer image type from image data header,
936 # only if format has not been specified.
935 # only if format has not been specified.
937 if data[:2] == _JPEG:
936 if data[:2] == _JPEG:
938 format = self._FMT_JPEG
937 format = self._FMT_JPEG
939
938
940 # failed to detect format, default png
939 # failed to detect format, default png
941 if format is None:
940 if format is None:
942 format = 'png'
941 format = 'png'
943
942
944 if format.lower() == 'jpg':
943 if format.lower() == 'jpg':
945 # jpg->jpeg
944 # jpg->jpeg
946 format = self._FMT_JPEG
945 format = self._FMT_JPEG
947
946
948 self.format = format.lower()
947 self.format = format.lower()
949 self.embed = embed if embed is not None else (url is None)
948 self.embed = embed if embed is not None else (url is None)
950
949
951 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
950 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
952 raise ValueError("Cannot embed the '%s' image format" % (self.format))
951 raise ValueError("Cannot embed the '%s' image format" % (self.format))
953 self.width = width
952 self.width = width
954 self.height = height
953 self.height = height
955 self.retina = retina
954 self.retina = retina
956 self.unconfined = unconfined
955 self.unconfined = unconfined
957 self.metadata = metadata
956 self.metadata = metadata
958 super(Image, self).__init__(data=data, url=url, filename=filename)
957 super(Image, self).__init__(data=data, url=url, filename=filename)
959
958
960 if retina:
959 if retina:
961 self._retina_shape()
960 self._retina_shape()
962
961
963 def _retina_shape(self):
962 def _retina_shape(self):
964 """load pixel-doubled width and height from image data"""
963 """load pixel-doubled width and height from image data"""
965 if not self.embed:
964 if not self.embed:
966 return
965 return
967 if self.format == 'png':
966 if self.format == 'png':
968 w, h = _pngxy(self.data)
967 w, h = _pngxy(self.data)
969 elif self.format == 'jpeg':
968 elif self.format == 'jpeg':
970 w, h = _jpegxy(self.data)
969 w, h = _jpegxy(self.data)
971 else:
970 else:
972 # retina only supports png
971 # retina only supports png
973 return
972 return
974 self.width = w // 2
973 self.width = w // 2
975 self.height = h // 2
974 self.height = h // 2
976
975
977 def reload(self):
976 def reload(self):
978 """Reload the raw data from file or URL."""
977 """Reload the raw data from file or URL."""
979 if self.embed:
978 if self.embed:
980 super(Image,self).reload()
979 super(Image,self).reload()
981 if self.retina:
980 if self.retina:
982 self._retina_shape()
981 self._retina_shape()
983
982
984 def _repr_html_(self):
983 def _repr_html_(self):
985 if not self.embed:
984 if not self.embed:
986 width = height = klass = ''
985 width = height = klass = ''
987 if self.width:
986 if self.width:
988 width = ' width="%d"' % self.width
987 width = ' width="%d"' % self.width
989 if self.height:
988 if self.height:
990 height = ' height="%d"' % self.height
989 height = ' height="%d"' % self.height
991 if self.unconfined:
990 if self.unconfined:
992 klass = ' class="unconfined"'
991 klass = ' class="unconfined"'
993 return u'<img src="{url}"{width}{height}{klass}/>'.format(
992 return u'<img src="{url}"{width}{height}{klass}/>'.format(
994 url=self.url,
993 url=self.url,
995 width=width,
994 width=width,
996 height=height,
995 height=height,
997 klass=klass,
996 klass=klass,
998 )
997 )
999
998
1000 def _data_and_metadata(self):
999 def _data_and_metadata(self):
1001 """shortcut for returning metadata with shape information, if defined"""
1000 """shortcut for returning metadata with shape information, if defined"""
1002 md = {}
1001 md = {}
1003 if self.width:
1002 if self.width:
1004 md['width'] = self.width
1003 md['width'] = self.width
1005 if self.height:
1004 if self.height:
1006 md['height'] = self.height
1005 md['height'] = self.height
1007 if self.unconfined:
1006 if self.unconfined:
1008 md['unconfined'] = self.unconfined
1007 md['unconfined'] = self.unconfined
1009 if self.metadata:
1008 if self.metadata:
1010 md.update(self.metadata)
1009 md.update(self.metadata)
1011 if md:
1010 if md:
1012 return self.data, md
1011 return self.data, md
1013 else:
1012 else:
1014 return self.data
1013 return self.data
1015
1014
1016 def _repr_png_(self):
1015 def _repr_png_(self):
1017 if self.embed and self.format == u'png':
1016 if self.embed and self.format == u'png':
1018 return self._data_and_metadata()
1017 return self._data_and_metadata()
1019
1018
1020 def _repr_jpeg_(self):
1019 def _repr_jpeg_(self):
1021 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
1020 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
1022 return self._data_and_metadata()
1021 return self._data_and_metadata()
1023
1022
1024 def _find_ext(self, s):
1023 def _find_ext(self, s):
1025 return s.split('.')[-1].lower()
1024 return s.split('.')[-1].lower()
1026
1025
1027 class Video(DisplayObject):
1026 class Video(DisplayObject):
1028
1027
1029 def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=None):
1028 def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=None):
1030 """Create a video object given raw data or an URL.
1029 """Create a video object given raw data or an URL.
1031
1030
1032 When this object is returned by an input cell or passed to the
1031 When this object is returned by an input cell or passed to the
1033 display function, it will result in the video being displayed
1032 display function, it will result in the video being displayed
1034 in the frontend.
1033 in the frontend.
1035
1034
1036 Parameters
1035 Parameters
1037 ----------
1036 ----------
1038 data : unicode, str or bytes
1037 data : unicode, str or bytes
1039 The raw video data or a URL or filename to load the data from.
1038 The raw video data or a URL or filename to load the data from.
1040 Raw data will require passing `embed=True`.
1039 Raw data will require passing `embed=True`.
1041 url : unicode
1040 url : unicode
1042 A URL for the video. If you specify `url=`,
1041 A URL for the video. If you specify `url=`,
1043 the image data will not be embedded.
1042 the image data will not be embedded.
1044 filename : unicode
1043 filename : unicode
1045 Path to a local file containing the video.
1044 Path to a local file containing the video.
1046 Will be interpreted as a local URL unless `embed=True`.
1045 Will be interpreted as a local URL unless `embed=True`.
1047 embed : bool
1046 embed : bool
1048 Should the video be embedded using a data URI (True) or be
1047 Should the video be embedded using a data URI (True) or be
1049 loaded using a <video> tag (False).
1048 loaded using a <video> tag (False).
1050
1049
1051 Since videos are large, embedding them should be avoided, if possible.
1050 Since videos are large, embedding them should be avoided, if possible.
1052 You must confirm embedding as your intention by passing `embed=True`.
1051 You must confirm embedding as your intention by passing `embed=True`.
1053
1052
1054 Local files can be displayed with URLs without embedding the content, via::
1053 Local files can be displayed with URLs without embedding the content, via::
1055
1054
1056 Video('./video.mp4')
1055 Video('./video.mp4')
1057
1056
1058 mimetype: unicode
1057 mimetype: unicode
1059 Specify the mimetype for embedded videos.
1058 Specify the mimetype for embedded videos.
1060 Default will be guessed from file extension, if available.
1059 Default will be guessed from file extension, if available.
1061
1060
1062 Examples
1061 Examples
1063 --------
1062 --------
1064
1063
1065 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1064 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1066 Video('path/to/video.mp4')
1065 Video('path/to/video.mp4')
1067 Video('path/to/video.mp4', embed=True)
1066 Video('path/to/video.mp4', embed=True)
1068 Video(b'raw-videodata', embed=True)
1067 Video(b'raw-videodata', embed=True)
1069 """
1068 """
1070 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1069 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1071 url = data
1070 url = data
1072 data = None
1071 data = None
1073 elif os.path.exists(data):
1072 elif os.path.exists(data):
1074 filename = data
1073 filename = data
1075 data = None
1074 data = None
1076
1075
1077 if data and not embed:
1076 if data and not embed:
1078 msg = ''.join([
1077 msg = ''.join([
1079 "To embed videos, you must pass embed=True ",
1078 "To embed videos, you must pass embed=True ",
1080 "(this may make your notebook files huge)\n",
1079 "(this may make your notebook files huge)\n",
1081 "Consider passing Video(url='...')",
1080 "Consider passing Video(url='...')",
1082 ])
1081 ])
1083 raise ValueError(msg)
1082 raise ValueError(msg)
1084
1083
1085 self.mimetype = mimetype
1084 self.mimetype = mimetype
1086 self.embed = embed
1085 self.embed = embed
1087 super(Video, self).__init__(data=data, url=url, filename=filename)
1086 super(Video, self).__init__(data=data, url=url, filename=filename)
1088
1087
1089 def _repr_html_(self):
1088 def _repr_html_(self):
1090 # External URLs and potentially local files are not embedded into the
1089 # External URLs and potentially local files are not embedded into the
1091 # notebook output.
1090 # notebook output.
1092 if not self.embed:
1091 if not self.embed:
1093 url = self.url if self.url is not None else self.filename
1092 url = self.url if self.url is not None else self.filename
1094 output = """<video src="{0}" controls>
1093 output = """<video src="{0}" controls>
1095 Your browser does not support the <code>video</code> element.
1094 Your browser does not support the <code>video</code> element.
1096 </video>""".format(url)
1095 </video>""".format(url)
1097 return output
1096 return output
1098
1097
1099 # Embedded videos are base64-encoded.
1098 # Embedded videos are base64-encoded.
1100 mimetype = self.mimetype
1099 mimetype = self.mimetype
1101 if self.filename is not None:
1100 if self.filename is not None:
1102 if not mimetype:
1101 if not mimetype:
1103 mimetype, _ = mimetypes.guess_type(self.filename)
1102 mimetype, _ = mimetypes.guess_type(self.filename)
1104
1103
1105 with open(self.filename, 'rb') as f:
1104 with open(self.filename, 'rb') as f:
1106 video = f.read()
1105 video = f.read()
1107 else:
1106 else:
1108 video = self.data
1107 video = self.data
1109 if isinstance(video, str):
1108 if isinstance(video, str):
1110 # unicode input is already b64-encoded
1109 # unicode input is already b64-encoded
1111 b64_video = video
1110 b64_video = video
1112 else:
1111 else:
1113 b64_video = base64_encode(video).decode('ascii').rstrip()
1112 b64_video = base64_encode(video).decode('ascii').rstrip()
1114
1113
1115 output = """<video controls>
1114 output = """<video controls>
1116 <source src="data:{0};base64,{1}" type="{0}">
1115 <source src="data:{0};base64,{1}" type="{0}">
1117 Your browser does not support the video tag.
1116 Your browser does not support the video tag.
1118 </video>""".format(mimetype, b64_video)
1117 </video>""".format(mimetype, b64_video)
1119 return output
1118 return output
1120
1119
1121 def reload(self):
1120 def reload(self):
1122 # TODO
1121 # TODO
1123 pass
1122 pass
1124
1123
1125 def _repr_png_(self):
1124 def _repr_png_(self):
1126 # TODO
1125 # TODO
1127 pass
1126 pass
1128 def _repr_jpeg_(self):
1127 def _repr_jpeg_(self):
1129 # TODO
1128 # TODO
1130 pass
1129 pass
1131
1130
1132 def clear_output(wait=False):
1131 def clear_output(wait=False):
1133 """Clear the output of the current cell receiving output.
1132 """Clear the output of the current cell receiving output.
1134
1133
1135 Parameters
1134 Parameters
1136 ----------
1135 ----------
1137 wait : bool [default: false]
1136 wait : bool [default: false]
1138 Wait to clear the output until new output is available to replace it."""
1137 Wait to clear the output until new output is available to replace it."""
1139 from IPython.core.interactiveshell import InteractiveShell
1138 from IPython.core.interactiveshell import InteractiveShell
1140 if InteractiveShell.initialized():
1139 if InteractiveShell.initialized():
1141 InteractiveShell.instance().display_pub.clear_output(wait)
1140 InteractiveShell.instance().display_pub.clear_output(wait)
1142 else:
1141 else:
1143 print('\033[2K\r', end='')
1142 print('\033[2K\r', end='')
1144 sys.stdout.flush()
1143 sys.stdout.flush()
1145 print('\033[2K\r', end='')
1144 print('\033[2K\r', end='')
1146 sys.stderr.flush()
1145 sys.stderr.flush()
1147
1146
1148
1147
1149 @skip_doctest
1148 @skip_doctest
1150 def set_matplotlib_formats(*formats, **kwargs):
1149 def set_matplotlib_formats(*formats, **kwargs):
1151 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
1150 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
1152
1151
1153 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1152 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1154
1153
1155 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1154 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1156
1155
1157 To set this in your config files use the following::
1156 To set this in your config files use the following::
1158
1157
1159 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1158 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1160 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1159 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1161
1160
1162 Parameters
1161 Parameters
1163 ----------
1162 ----------
1164 *formats : strs
1163 *formats : strs
1165 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1164 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1166 **kwargs :
1165 **kwargs :
1167 Keyword args will be relayed to ``figure.canvas.print_figure``.
1166 Keyword args will be relayed to ``figure.canvas.print_figure``.
1168 """
1167 """
1169 from IPython.core.interactiveshell import InteractiveShell
1168 from IPython.core.interactiveshell import InteractiveShell
1170 from IPython.core.pylabtools import select_figure_formats
1169 from IPython.core.pylabtools import select_figure_formats
1171 # build kwargs, starting with InlineBackend config
1170 # build kwargs, starting with InlineBackend config
1172 kw = {}
1171 kw = {}
1173 from ipykernel.pylab.config import InlineBackend
1172 from ipykernel.pylab.config import InlineBackend
1174 cfg = InlineBackend.instance()
1173 cfg = InlineBackend.instance()
1175 kw.update(cfg.print_figure_kwargs)
1174 kw.update(cfg.print_figure_kwargs)
1176 kw.update(**kwargs)
1175 kw.update(**kwargs)
1177 shell = InteractiveShell.instance()
1176 shell = InteractiveShell.instance()
1178 select_figure_formats(shell, formats, **kw)
1177 select_figure_formats(shell, formats, **kw)
1179
1178
1180 @skip_doctest
1179 @skip_doctest
1181 def set_matplotlib_close(close=True):
1180 def set_matplotlib_close(close=True):
1182 """Set whether the inline backend closes all figures automatically or not.
1181 """Set whether the inline backend closes all figures automatically or not.
1183
1182
1184 By default, the inline backend used in the IPython Notebook will close all
1183 By default, the inline backend used in the IPython Notebook will close all
1185 matplotlib figures automatically after each cell is run. This means that
1184 matplotlib figures automatically after each cell is run. This means that
1186 plots in different cells won't interfere. Sometimes, you may want to make
1185 plots in different cells won't interfere. Sometimes, you may want to make
1187 a plot in one cell and then refine it in later cells. This can be accomplished
1186 a plot in one cell and then refine it in later cells. This can be accomplished
1188 by::
1187 by::
1189
1188
1190 In [1]: set_matplotlib_close(False)
1189 In [1]: set_matplotlib_close(False)
1191
1190
1192 To set this in your config files use the following::
1191 To set this in your config files use the following::
1193
1192
1194 c.InlineBackend.close_figures = False
1193 c.InlineBackend.close_figures = False
1195
1194
1196 Parameters
1195 Parameters
1197 ----------
1196 ----------
1198 close : bool
1197 close : bool
1199 Should all matplotlib figures be automatically closed after each cell is
1198 Should all matplotlib figures be automatically closed after each cell is
1200 run?
1199 run?
1201 """
1200 """
1202 from ipykernel.pylab.config import InlineBackend
1201 from ipykernel.pylab.config import InlineBackend
1203 cfg = InlineBackend.instance()
1202 cfg = InlineBackend.instance()
1204 cfg.close_figures = close
1203 cfg.close_figures = close
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,793 +1,793 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 # Copyright (c) IPython Development Team.
6 # Copyright (c) IPython Development Team.
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8
8
9 import io
9 import io
10 import os
10 import os
11 import re
11 import re
12 import sys
12 import sys
13 from pprint import pformat
13 from pprint import pformat
14
14
15 from IPython.core import magic_arguments
15 from IPython.core import magic_arguments
16 from IPython.core import oinspect
16 from IPython.core import oinspect
17 from IPython.core import page
17 from IPython.core import page
18 from IPython.core.alias import AliasError, Alias
18 from IPython.core.alias import AliasError, Alias
19 from IPython.core.error import UsageError
19 from IPython.core.error import UsageError
20 from IPython.core.magic import (
20 from IPython.core.magic import (
21 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
21 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
22 )
22 )
23 from IPython.testing.skipdoctest import skip_doctest
23 from IPython.testing.skipdoctest import skip_doctest
24 from IPython.utils.openpy import source_to_unicode
24 from IPython.utils.openpy import source_to_unicode
25 from IPython.utils.process import abbrev_cwd
25 from IPython.utils.process import abbrev_cwd
26 from IPython.utils import py3compat
26 from IPython.utils import py3compat
27 from IPython.utils.terminal import set_term_title
27 from IPython.utils.terminal import set_term_title
28
28
29
29
30 @magics_class
30 @magics_class
31 class OSMagics(Magics):
31 class OSMagics(Magics):
32 """Magics to interact with the underlying OS (shell-type functionality).
32 """Magics to interact with the underlying OS (shell-type functionality).
33 """
33 """
34
34
35 @skip_doctest
35 @skip_doctest
36 @line_magic
36 @line_magic
37 def alias(self, parameter_s=''):
37 def alias(self, parameter_s=''):
38 """Define an alias for a system command.
38 """Define an alias for a system command.
39
39
40 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
40 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
41
41
42 Then, typing 'alias_name params' will execute the system command 'cmd
42 Then, typing 'alias_name params' will execute the system command 'cmd
43 params' (from your underlying operating system).
43 params' (from your underlying operating system).
44
44
45 Aliases have lower precedence than magic functions and Python normal
45 Aliases have lower precedence than magic functions and Python normal
46 variables, so if 'foo' is both a Python variable and an alias, the
46 variables, so if 'foo' is both a Python variable and an alias, the
47 alias can not be executed until 'del foo' removes the Python variable.
47 alias can not be executed until 'del foo' removes the Python variable.
48
48
49 You can use the %l specifier in an alias definition to represent the
49 You can use the %l specifier in an alias definition to represent the
50 whole line when the alias is called. For example::
50 whole line when the alias is called. For example::
51
51
52 In [2]: alias bracket echo "Input in brackets: <%l>"
52 In [2]: alias bracket echo "Input in brackets: <%l>"
53 In [3]: bracket hello world
53 In [3]: bracket hello world
54 Input in brackets: <hello world>
54 Input in brackets: <hello world>
55
55
56 You can also define aliases with parameters using %s specifiers (one
56 You can also define aliases with parameters using %s specifiers (one
57 per parameter)::
57 per parameter)::
58
58
59 In [1]: alias parts echo first %s second %s
59 In [1]: alias parts echo first %s second %s
60 In [2]: %parts A B
60 In [2]: %parts A B
61 first A second B
61 first A second B
62 In [3]: %parts A
62 In [3]: %parts A
63 Incorrect number of arguments: 2 expected.
63 Incorrect number of arguments: 2 expected.
64 parts is an alias to: 'echo first %s second %s'
64 parts is an alias to: 'echo first %s second %s'
65
65
66 Note that %l and %s are mutually exclusive. You can only use one or
66 Note that %l and %s are mutually exclusive. You can only use one or
67 the other in your aliases.
67 the other in your aliases.
68
68
69 Aliases expand Python variables just like system calls using ! or !!
69 Aliases expand Python variables just like system calls using ! or !!
70 do: all expressions prefixed with '$' get expanded. For details of
70 do: all expressions prefixed with '$' get expanded. For details of
71 the semantic rules, see PEP-215:
71 the semantic rules, see PEP-215:
72 http://www.python.org/peps/pep-0215.html. This is the library used by
72 http://www.python.org/peps/pep-0215.html. This is the library used by
73 IPython for variable expansion. If you want to access a true shell
73 IPython for variable expansion. If you want to access a true shell
74 variable, an extra $ is necessary to prevent its expansion by
74 variable, an extra $ is necessary to prevent its expansion by
75 IPython::
75 IPython::
76
76
77 In [6]: alias show echo
77 In [6]: alias show echo
78 In [7]: PATH='A Python string'
78 In [7]: PATH='A Python string'
79 In [8]: show $PATH
79 In [8]: show $PATH
80 A Python string
80 A Python string
81 In [9]: show $$PATH
81 In [9]: show $$PATH
82 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
82 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
83
83
84 You can use the alias facility to access all of $PATH. See the %rehashx
84 You can use the alias facility to access all of $PATH. See the %rehashx
85 function, which automatically creates aliases for the contents of your
85 function, which automatically creates aliases for the contents of your
86 $PATH.
86 $PATH.
87
87
88 If called with no parameters, %alias prints the current alias table
88 If called with no parameters, %alias prints the current alias table
89 for your system. For posix systems, the default aliases are 'cat',
89 for your system. For posix systems, the default aliases are 'cat',
90 'cp', 'mv', 'rm', 'rmdir', and 'mkdir', and other platform-specific
90 'cp', 'mv', 'rm', 'rmdir', and 'mkdir', and other platform-specific
91 aliases are added. For windows-based systems, the default aliases are
91 aliases are added. For windows-based systems, the default aliases are
92 'copy', 'ddir', 'echo', 'ls', 'ldir', 'mkdir', 'ren', and 'rmdir'.
92 'copy', 'ddir', 'echo', 'ls', 'ldir', 'mkdir', 'ren', and 'rmdir'.
93
93
94 You can see the definition of alias by adding a question mark in the
94 You can see the definition of alias by adding a question mark in the
95 end::
95 end::
96
96
97 In [1]: cat?
97 In [1]: cat?
98 Repr: <alias cat for 'cat'>"""
98 Repr: <alias cat for 'cat'>"""
99
99
100 par = parameter_s.strip()
100 par = parameter_s.strip()
101 if not par:
101 if not par:
102 aliases = sorted(self.shell.alias_manager.aliases)
102 aliases = sorted(self.shell.alias_manager.aliases)
103 # stored = self.shell.db.get('stored_aliases', {} )
103 # stored = self.shell.db.get('stored_aliases', {} )
104 # for k, v in stored:
104 # for k, v in stored:
105 # atab.append(k, v[0])
105 # atab.append(k, v[0])
106
106
107 print("Total number of aliases:", len(aliases))
107 print("Total number of aliases:", len(aliases))
108 sys.stdout.flush()
108 sys.stdout.flush()
109 return aliases
109 return aliases
110
110
111 # Now try to define a new one
111 # Now try to define a new one
112 try:
112 try:
113 alias,cmd = par.split(None, 1)
113 alias,cmd = par.split(None, 1)
114 except TypeError:
114 except TypeError:
115 print(oinspect.getdoc(self.alias))
115 print(oinspect.getdoc(self.alias))
116 return
116 return
117
117
118 try:
118 try:
119 self.shell.alias_manager.define_alias(alias, cmd)
119 self.shell.alias_manager.define_alias(alias, cmd)
120 except AliasError as e:
120 except AliasError as e:
121 print(e)
121 print(e)
122 # end magic_alias
122 # end magic_alias
123
123
124 @line_magic
124 @line_magic
125 def unalias(self, parameter_s=''):
125 def unalias(self, parameter_s=''):
126 """Remove an alias"""
126 """Remove an alias"""
127
127
128 aname = parameter_s.strip()
128 aname = parameter_s.strip()
129 try:
129 try:
130 self.shell.alias_manager.undefine_alias(aname)
130 self.shell.alias_manager.undefine_alias(aname)
131 except ValueError as e:
131 except ValueError as e:
132 print(e)
132 print(e)
133 return
133 return
134
134
135 stored = self.shell.db.get('stored_aliases', {} )
135 stored = self.shell.db.get('stored_aliases', {} )
136 if aname in stored:
136 if aname in stored:
137 print("Removing %stored alias",aname)
137 print("Removing %stored alias",aname)
138 del stored[aname]
138 del stored[aname]
139 self.shell.db['stored_aliases'] = stored
139 self.shell.db['stored_aliases'] = stored
140
140
141 @line_magic
141 @line_magic
142 def rehashx(self, parameter_s=''):
142 def rehashx(self, parameter_s=''):
143 """Update the alias table with all executable files in $PATH.
143 """Update the alias table with all executable files in $PATH.
144
144
145 rehashx explicitly checks that every entry in $PATH is a file
145 rehashx explicitly checks that every entry in $PATH is a file
146 with execute access (os.X_OK).
146 with execute access (os.X_OK).
147
147
148 Under Windows, it checks executability as a match against a
148 Under Windows, it checks executability as a match against a
149 '|'-separated string of extensions, stored in the IPython config
149 '|'-separated string of extensions, stored in the IPython config
150 variable win_exec_ext. This defaults to 'exe|com|bat'.
150 variable win_exec_ext. This defaults to 'exe|com|bat'.
151
151
152 This function also resets the root module cache of module completer,
152 This function also resets the root module cache of module completer,
153 used on slow filesystems.
153 used on slow filesystems.
154 """
154 """
155 from IPython.core.alias import InvalidAliasError
155 from IPython.core.alias import InvalidAliasError
156
156
157 # for the benefit of module completer in ipy_completers.py
157 # for the benefit of module completer in ipy_completers.py
158 del self.shell.db['rootmodules_cache']
158 del self.shell.db['rootmodules_cache']
159
159
160 path = [os.path.abspath(os.path.expanduser(p)) for p in
160 path = [os.path.abspath(os.path.expanduser(p)) for p in
161 os.environ.get('PATH','').split(os.pathsep)]
161 os.environ.get('PATH','').split(os.pathsep)]
162
162
163 syscmdlist = []
163 syscmdlist = []
164 # Now define isexec in a cross platform manner.
164 # Now define isexec in a cross platform manner.
165 if os.name == 'posix':
165 if os.name == 'posix':
166 isexec = lambda fname:os.path.isfile(fname) and \
166 isexec = lambda fname:os.path.isfile(fname) and \
167 os.access(fname,os.X_OK)
167 os.access(fname,os.X_OK)
168 else:
168 else:
169 try:
169 try:
170 winext = os.environ['pathext'].replace(';','|').replace('.','')
170 winext = os.environ['pathext'].replace(';','|').replace('.','')
171 except KeyError:
171 except KeyError:
172 winext = 'exe|com|bat|py'
172 winext = 'exe|com|bat|py'
173 if 'py' not in winext:
173 if 'py' not in winext:
174 winext += '|py'
174 winext += '|py'
175 execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
175 execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
176 isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
176 isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
177 savedir = os.getcwd()
177 savedir = os.getcwd()
178
178
179 # Now walk the paths looking for executables to alias.
179 # Now walk the paths looking for executables to alias.
180 try:
180 try:
181 # write the whole loop for posix/Windows so we don't have an if in
181 # write the whole loop for posix/Windows so we don't have an if in
182 # the innermost part
182 # the innermost part
183 if os.name == 'posix':
183 if os.name == 'posix':
184 for pdir in path:
184 for pdir in path:
185 try:
185 try:
186 os.chdir(pdir)
186 os.chdir(pdir)
187 dirlist = os.listdir(pdir)
187 dirlist = os.listdir(pdir)
188 except OSError:
188 except OSError:
189 continue
189 continue
190 for ff in dirlist:
190 for ff in dirlist:
191 if isexec(ff):
191 if isexec(ff):
192 try:
192 try:
193 # Removes dots from the name since ipython
193 # Removes dots from the name since ipython
194 # will assume names with dots to be python.
194 # will assume names with dots to be python.
195 if not self.shell.alias_manager.is_alias(ff):
195 if not self.shell.alias_manager.is_alias(ff):
196 self.shell.alias_manager.define_alias(
196 self.shell.alias_manager.define_alias(
197 ff.replace('.',''), ff)
197 ff.replace('.',''), ff)
198 except InvalidAliasError:
198 except InvalidAliasError:
199 pass
199 pass
200 else:
200 else:
201 syscmdlist.append(ff)
201 syscmdlist.append(ff)
202 else:
202 else:
203 no_alias = Alias.blacklist
203 no_alias = Alias.blacklist
204 for pdir in path:
204 for pdir in path:
205 try:
205 try:
206 os.chdir(pdir)
206 os.chdir(pdir)
207 dirlist = os.listdir(pdir)
207 dirlist = os.listdir(pdir)
208 except OSError:
208 except OSError:
209 continue
209 continue
210 for ff in dirlist:
210 for ff in dirlist:
211 base, ext = os.path.splitext(ff)
211 base, ext = os.path.splitext(ff)
212 if isexec(ff) and base.lower() not in no_alias:
212 if isexec(ff) and base.lower() not in no_alias:
213 if ext.lower() == '.exe':
213 if ext.lower() == '.exe':
214 ff = base
214 ff = base
215 try:
215 try:
216 # Removes dots from the name since ipython
216 # Removes dots from the name since ipython
217 # will assume names with dots to be python.
217 # will assume names with dots to be python.
218 self.shell.alias_manager.define_alias(
218 self.shell.alias_manager.define_alias(
219 base.lower().replace('.',''), ff)
219 base.lower().replace('.',''), ff)
220 except InvalidAliasError:
220 except InvalidAliasError:
221 pass
221 pass
222 syscmdlist.append(ff)
222 syscmdlist.append(ff)
223 self.shell.db['syscmdlist'] = syscmdlist
223 self.shell.db['syscmdlist'] = syscmdlist
224 finally:
224 finally:
225 os.chdir(savedir)
225 os.chdir(savedir)
226
226
227 @skip_doctest
227 @skip_doctest
228 @line_magic
228 @line_magic
229 def pwd(self, parameter_s=''):
229 def pwd(self, parameter_s=''):
230 """Return the current working directory path.
230 """Return the current working directory path.
231
231
232 Examples
232 Examples
233 --------
233 --------
234 ::
234 ::
235
235
236 In [9]: pwd
236 In [9]: pwd
237 Out[9]: '/home/tsuser/sprint/ipython'
237 Out[9]: '/home/tsuser/sprint/ipython'
238 """
238 """
239 try:
239 try:
240 return os.getcwd()
240 return os.getcwd()
241 except FileNotFoundError:
241 except FileNotFoundError:
242 raise UsageError("CWD no longer exists - please use %cd to change directory.")
242 raise UsageError("CWD no longer exists - please use %cd to change directory.")
243
243
244 @skip_doctest
244 @skip_doctest
245 @line_magic
245 @line_magic
246 def cd(self, parameter_s=''):
246 def cd(self, parameter_s=''):
247 """Change the current working directory.
247 """Change the current working directory.
248
248
249 This command automatically maintains an internal list of directories
249 This command automatically maintains an internal list of directories
250 you visit during your IPython session, in the variable _dh. The
250 you visit during your IPython session, in the variable _dh. The
251 command %dhist shows this history nicely formatted. You can also
251 command %dhist shows this history nicely formatted. You can also
252 do 'cd -<tab>' to see directory history conveniently.
252 do 'cd -<tab>' to see directory history conveniently.
253
253
254 Usage:
254 Usage:
255
255
256 cd 'dir': changes to directory 'dir'.
256 cd 'dir': changes to directory 'dir'.
257
257
258 cd -: changes to the last visited directory.
258 cd -: changes to the last visited directory.
259
259
260 cd -<n>: changes to the n-th directory in the directory history.
260 cd -<n>: changes to the n-th directory in the directory history.
261
261
262 cd --foo: change to directory that matches 'foo' in history
262 cd --foo: change to directory that matches 'foo' in history
263
263
264 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
264 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
265 (note: cd <bookmark_name> is enough if there is no
265 (note: cd <bookmark_name> is enough if there is no
266 directory <bookmark_name>, but a bookmark with the name exists.)
266 directory <bookmark_name>, but a bookmark with the name exists.)
267 'cd -b <tab>' allows you to tab-complete bookmark names.
267 'cd -b <tab>' allows you to tab-complete bookmark names.
268
268
269 Options:
269 Options:
270
270
271 -q: quiet. Do not print the working directory after the cd command is
271 -q: quiet. Do not print the working directory after the cd command is
272 executed. By default IPython's cd command does print this directory,
272 executed. By default IPython's cd command does print this directory,
273 since the default prompts do not display path information.
273 since the default prompts do not display path information.
274
274
275 Note that !cd doesn't work for this purpose because the shell where
275 Note that !cd doesn't work for this purpose because the shell where
276 !command runs is immediately discarded after executing 'command'.
276 !command runs is immediately discarded after executing 'command'.
277
277
278 Examples
278 Examples
279 --------
279 --------
280 ::
280 ::
281
281
282 In [10]: cd parent/child
282 In [10]: cd parent/child
283 /home/tsuser/parent/child
283 /home/tsuser/parent/child
284 """
284 """
285
285
286 try:
286 try:
287 oldcwd = os.getcwd()
287 oldcwd = os.getcwd()
288 except FileNotFoundError:
288 except FileNotFoundError:
289 # Happens if the CWD has been deleted.
289 # Happens if the CWD has been deleted.
290 oldcwd = None
290 oldcwd = None
291
291
292 numcd = re.match(r'(-)(\d+)$',parameter_s)
292 numcd = re.match(r'(-)(\d+)$',parameter_s)
293 # jump in directory history by number
293 # jump in directory history by number
294 if numcd:
294 if numcd:
295 nn = int(numcd.group(2))
295 nn = int(numcd.group(2))
296 try:
296 try:
297 ps = self.shell.user_ns['_dh'][nn]
297 ps = self.shell.user_ns['_dh'][nn]
298 except IndexError:
298 except IndexError:
299 print('The requested directory does not exist in history.')
299 print('The requested directory does not exist in history.')
300 return
300 return
301 else:
301 else:
302 opts = {}
302 opts = {}
303 elif parameter_s.startswith('--'):
303 elif parameter_s.startswith('--'):
304 ps = None
304 ps = None
305 fallback = None
305 fallback = None
306 pat = parameter_s[2:]
306 pat = parameter_s[2:]
307 dh = self.shell.user_ns['_dh']
307 dh = self.shell.user_ns['_dh']
308 # first search only by basename (last component)
308 # first search only by basename (last component)
309 for ent in reversed(dh):
309 for ent in reversed(dh):
310 if pat in os.path.basename(ent) and os.path.isdir(ent):
310 if pat in os.path.basename(ent) and os.path.isdir(ent):
311 ps = ent
311 ps = ent
312 break
312 break
313
313
314 if fallback is None and pat in ent and os.path.isdir(ent):
314 if fallback is None and pat in ent and os.path.isdir(ent):
315 fallback = ent
315 fallback = ent
316
316
317 # if we have no last part match, pick the first full path match
317 # if we have no last part match, pick the first full path match
318 if ps is None:
318 if ps is None:
319 ps = fallback
319 ps = fallback
320
320
321 if ps is None:
321 if ps is None:
322 print("No matching entry in directory history")
322 print("No matching entry in directory history")
323 return
323 return
324 else:
324 else:
325 opts = {}
325 opts = {}
326
326
327
327
328 else:
328 else:
329 opts, ps = self.parse_options(parameter_s, 'qb', mode='string')
329 opts, ps = self.parse_options(parameter_s, 'qb', mode='string')
330 # jump to previous
330 # jump to previous
331 if ps == '-':
331 if ps == '-':
332 try:
332 try:
333 ps = self.shell.user_ns['_dh'][-2]
333 ps = self.shell.user_ns['_dh'][-2]
334 except IndexError:
334 except IndexError:
335 raise UsageError('%cd -: No previous directory to change to.')
335 raise UsageError('%cd -: No previous directory to change to.')
336 # jump to bookmark if needed
336 # jump to bookmark if needed
337 else:
337 else:
338 if not os.path.isdir(ps) or 'b' in opts:
338 if not os.path.isdir(ps) or 'b' in opts:
339 bkms = self.shell.db.get('bookmarks', {})
339 bkms = self.shell.db.get('bookmarks', {})
340
340
341 if ps in bkms:
341 if ps in bkms:
342 target = bkms[ps]
342 target = bkms[ps]
343 print('(bookmark:%s) -> %s' % (ps, target))
343 print('(bookmark:%s) -> %s' % (ps, target))
344 ps = target
344 ps = target
345 else:
345 else:
346 if 'b' in opts:
346 if 'b' in opts:
347 raise UsageError("Bookmark '%s' not found. "
347 raise UsageError("Bookmark '%s' not found. "
348 "Use '%%bookmark -l' to see your bookmarks." % ps)
348 "Use '%%bookmark -l' to see your bookmarks." % ps)
349
349
350 # at this point ps should point to the target dir
350 # at this point ps should point to the target dir
351 if ps:
351 if ps:
352 try:
352 try:
353 os.chdir(os.path.expanduser(ps))
353 os.chdir(os.path.expanduser(ps))
354 if hasattr(self.shell, 'term_title') and self.shell.term_title:
354 if hasattr(self.shell, 'term_title') and self.shell.term_title:
355 set_term_title(self.shell.term_title_format.format(cwd=abbrev_cwd()))
355 set_term_title(self.shell.term_title_format.format(cwd=abbrev_cwd()))
356 except OSError:
356 except OSError:
357 print(sys.exc_info()[1])
357 print(sys.exc_info()[1])
358 else:
358 else:
359 cwd = os.getcwd()
359 cwd = os.getcwd()
360 dhist = self.shell.user_ns['_dh']
360 dhist = self.shell.user_ns['_dh']
361 if oldcwd != cwd:
361 if oldcwd != cwd:
362 dhist.append(cwd)
362 dhist.append(cwd)
363 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
363 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
364
364
365 else:
365 else:
366 os.chdir(self.shell.home_dir)
366 os.chdir(self.shell.home_dir)
367 if hasattr(self.shell, 'term_title') and self.shell.term_title:
367 if hasattr(self.shell, 'term_title') and self.shell.term_title:
368 set_term_title(self.shell.term_title_format.format(cwd="~"))
368 set_term_title(self.shell.term_title_format.format(cwd="~"))
369 cwd = os.getcwd()
369 cwd = os.getcwd()
370 dhist = self.shell.user_ns['_dh']
370 dhist = self.shell.user_ns['_dh']
371
371
372 if oldcwd != cwd:
372 if oldcwd != cwd:
373 dhist.append(cwd)
373 dhist.append(cwd)
374 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
374 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
375 if not 'q' in opts and self.shell.user_ns['_dh']:
375 if not 'q' in opts and self.shell.user_ns['_dh']:
376 print(self.shell.user_ns['_dh'][-1])
376 print(self.shell.user_ns['_dh'][-1])
377
377
378 @line_magic
378 @line_magic
379 def env(self, parameter_s=''):
379 def env(self, parameter_s=''):
380 """Get, set, or list environment variables.
380 """Get, set, or list environment variables.
381
381
382 Usage:\\
382 Usage:\\
383
383
384 %env: lists all environment variables/values
384 %env: lists all environment variables/values
385 %env var: get value for var
385 %env var: get value for var
386 %env var val: set value for var
386 %env var val: set value for var
387 %env var=val: set value for var
387 %env var=val: set value for var
388 %env var=$val: set value for var, using python expansion if possible
388 %env var=$val: set value for var, using python expansion if possible
389 """
389 """
390 if parameter_s.strip():
390 if parameter_s.strip():
391 split = '=' if '=' in parameter_s else ' '
391 split = '=' if '=' in parameter_s else ' '
392 bits = parameter_s.split(split)
392 bits = parameter_s.split(split)
393 if len(bits) == 1:
393 if len(bits) == 1:
394 key = parameter_s.strip()
394 key = parameter_s.strip()
395 if key in os.environ:
395 if key in os.environ:
396 return os.environ[key]
396 return os.environ[key]
397 else:
397 else:
398 err = "Environment does not have key: {0}".format(key)
398 err = "Environment does not have key: {0}".format(key)
399 raise UsageError(err)
399 raise UsageError(err)
400 if len(bits) > 1:
400 if len(bits) > 1:
401 return self.set_env(parameter_s)
401 return self.set_env(parameter_s)
402 return dict(os.environ)
402 return dict(os.environ)
403
403
404 @line_magic
404 @line_magic
405 def set_env(self, parameter_s):
405 def set_env(self, parameter_s):
406 """Set environment variables. Assumptions are that either "val" is a
406 """Set environment variables. Assumptions are that either "val" is a
407 name in the user namespace, or val is something that evaluates to a
407 name in the user namespace, or val is something that evaluates to a
408 string.
408 string.
409
409
410 Usage:\\
410 Usage:\\
411 %set_env var val: set value for var
411 %set_env var val: set value for var
412 %set_env var=val: set value for var
412 %set_env var=val: set value for var
413 %set_env var=$val: set value for var, using python expansion if possible
413 %set_env var=$val: set value for var, using python expansion if possible
414 """
414 """
415 split = '=' if '=' in parameter_s else ' '
415 split = '=' if '=' in parameter_s else ' '
416 bits = parameter_s.split(split, 1)
416 bits = parameter_s.split(split, 1)
417 if not parameter_s.strip() or len(bits)<2:
417 if not parameter_s.strip() or len(bits)<2:
418 raise UsageError("usage is 'set_env var=val'")
418 raise UsageError("usage is 'set_env var=val'")
419 var = bits[0].strip()
419 var = bits[0].strip()
420 val = bits[1].strip()
420 val = bits[1].strip()
421 if re.match(r'.*\s.*', var):
421 if re.match(r'.*\s.*', var):
422 # an environment variable with whitespace is almost certainly
422 # an environment variable with whitespace is almost certainly
423 # not what the user intended. what's more likely is the wrong
423 # not what the user intended. what's more likely is the wrong
424 # split was chosen, ie for "set_env cmd_args A=B", we chose
424 # split was chosen, ie for "set_env cmd_args A=B", we chose
425 # '=' for the split and should have chosen ' '. to get around
425 # '=' for the split and should have chosen ' '. to get around
426 # this, users should just assign directly to os.environ or use
426 # this, users should just assign directly to os.environ or use
427 # standard magic {var} expansion.
427 # standard magic {var} expansion.
428 err = "refusing to set env var with whitespace: '{0}'"
428 err = "refusing to set env var with whitespace: '{0}'"
429 err = err.format(val)
429 err = err.format(val)
430 raise UsageError(err)
430 raise UsageError(err)
431 os.environ[py3compat.cast_bytes_py2(var)] = py3compat.cast_bytes_py2(val)
431 os.environ[var] = val
432 print('env: {0}={1}'.format(var,val))
432 print('env: {0}={1}'.format(var,val))
433
433
434 @line_magic
434 @line_magic
435 def pushd(self, parameter_s=''):
435 def pushd(self, parameter_s=''):
436 """Place the current dir on stack and change directory.
436 """Place the current dir on stack and change directory.
437
437
438 Usage:\\
438 Usage:\\
439 %pushd ['dirname']
439 %pushd ['dirname']
440 """
440 """
441
441
442 dir_s = self.shell.dir_stack
442 dir_s = self.shell.dir_stack
443 tgt = os.path.expanduser(parameter_s)
443 tgt = os.path.expanduser(parameter_s)
444 cwd = os.getcwd().replace(self.shell.home_dir,'~')
444 cwd = os.getcwd().replace(self.shell.home_dir,'~')
445 if tgt:
445 if tgt:
446 self.cd(parameter_s)
446 self.cd(parameter_s)
447 dir_s.insert(0,cwd)
447 dir_s.insert(0,cwd)
448 return self.shell.magic('dirs')
448 return self.shell.magic('dirs')
449
449
450 @line_magic
450 @line_magic
451 def popd(self, parameter_s=''):
451 def popd(self, parameter_s=''):
452 """Change to directory popped off the top of the stack.
452 """Change to directory popped off the top of the stack.
453 """
453 """
454 if not self.shell.dir_stack:
454 if not self.shell.dir_stack:
455 raise UsageError("%popd on empty stack")
455 raise UsageError("%popd on empty stack")
456 top = self.shell.dir_stack.pop(0)
456 top = self.shell.dir_stack.pop(0)
457 self.cd(top)
457 self.cd(top)
458 print("popd ->",top)
458 print("popd ->",top)
459
459
460 @line_magic
460 @line_magic
461 def dirs(self, parameter_s=''):
461 def dirs(self, parameter_s=''):
462 """Return the current directory stack."""
462 """Return the current directory stack."""
463
463
464 return self.shell.dir_stack
464 return self.shell.dir_stack
465
465
466 @line_magic
466 @line_magic
467 def dhist(self, parameter_s=''):
467 def dhist(self, parameter_s=''):
468 """Print your history of visited directories.
468 """Print your history of visited directories.
469
469
470 %dhist -> print full history\\
470 %dhist -> print full history\\
471 %dhist n -> print last n entries only\\
471 %dhist n -> print last n entries only\\
472 %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
472 %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
473
473
474 This history is automatically maintained by the %cd command, and
474 This history is automatically maintained by the %cd command, and
475 always available as the global list variable _dh. You can use %cd -<n>
475 always available as the global list variable _dh. You can use %cd -<n>
476 to go to directory number <n>.
476 to go to directory number <n>.
477
477
478 Note that most of time, you should view directory history by entering
478 Note that most of time, you should view directory history by entering
479 cd -<TAB>.
479 cd -<TAB>.
480
480
481 """
481 """
482
482
483 dh = self.shell.user_ns['_dh']
483 dh = self.shell.user_ns['_dh']
484 if parameter_s:
484 if parameter_s:
485 try:
485 try:
486 args = map(int,parameter_s.split())
486 args = map(int,parameter_s.split())
487 except:
487 except:
488 self.arg_err(self.dhist)
488 self.arg_err(self.dhist)
489 return
489 return
490 if len(args) == 1:
490 if len(args) == 1:
491 ini,fin = max(len(dh)-(args[0]),0),len(dh)
491 ini,fin = max(len(dh)-(args[0]),0),len(dh)
492 elif len(args) == 2:
492 elif len(args) == 2:
493 ini,fin = args
493 ini,fin = args
494 fin = min(fin, len(dh))
494 fin = min(fin, len(dh))
495 else:
495 else:
496 self.arg_err(self.dhist)
496 self.arg_err(self.dhist)
497 return
497 return
498 else:
498 else:
499 ini,fin = 0,len(dh)
499 ini,fin = 0,len(dh)
500 print('Directory history (kept in _dh)')
500 print('Directory history (kept in _dh)')
501 for i in range(ini, fin):
501 for i in range(ini, fin):
502 print("%d: %s" % (i, dh[i]))
502 print("%d: %s" % (i, dh[i]))
503
503
504 @skip_doctest
504 @skip_doctest
505 @line_magic
505 @line_magic
506 def sc(self, parameter_s=''):
506 def sc(self, parameter_s=''):
507 """Shell capture - run shell command and capture output (DEPRECATED use !).
507 """Shell capture - run shell command and capture output (DEPRECATED use !).
508
508
509 DEPRECATED. Suboptimal, retained for backwards compatibility.
509 DEPRECATED. Suboptimal, retained for backwards compatibility.
510
510
511 You should use the form 'var = !command' instead. Example:
511 You should use the form 'var = !command' instead. Example:
512
512
513 "%sc -l myfiles = ls ~" should now be written as
513 "%sc -l myfiles = ls ~" should now be written as
514
514
515 "myfiles = !ls ~"
515 "myfiles = !ls ~"
516
516
517 myfiles.s, myfiles.l and myfiles.n still apply as documented
517 myfiles.s, myfiles.l and myfiles.n still apply as documented
518 below.
518 below.
519
519
520 --
520 --
521 %sc [options] varname=command
521 %sc [options] varname=command
522
522
523 IPython will run the given command using commands.getoutput(), and
523 IPython will run the given command using commands.getoutput(), and
524 will then update the user's interactive namespace with a variable
524 will then update the user's interactive namespace with a variable
525 called varname, containing the value of the call. Your command can
525 called varname, containing the value of the call. Your command can
526 contain shell wildcards, pipes, etc.
526 contain shell wildcards, pipes, etc.
527
527
528 The '=' sign in the syntax is mandatory, and the variable name you
528 The '=' sign in the syntax is mandatory, and the variable name you
529 supply must follow Python's standard conventions for valid names.
529 supply must follow Python's standard conventions for valid names.
530
530
531 (A special format without variable name exists for internal use)
531 (A special format without variable name exists for internal use)
532
532
533 Options:
533 Options:
534
534
535 -l: list output. Split the output on newlines into a list before
535 -l: list output. Split the output on newlines into a list before
536 assigning it to the given variable. By default the output is stored
536 assigning it to the given variable. By default the output is stored
537 as a single string.
537 as a single string.
538
538
539 -v: verbose. Print the contents of the variable.
539 -v: verbose. Print the contents of the variable.
540
540
541 In most cases you should not need to split as a list, because the
541 In most cases you should not need to split as a list, because the
542 returned value is a special type of string which can automatically
542 returned value is a special type of string which can automatically
543 provide its contents either as a list (split on newlines) or as a
543 provide its contents either as a list (split on newlines) or as a
544 space-separated string. These are convenient, respectively, either
544 space-separated string. These are convenient, respectively, either
545 for sequential processing or to be passed to a shell command.
545 for sequential processing or to be passed to a shell command.
546
546
547 For example::
547 For example::
548
548
549 # Capture into variable a
549 # Capture into variable a
550 In [1]: sc a=ls *py
550 In [1]: sc a=ls *py
551
551
552 # a is a string with embedded newlines
552 # a is a string with embedded newlines
553 In [2]: a
553 In [2]: a
554 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
554 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
555
555
556 # which can be seen as a list:
556 # which can be seen as a list:
557 In [3]: a.l
557 In [3]: a.l
558 Out[3]: ['setup.py', 'win32_manual_post_install.py']
558 Out[3]: ['setup.py', 'win32_manual_post_install.py']
559
559
560 # or as a whitespace-separated string:
560 # or as a whitespace-separated string:
561 In [4]: a.s
561 In [4]: a.s
562 Out[4]: 'setup.py win32_manual_post_install.py'
562 Out[4]: 'setup.py win32_manual_post_install.py'
563
563
564 # a.s is useful to pass as a single command line:
564 # a.s is useful to pass as a single command line:
565 In [5]: !wc -l $a.s
565 In [5]: !wc -l $a.s
566 146 setup.py
566 146 setup.py
567 130 win32_manual_post_install.py
567 130 win32_manual_post_install.py
568 276 total
568 276 total
569
569
570 # while the list form is useful to loop over:
570 # while the list form is useful to loop over:
571 In [6]: for f in a.l:
571 In [6]: for f in a.l:
572 ...: !wc -l $f
572 ...: !wc -l $f
573 ...:
573 ...:
574 146 setup.py
574 146 setup.py
575 130 win32_manual_post_install.py
575 130 win32_manual_post_install.py
576
576
577 Similarly, the lists returned by the -l option are also special, in
577 Similarly, the lists returned by the -l option are also special, in
578 the sense that you can equally invoke the .s attribute on them to
578 the sense that you can equally invoke the .s attribute on them to
579 automatically get a whitespace-separated string from their contents::
579 automatically get a whitespace-separated string from their contents::
580
580
581 In [7]: sc -l b=ls *py
581 In [7]: sc -l b=ls *py
582
582
583 In [8]: b
583 In [8]: b
584 Out[8]: ['setup.py', 'win32_manual_post_install.py']
584 Out[8]: ['setup.py', 'win32_manual_post_install.py']
585
585
586 In [9]: b.s
586 In [9]: b.s
587 Out[9]: 'setup.py win32_manual_post_install.py'
587 Out[9]: 'setup.py win32_manual_post_install.py'
588
588
589 In summary, both the lists and strings used for output capture have
589 In summary, both the lists and strings used for output capture have
590 the following special attributes::
590 the following special attributes::
591
591
592 .l (or .list) : value as list.
592 .l (or .list) : value as list.
593 .n (or .nlstr): value as newline-separated string.
593 .n (or .nlstr): value as newline-separated string.
594 .s (or .spstr): value as space-separated string.
594 .s (or .spstr): value as space-separated string.
595 """
595 """
596
596
597 opts,args = self.parse_options(parameter_s, 'lv')
597 opts,args = self.parse_options(parameter_s, 'lv')
598 # Try to get a variable name and command to run
598 # Try to get a variable name and command to run
599 try:
599 try:
600 # the variable name must be obtained from the parse_options
600 # the variable name must be obtained from the parse_options
601 # output, which uses shlex.split to strip options out.
601 # output, which uses shlex.split to strip options out.
602 var,_ = args.split('=', 1)
602 var,_ = args.split('=', 1)
603 var = var.strip()
603 var = var.strip()
604 # But the command has to be extracted from the original input
604 # But the command has to be extracted from the original input
605 # parameter_s, not on what parse_options returns, to avoid the
605 # parameter_s, not on what parse_options returns, to avoid the
606 # quote stripping which shlex.split performs on it.
606 # quote stripping which shlex.split performs on it.
607 _,cmd = parameter_s.split('=', 1)
607 _,cmd = parameter_s.split('=', 1)
608 except ValueError:
608 except ValueError:
609 var,cmd = '',''
609 var,cmd = '',''
610 # If all looks ok, proceed
610 # If all looks ok, proceed
611 split = 'l' in opts
611 split = 'l' in opts
612 out = self.shell.getoutput(cmd, split=split)
612 out = self.shell.getoutput(cmd, split=split)
613 if 'v' in opts:
613 if 'v' in opts:
614 print('%s ==\n%s' % (var, pformat(out)))
614 print('%s ==\n%s' % (var, pformat(out)))
615 if var:
615 if var:
616 self.shell.user_ns.update({var:out})
616 self.shell.user_ns.update({var:out})
617 else:
617 else:
618 return out
618 return out
619
619
620 @line_cell_magic
620 @line_cell_magic
621 def sx(self, line='', cell=None):
621 def sx(self, line='', cell=None):
622 """Shell execute - run shell command and capture output (!! is short-hand).
622 """Shell execute - run shell command and capture output (!! is short-hand).
623
623
624 %sx command
624 %sx command
625
625
626 IPython will run the given command using commands.getoutput(), and
626 IPython will run the given command using commands.getoutput(), and
627 return the result formatted as a list (split on '\\n'). Since the
627 return the result formatted as a list (split on '\\n'). Since the
628 output is _returned_, it will be stored in ipython's regular output
628 output is _returned_, it will be stored in ipython's regular output
629 cache Out[N] and in the '_N' automatic variables.
629 cache Out[N] and in the '_N' automatic variables.
630
630
631 Notes:
631 Notes:
632
632
633 1) If an input line begins with '!!', then %sx is automatically
633 1) If an input line begins with '!!', then %sx is automatically
634 invoked. That is, while::
634 invoked. That is, while::
635
635
636 !ls
636 !ls
637
637
638 causes ipython to simply issue system('ls'), typing::
638 causes ipython to simply issue system('ls'), typing::
639
639
640 !!ls
640 !!ls
641
641
642 is a shorthand equivalent to::
642 is a shorthand equivalent to::
643
643
644 %sx ls
644 %sx ls
645
645
646 2) %sx differs from %sc in that %sx automatically splits into a list,
646 2) %sx differs from %sc in that %sx automatically splits into a list,
647 like '%sc -l'. The reason for this is to make it as easy as possible
647 like '%sc -l'. The reason for this is to make it as easy as possible
648 to process line-oriented shell output via further python commands.
648 to process line-oriented shell output via further python commands.
649 %sc is meant to provide much finer control, but requires more
649 %sc is meant to provide much finer control, but requires more
650 typing.
650 typing.
651
651
652 3) Just like %sc -l, this is a list with special attributes:
652 3) Just like %sc -l, this is a list with special attributes:
653 ::
653 ::
654
654
655 .l (or .list) : value as list.
655 .l (or .list) : value as list.
656 .n (or .nlstr): value as newline-separated string.
656 .n (or .nlstr): value as newline-separated string.
657 .s (or .spstr): value as whitespace-separated string.
657 .s (or .spstr): value as whitespace-separated string.
658
658
659 This is very useful when trying to use such lists as arguments to
659 This is very useful when trying to use such lists as arguments to
660 system commands."""
660 system commands."""
661
661
662 if cell is None:
662 if cell is None:
663 # line magic
663 # line magic
664 return self.shell.getoutput(line)
664 return self.shell.getoutput(line)
665 else:
665 else:
666 opts,args = self.parse_options(line, '', 'out=')
666 opts,args = self.parse_options(line, '', 'out=')
667 output = self.shell.getoutput(cell)
667 output = self.shell.getoutput(cell)
668 out_name = opts.get('out', opts.get('o'))
668 out_name = opts.get('out', opts.get('o'))
669 if out_name:
669 if out_name:
670 self.shell.user_ns[out_name] = output
670 self.shell.user_ns[out_name] = output
671 else:
671 else:
672 return output
672 return output
673
673
674 system = line_cell_magic('system')(sx)
674 system = line_cell_magic('system')(sx)
675 bang = cell_magic('!')(sx)
675 bang = cell_magic('!')(sx)
676
676
677 @line_magic
677 @line_magic
678 def bookmark(self, parameter_s=''):
678 def bookmark(self, parameter_s=''):
679 """Manage IPython's bookmark system.
679 """Manage IPython's bookmark system.
680
680
681 %bookmark <name> - set bookmark to current dir
681 %bookmark <name> - set bookmark to current dir
682 %bookmark <name> <dir> - set bookmark to <dir>
682 %bookmark <name> <dir> - set bookmark to <dir>
683 %bookmark -l - list all bookmarks
683 %bookmark -l - list all bookmarks
684 %bookmark -d <name> - remove bookmark
684 %bookmark -d <name> - remove bookmark
685 %bookmark -r - remove all bookmarks
685 %bookmark -r - remove all bookmarks
686
686
687 You can later on access a bookmarked folder with::
687 You can later on access a bookmarked folder with::
688
688
689 %cd -b <name>
689 %cd -b <name>
690
690
691 or simply '%cd <name>' if there is no directory called <name> AND
691 or simply '%cd <name>' if there is no directory called <name> AND
692 there is such a bookmark defined.
692 there is such a bookmark defined.
693
693
694 Your bookmarks persist through IPython sessions, but they are
694 Your bookmarks persist through IPython sessions, but they are
695 associated with each profile."""
695 associated with each profile."""
696
696
697 opts,args = self.parse_options(parameter_s,'drl',mode='list')
697 opts,args = self.parse_options(parameter_s,'drl',mode='list')
698 if len(args) > 2:
698 if len(args) > 2:
699 raise UsageError("%bookmark: too many arguments")
699 raise UsageError("%bookmark: too many arguments")
700
700
701 bkms = self.shell.db.get('bookmarks',{})
701 bkms = self.shell.db.get('bookmarks',{})
702
702
703 if 'd' in opts:
703 if 'd' in opts:
704 try:
704 try:
705 todel = args[0]
705 todel = args[0]
706 except IndexError:
706 except IndexError:
707 raise UsageError(
707 raise UsageError(
708 "%bookmark -d: must provide a bookmark to delete")
708 "%bookmark -d: must provide a bookmark to delete")
709 else:
709 else:
710 try:
710 try:
711 del bkms[todel]
711 del bkms[todel]
712 except KeyError:
712 except KeyError:
713 raise UsageError(
713 raise UsageError(
714 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
714 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
715
715
716 elif 'r' in opts:
716 elif 'r' in opts:
717 bkms = {}
717 bkms = {}
718 elif 'l' in opts:
718 elif 'l' in opts:
719 bks = sorted(bkms)
719 bks = sorted(bkms)
720 if bks:
720 if bks:
721 size = max(map(len, bks))
721 size = max(map(len, bks))
722 else:
722 else:
723 size = 0
723 size = 0
724 fmt = '%-'+str(size)+'s -> %s'
724 fmt = '%-'+str(size)+'s -> %s'
725 print('Current bookmarks:')
725 print('Current bookmarks:')
726 for bk in bks:
726 for bk in bks:
727 print(fmt % (bk, bkms[bk]))
727 print(fmt % (bk, bkms[bk]))
728 else:
728 else:
729 if not args:
729 if not args:
730 raise UsageError("%bookmark: You must specify the bookmark name")
730 raise UsageError("%bookmark: You must specify the bookmark name")
731 elif len(args)==1:
731 elif len(args)==1:
732 bkms[args[0]] = os.getcwd()
732 bkms[args[0]] = os.getcwd()
733 elif len(args)==2:
733 elif len(args)==2:
734 bkms[args[0]] = args[1]
734 bkms[args[0]] = args[1]
735 self.shell.db['bookmarks'] = bkms
735 self.shell.db['bookmarks'] = bkms
736
736
737 @line_magic
737 @line_magic
738 def pycat(self, parameter_s=''):
738 def pycat(self, parameter_s=''):
739 """Show a syntax-highlighted file through a pager.
739 """Show a syntax-highlighted file through a pager.
740
740
741 This magic is similar to the cat utility, but it will assume the file
741 This magic is similar to the cat utility, but it will assume the file
742 to be Python source and will show it with syntax highlighting.
742 to be Python source and will show it with syntax highlighting.
743
743
744 This magic command can either take a local filename, an url,
744 This magic command can either take a local filename, an url,
745 an history range (see %history) or a macro as argument ::
745 an history range (see %history) or a macro as argument ::
746
746
747 %pycat myscript.py
747 %pycat myscript.py
748 %pycat 7-27
748 %pycat 7-27
749 %pycat myMacro
749 %pycat myMacro
750 %pycat http://www.example.com/myscript.py
750 %pycat http://www.example.com/myscript.py
751 """
751 """
752 if not parameter_s:
752 if not parameter_s:
753 raise UsageError('Missing filename, URL, input history range, '
753 raise UsageError('Missing filename, URL, input history range, '
754 'or macro.')
754 'or macro.')
755
755
756 try :
756 try :
757 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
757 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
758 except (ValueError, IOError):
758 except (ValueError, IOError):
759 print("Error: no such file, variable, URL, history range or macro")
759 print("Error: no such file, variable, URL, history range or macro")
760 return
760 return
761
761
762 page.page(self.shell.pycolorize(source_to_unicode(cont)))
762 page.page(self.shell.pycolorize(source_to_unicode(cont)))
763
763
764 @magic_arguments.magic_arguments()
764 @magic_arguments.magic_arguments()
765 @magic_arguments.argument(
765 @magic_arguments.argument(
766 '-a', '--append', action='store_true', default=False,
766 '-a', '--append', action='store_true', default=False,
767 help='Append contents of the cell to an existing file. '
767 help='Append contents of the cell to an existing file. '
768 'The file will be created if it does not exist.'
768 'The file will be created if it does not exist.'
769 )
769 )
770 @magic_arguments.argument(
770 @magic_arguments.argument(
771 'filename', type=str,
771 'filename', type=str,
772 help='file to write'
772 help='file to write'
773 )
773 )
774 @cell_magic
774 @cell_magic
775 def writefile(self, line, cell):
775 def writefile(self, line, cell):
776 """Write the contents of the cell to a file.
776 """Write the contents of the cell to a file.
777
777
778 The file will be overwritten unless the -a (--append) flag is specified.
778 The file will be overwritten unless the -a (--append) flag is specified.
779 """
779 """
780 args = magic_arguments.parse_argstring(self.writefile, line)
780 args = magic_arguments.parse_argstring(self.writefile, line)
781 filename = os.path.expanduser(args.filename)
781 filename = os.path.expanduser(args.filename)
782
782
783 if os.path.exists(filename):
783 if os.path.exists(filename):
784 if args.append:
784 if args.append:
785 print("Appending to %s" % filename)
785 print("Appending to %s" % filename)
786 else:
786 else:
787 print("Overwriting %s" % filename)
787 print("Overwriting %s" % filename)
788 else:
788 else:
789 print("Writing %s" % filename)
789 print("Writing %s" % filename)
790
790
791 mode = 'a' if args.append else 'w'
791 mode = 'a' if args.append else 'w'
792 with io.open(filename, mode, encoding='utf-8') as f:
792 with io.open(filename, mode, encoding='utf-8') as f:
793 f.write(cell)
793 f.write(cell)
@@ -1,385 +1,384 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Paging capabilities for IPython.core
3 Paging capabilities for IPython.core
4
4
5 Notes
5 Notes
6 -----
6 -----
7
7
8 For now this uses IPython hooks, so it can't be in IPython.utils. If we can get
8 For now this uses IPython hooks, so it can't be in IPython.utils. If we can get
9 rid of that dependency, we could move it there.
9 rid of that dependency, we could move it there.
10 -----
10 -----
11 """
11 """
12
12
13 # Copyright (c) IPython Development Team.
13 # Copyright (c) IPython Development Team.
14 # Distributed under the terms of the Modified BSD License.
14 # Distributed under the terms of the Modified BSD License.
15
15
16
16
17 import os
17 import os
18 import re
18 import re
19 import sys
19 import sys
20 import tempfile
20 import tempfile
21
21
22 from io import UnsupportedOperation
22 from io import UnsupportedOperation
23
23
24 from IPython import get_ipython
24 from IPython import get_ipython
25 from IPython.core.display import display
25 from IPython.core.display import display
26 from IPython.core.error import TryNext
26 from IPython.core.error import TryNext
27 from IPython.utils.data import chop
27 from IPython.utils.data import chop
28 from IPython.utils.process import system
28 from IPython.utils.process import system
29 from IPython.utils.terminal import get_terminal_size
29 from IPython.utils.terminal import get_terminal_size
30 from IPython.utils import py3compat
30 from IPython.utils import py3compat
31
31
32
32
33 def display_page(strng, start=0, screen_lines=25):
33 def display_page(strng, start=0, screen_lines=25):
34 """Just display, no paging. screen_lines is ignored."""
34 """Just display, no paging. screen_lines is ignored."""
35 if isinstance(strng, dict):
35 if isinstance(strng, dict):
36 data = strng
36 data = strng
37 else:
37 else:
38 if start:
38 if start:
39 strng = u'\n'.join(strng.splitlines()[start:])
39 strng = u'\n'.join(strng.splitlines()[start:])
40 data = { 'text/plain': strng }
40 data = { 'text/plain': strng }
41 display(data, raw=True)
41 display(data, raw=True)
42
42
43
43
44 def as_hook(page_func):
44 def as_hook(page_func):
45 """Wrap a pager func to strip the `self` arg
45 """Wrap a pager func to strip the `self` arg
46
46
47 so it can be called as a hook.
47 so it can be called as a hook.
48 """
48 """
49 return lambda self, *args, **kwargs: page_func(*args, **kwargs)
49 return lambda self, *args, **kwargs: page_func(*args, **kwargs)
50
50
51
51
52 esc_re = re.compile(r"(\x1b[^m]+m)")
52 esc_re = re.compile(r"(\x1b[^m]+m)")
53
53
54 def page_dumb(strng, start=0, screen_lines=25):
54 def page_dumb(strng, start=0, screen_lines=25):
55 """Very dumb 'pager' in Python, for when nothing else works.
55 """Very dumb 'pager' in Python, for when nothing else works.
56
56
57 Only moves forward, same interface as page(), except for pager_cmd and
57 Only moves forward, same interface as page(), except for pager_cmd and
58 mode.
58 mode.
59 """
59 """
60 if isinstance(strng, dict):
60 if isinstance(strng, dict):
61 strng = strng.get('text/plain', '')
61 strng = strng.get('text/plain', '')
62 out_ln = strng.splitlines()[start:]
62 out_ln = strng.splitlines()[start:]
63 screens = chop(out_ln,screen_lines-1)
63 screens = chop(out_ln,screen_lines-1)
64 if len(screens) == 1:
64 if len(screens) == 1:
65 print(os.linesep.join(screens[0]))
65 print(os.linesep.join(screens[0]))
66 else:
66 else:
67 last_escape = ""
67 last_escape = ""
68 for scr in screens[0:-1]:
68 for scr in screens[0:-1]:
69 hunk = os.linesep.join(scr)
69 hunk = os.linesep.join(scr)
70 print(last_escape + hunk)
70 print(last_escape + hunk)
71 if not page_more():
71 if not page_more():
72 return
72 return
73 esc_list = esc_re.findall(hunk)
73 esc_list = esc_re.findall(hunk)
74 if len(esc_list) > 0:
74 if len(esc_list) > 0:
75 last_escape = esc_list[-1]
75 last_escape = esc_list[-1]
76 print(last_escape + os.linesep.join(screens[-1]))
76 print(last_escape + os.linesep.join(screens[-1]))
77
77
78 def _detect_screen_size(screen_lines_def):
78 def _detect_screen_size(screen_lines_def):
79 """Attempt to work out the number of lines on the screen.
79 """Attempt to work out the number of lines on the screen.
80
80
81 This is called by page(). It can raise an error (e.g. when run in the
81 This is called by page(). It can raise an error (e.g. when run in the
82 test suite), so it's separated out so it can easily be called in a try block.
82 test suite), so it's separated out so it can easily be called in a try block.
83 """
83 """
84 TERM = os.environ.get('TERM',None)
84 TERM = os.environ.get('TERM',None)
85 if not((TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5'):
85 if not((TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5'):
86 # curses causes problems on many terminals other than xterm, and
86 # curses causes problems on many terminals other than xterm, and
87 # some termios calls lock up on Sun OS5.
87 # some termios calls lock up on Sun OS5.
88 return screen_lines_def
88 return screen_lines_def
89
89
90 try:
90 try:
91 import termios
91 import termios
92 import curses
92 import curses
93 except ImportError:
93 except ImportError:
94 return screen_lines_def
94 return screen_lines_def
95
95
96 # There is a bug in curses, where *sometimes* it fails to properly
96 # There is a bug in curses, where *sometimes* it fails to properly
97 # initialize, and then after the endwin() call is made, the
97 # initialize, and then after the endwin() call is made, the
98 # terminal is left in an unusable state. Rather than trying to
98 # terminal is left in an unusable state. Rather than trying to
99 # check everytime for this (by requesting and comparing termios
99 # check everytime for this (by requesting and comparing termios
100 # flags each time), we just save the initial terminal state and
100 # flags each time), we just save the initial terminal state and
101 # unconditionally reset it every time. It's cheaper than making
101 # unconditionally reset it every time. It's cheaper than making
102 # the checks.
102 # the checks.
103 try:
103 try:
104 term_flags = termios.tcgetattr(sys.stdout)
104 term_flags = termios.tcgetattr(sys.stdout)
105 except termios.error as err:
105 except termios.error as err:
106 # can fail on Linux 2.6, pager_page will catch the TypeError
106 # can fail on Linux 2.6, pager_page will catch the TypeError
107 raise TypeError('termios error: {0}'.format(err))
107 raise TypeError('termios error: {0}'.format(err))
108
108
109 # Curses modifies the stdout buffer size by default, which messes
109 # Curses modifies the stdout buffer size by default, which messes
110 # up Python's normal stdout buffering. This would manifest itself
110 # up Python's normal stdout buffering. This would manifest itself
111 # to IPython users as delayed printing on stdout after having used
111 # to IPython users as delayed printing on stdout after having used
112 # the pager.
112 # the pager.
113 #
113 #
114 # We can prevent this by manually setting the NCURSES_NO_SETBUF
114 # We can prevent this by manually setting the NCURSES_NO_SETBUF
115 # environment variable. For more details, see:
115 # environment variable. For more details, see:
116 # http://bugs.python.org/issue10144
116 # http://bugs.python.org/issue10144
117 NCURSES_NO_SETBUF = os.environ.get('NCURSES_NO_SETBUF', None)
117 NCURSES_NO_SETBUF = os.environ.get('NCURSES_NO_SETBUF', None)
118 os.environ['NCURSES_NO_SETBUF'] = ''
118 os.environ['NCURSES_NO_SETBUF'] = ''
119
119
120 # Proceed with curses initialization
120 # Proceed with curses initialization
121 try:
121 try:
122 scr = curses.initscr()
122 scr = curses.initscr()
123 except AttributeError:
123 except AttributeError:
124 # Curses on Solaris may not be complete, so we can't use it there
124 # Curses on Solaris may not be complete, so we can't use it there
125 return screen_lines_def
125 return screen_lines_def
126
126
127 screen_lines_real,screen_cols = scr.getmaxyx()
127 screen_lines_real,screen_cols = scr.getmaxyx()
128 curses.endwin()
128 curses.endwin()
129
129
130 # Restore environment
130 # Restore environment
131 if NCURSES_NO_SETBUF is None:
131 if NCURSES_NO_SETBUF is None:
132 del os.environ['NCURSES_NO_SETBUF']
132 del os.environ['NCURSES_NO_SETBUF']
133 else:
133 else:
134 os.environ['NCURSES_NO_SETBUF'] = NCURSES_NO_SETBUF
134 os.environ['NCURSES_NO_SETBUF'] = NCURSES_NO_SETBUF
135
135
136 # Restore terminal state in case endwin() didn't.
136 # Restore terminal state in case endwin() didn't.
137 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
137 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
138 # Now we have what we needed: the screen size in rows/columns
138 # Now we have what we needed: the screen size in rows/columns
139 return screen_lines_real
139 return screen_lines_real
140 #print '***Screen size:',screen_lines_real,'lines x',\
140 #print '***Screen size:',screen_lines_real,'lines x',\
141 #screen_cols,'columns.' # dbg
141 #screen_cols,'columns.' # dbg
142
142
143 def pager_page(strng, start=0, screen_lines=0, pager_cmd=None):
143 def pager_page(strng, start=0, screen_lines=0, pager_cmd=None):
144 """Display a string, piping through a pager after a certain length.
144 """Display a string, piping through a pager after a certain length.
145
145
146 strng can be a mime-bundle dict, supplying multiple representations,
146 strng can be a mime-bundle dict, supplying multiple representations,
147 keyed by mime-type.
147 keyed by mime-type.
148
148
149 The screen_lines parameter specifies the number of *usable* lines of your
149 The screen_lines parameter specifies the number of *usable* lines of your
150 terminal screen (total lines minus lines you need to reserve to show other
150 terminal screen (total lines minus lines you need to reserve to show other
151 information).
151 information).
152
152
153 If you set screen_lines to a number <=0, page() will try to auto-determine
153 If you set screen_lines to a number <=0, page() will try to auto-determine
154 your screen size and will only use up to (screen_size+screen_lines) for
154 your screen size and will only use up to (screen_size+screen_lines) for
155 printing, paging after that. That is, if you want auto-detection but need
155 printing, paging after that. That is, if you want auto-detection but need
156 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
156 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
157 auto-detection without any lines reserved simply use screen_lines = 0.
157 auto-detection without any lines reserved simply use screen_lines = 0.
158
158
159 If a string won't fit in the allowed lines, it is sent through the
159 If a string won't fit in the allowed lines, it is sent through the
160 specified pager command. If none given, look for PAGER in the environment,
160 specified pager command. If none given, look for PAGER in the environment,
161 and ultimately default to less.
161 and ultimately default to less.
162
162
163 If no system pager works, the string is sent through a 'dumb pager'
163 If no system pager works, the string is sent through a 'dumb pager'
164 written in python, very simplistic.
164 written in python, very simplistic.
165 """
165 """
166
166
167 # for compatibility with mime-bundle form:
167 # for compatibility with mime-bundle form:
168 if isinstance(strng, dict):
168 if isinstance(strng, dict):
169 strng = strng['text/plain']
169 strng = strng['text/plain']
170
170
171 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
171 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
172 TERM = os.environ.get('TERM','dumb')
172 TERM = os.environ.get('TERM','dumb')
173 if TERM in ['dumb','emacs'] and os.name != 'nt':
173 if TERM in ['dumb','emacs'] and os.name != 'nt':
174 print(strng)
174 print(strng)
175 return
175 return
176 # chop off the topmost part of the string we don't want to see
176 # chop off the topmost part of the string we don't want to see
177 str_lines = strng.splitlines()[start:]
177 str_lines = strng.splitlines()[start:]
178 str_toprint = os.linesep.join(str_lines)
178 str_toprint = os.linesep.join(str_lines)
179 num_newlines = len(str_lines)
179 num_newlines = len(str_lines)
180 len_str = len(str_toprint)
180 len_str = len(str_toprint)
181
181
182 # Dumb heuristics to guesstimate number of on-screen lines the string
182 # Dumb heuristics to guesstimate number of on-screen lines the string
183 # takes. Very basic, but good enough for docstrings in reasonable
183 # takes. Very basic, but good enough for docstrings in reasonable
184 # terminals. If someone later feels like refining it, it's not hard.
184 # terminals. If someone later feels like refining it, it's not hard.
185 numlines = max(num_newlines,int(len_str/80)+1)
185 numlines = max(num_newlines,int(len_str/80)+1)
186
186
187 screen_lines_def = get_terminal_size()[1]
187 screen_lines_def = get_terminal_size()[1]
188
188
189 # auto-determine screen size
189 # auto-determine screen size
190 if screen_lines <= 0:
190 if screen_lines <= 0:
191 try:
191 try:
192 screen_lines += _detect_screen_size(screen_lines_def)
192 screen_lines += _detect_screen_size(screen_lines_def)
193 except (TypeError, UnsupportedOperation):
193 except (TypeError, UnsupportedOperation):
194 print(str_toprint)
194 print(str_toprint)
195 return
195 return
196
196
197 #print 'numlines',numlines,'screenlines',screen_lines # dbg
197 #print 'numlines',numlines,'screenlines',screen_lines # dbg
198 if numlines <= screen_lines :
198 if numlines <= screen_lines :
199 #print '*** normal print' # dbg
199 #print '*** normal print' # dbg
200 print(str_toprint)
200 print(str_toprint)
201 else:
201 else:
202 # Try to open pager and default to internal one if that fails.
202 # Try to open pager and default to internal one if that fails.
203 # All failure modes are tagged as 'retval=1', to match the return
203 # All failure modes are tagged as 'retval=1', to match the return
204 # value of a failed system command. If any intermediate attempt
204 # value of a failed system command. If any intermediate attempt
205 # sets retval to 1, at the end we resort to our own page_dumb() pager.
205 # sets retval to 1, at the end we resort to our own page_dumb() pager.
206 pager_cmd = get_pager_cmd(pager_cmd)
206 pager_cmd = get_pager_cmd(pager_cmd)
207 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
207 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
208 if os.name == 'nt':
208 if os.name == 'nt':
209 if pager_cmd.startswith('type'):
209 if pager_cmd.startswith('type'):
210 # The default WinXP 'type' command is failing on complex strings.
210 # The default WinXP 'type' command is failing on complex strings.
211 retval = 1
211 retval = 1
212 else:
212 else:
213 fd, tmpname = tempfile.mkstemp('.txt')
213 fd, tmpname = tempfile.mkstemp('.txt')
214 try:
214 try:
215 os.close(fd)
215 os.close(fd)
216 with open(tmpname, 'wt') as tmpfile:
216 with open(tmpname, 'wt') as tmpfile:
217 tmpfile.write(strng)
217 tmpfile.write(strng)
218 cmd = "%s < %s" % (pager_cmd, tmpname)
218 cmd = "%s < %s" % (pager_cmd, tmpname)
219 # tmpfile needs to be closed for windows
219 # tmpfile needs to be closed for windows
220 if os.system(cmd):
220 if os.system(cmd):
221 retval = 1
221 retval = 1
222 else:
222 else:
223 retval = None
223 retval = None
224 finally:
224 finally:
225 os.remove(tmpname)
225 os.remove(tmpname)
226 else:
226 else:
227 try:
227 try:
228 retval = None
228 retval = None
229 # if I use popen4, things hang. No idea why.
229 # if I use popen4, things hang. No idea why.
230 #pager,shell_out = os.popen4(pager_cmd)
230 #pager,shell_out = os.popen4(pager_cmd)
231 pager = os.popen(pager_cmd, 'w')
231 pager = os.popen(pager_cmd, 'w')
232 try:
232 try:
233 pager_encoding = pager.encoding or sys.stdout.encoding
233 pager_encoding = pager.encoding or sys.stdout.encoding
234 pager.write(py3compat.cast_bytes_py2(
234 pager.write(strng)
235 strng, encoding=pager_encoding))
236 finally:
235 finally:
237 retval = pager.close()
236 retval = pager.close()
238 except IOError as msg: # broken pipe when user quits
237 except IOError as msg: # broken pipe when user quits
239 if msg.args == (32, 'Broken pipe'):
238 if msg.args == (32, 'Broken pipe'):
240 retval = None
239 retval = None
241 else:
240 else:
242 retval = 1
241 retval = 1
243 except OSError:
242 except OSError:
244 # Other strange problems, sometimes seen in Win2k/cygwin
243 # Other strange problems, sometimes seen in Win2k/cygwin
245 retval = 1
244 retval = 1
246 if retval is not None:
245 if retval is not None:
247 page_dumb(strng,screen_lines=screen_lines)
246 page_dumb(strng,screen_lines=screen_lines)
248
247
249
248
250 def page(data, start=0, screen_lines=0, pager_cmd=None):
249 def page(data, start=0, screen_lines=0, pager_cmd=None):
251 """Display content in a pager, piping through a pager after a certain length.
250 """Display content in a pager, piping through a pager after a certain length.
252
251
253 data can be a mime-bundle dict, supplying multiple representations,
252 data can be a mime-bundle dict, supplying multiple representations,
254 keyed by mime-type, or text.
253 keyed by mime-type, or text.
255
254
256 Pager is dispatched via the `show_in_pager` IPython hook.
255 Pager is dispatched via the `show_in_pager` IPython hook.
257 If no hook is registered, `pager_page` will be used.
256 If no hook is registered, `pager_page` will be used.
258 """
257 """
259 # Some routines may auto-compute start offsets incorrectly and pass a
258 # Some routines may auto-compute start offsets incorrectly and pass a
260 # negative value. Offset to 0 for robustness.
259 # negative value. Offset to 0 for robustness.
261 start = max(0, start)
260 start = max(0, start)
262
261
263 # first, try the hook
262 # first, try the hook
264 ip = get_ipython()
263 ip = get_ipython()
265 if ip:
264 if ip:
266 try:
265 try:
267 ip.hooks.show_in_pager(data, start=start, screen_lines=screen_lines)
266 ip.hooks.show_in_pager(data, start=start, screen_lines=screen_lines)
268 return
267 return
269 except TryNext:
268 except TryNext:
270 pass
269 pass
271
270
272 # fallback on default pager
271 # fallback on default pager
273 return pager_page(data, start, screen_lines, pager_cmd)
272 return pager_page(data, start, screen_lines, pager_cmd)
274
273
275
274
276 def page_file(fname, start=0, pager_cmd=None):
275 def page_file(fname, start=0, pager_cmd=None):
277 """Page a file, using an optional pager command and starting line.
276 """Page a file, using an optional pager command and starting line.
278 """
277 """
279
278
280 pager_cmd = get_pager_cmd(pager_cmd)
279 pager_cmd = get_pager_cmd(pager_cmd)
281 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
280 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
282
281
283 try:
282 try:
284 if os.environ['TERM'] in ['emacs','dumb']:
283 if os.environ['TERM'] in ['emacs','dumb']:
285 raise EnvironmentError
284 raise EnvironmentError
286 system(pager_cmd + ' ' + fname)
285 system(pager_cmd + ' ' + fname)
287 except:
286 except:
288 try:
287 try:
289 if start > 0:
288 if start > 0:
290 start -= 1
289 start -= 1
291 page(open(fname).read(),start)
290 page(open(fname).read(),start)
292 except:
291 except:
293 print('Unable to show file',repr(fname))
292 print('Unable to show file',repr(fname))
294
293
295
294
296 def get_pager_cmd(pager_cmd=None):
295 def get_pager_cmd(pager_cmd=None):
297 """Return a pager command.
296 """Return a pager command.
298
297
299 Makes some attempts at finding an OS-correct one.
298 Makes some attempts at finding an OS-correct one.
300 """
299 """
301 if os.name == 'posix':
300 if os.name == 'posix':
302 default_pager_cmd = 'less -R' # -R for color control sequences
301 default_pager_cmd = 'less -R' # -R for color control sequences
303 elif os.name in ['nt','dos']:
302 elif os.name in ['nt','dos']:
304 default_pager_cmd = 'type'
303 default_pager_cmd = 'type'
305
304
306 if pager_cmd is None:
305 if pager_cmd is None:
307 try:
306 try:
308 pager_cmd = os.environ['PAGER']
307 pager_cmd = os.environ['PAGER']
309 except:
308 except:
310 pager_cmd = default_pager_cmd
309 pager_cmd = default_pager_cmd
311
310
312 if pager_cmd == 'less' and '-r' not in os.environ.get('LESS', '').lower():
311 if pager_cmd == 'less' and '-r' not in os.environ.get('LESS', '').lower():
313 pager_cmd += ' -R'
312 pager_cmd += ' -R'
314
313
315 return pager_cmd
314 return pager_cmd
316
315
317
316
318 def get_pager_start(pager, start):
317 def get_pager_start(pager, start):
319 """Return the string for paging files with an offset.
318 """Return the string for paging files with an offset.
320
319
321 This is the '+N' argument which less and more (under Unix) accept.
320 This is the '+N' argument which less and more (under Unix) accept.
322 """
321 """
323
322
324 if pager in ['less','more']:
323 if pager in ['less','more']:
325 if start:
324 if start:
326 start_string = '+' + str(start)
325 start_string = '+' + str(start)
327 else:
326 else:
328 start_string = ''
327 start_string = ''
329 else:
328 else:
330 start_string = ''
329 start_string = ''
331 return start_string
330 return start_string
332
331
333
332
334 # (X)emacs on win32 doesn't like to be bypassed with msvcrt.getch()
333 # (X)emacs on win32 doesn't like to be bypassed with msvcrt.getch()
335 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
334 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
336 import msvcrt
335 import msvcrt
337 def page_more():
336 def page_more():
338 """ Smart pausing between pages
337 """ Smart pausing between pages
339
338
340 @return: True if need print more lines, False if quit
339 @return: True if need print more lines, False if quit
341 """
340 """
342 sys.stdout.write('---Return to continue, q to quit--- ')
341 sys.stdout.write('---Return to continue, q to quit--- ')
343 ans = msvcrt.getwch()
342 ans = msvcrt.getwch()
344 if ans in ("q", "Q"):
343 if ans in ("q", "Q"):
345 result = False
344 result = False
346 else:
345 else:
347 result = True
346 result = True
348 sys.stdout.write("\b"*37 + " "*37 + "\b"*37)
347 sys.stdout.write("\b"*37 + " "*37 + "\b"*37)
349 return result
348 return result
350 else:
349 else:
351 def page_more():
350 def page_more():
352 ans = py3compat.input('---Return to continue, q to quit--- ')
351 ans = py3compat.input('---Return to continue, q to quit--- ')
353 if ans.lower().startswith('q'):
352 if ans.lower().startswith('q'):
354 return False
353 return False
355 else:
354 else:
356 return True
355 return True
357
356
358
357
359 def snip_print(str,width = 75,print_full = 0,header = ''):
358 def snip_print(str,width = 75,print_full = 0,header = ''):
360 """Print a string snipping the midsection to fit in width.
359 """Print a string snipping the midsection to fit in width.
361
360
362 print_full: mode control:
361 print_full: mode control:
363
362
364 - 0: only snip long strings
363 - 0: only snip long strings
365 - 1: send to page() directly.
364 - 1: send to page() directly.
366 - 2: snip long strings and ask for full length viewing with page()
365 - 2: snip long strings and ask for full length viewing with page()
367
366
368 Return 1 if snipping was necessary, 0 otherwise."""
367 Return 1 if snipping was necessary, 0 otherwise."""
369
368
370 if print_full == 1:
369 if print_full == 1:
371 page(header+str)
370 page(header+str)
372 return 0
371 return 0
373
372
374 print(header, end=' ')
373 print(header, end=' ')
375 if len(str) < width:
374 if len(str) < width:
376 print(str)
375 print(str)
377 snip = 0
376 snip = 0
378 else:
377 else:
379 whalf = int((width -5)/2)
378 whalf = int((width -5)/2)
380 print(str[:whalf] + ' <...> ' + str[-whalf:])
379 print(str[:whalf] + ' <...> ' + str[-whalf:])
381 snip = 1
380 snip = 1
382 if snip and print_full == 2:
381 if snip and print_full == 2:
383 if py3compat.input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
382 if py3compat.input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
384 page(str)
383 page(str)
385 return snip
384 return snip
@@ -1,71 +1,62 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Context managers for adding things to sys.path temporarily.
3 Context managers for adding things to sys.path temporarily.
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 """
8 """
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2008-2011 The IPython Development Team
11 # Copyright (C) 2008-2011 The IPython Development Team
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 #-----------------------------------------------------------------------------
18 # Imports
19 #-----------------------------------------------------------------------------
20
21 import sys
17 import sys
22
18
23 from IPython.utils.py3compat import cast_bytes_py2
24
25 #-----------------------------------------------------------------------------
26 # Code
27 #-----------------------------------------------------------------------------
28
19
29 class appended_to_syspath(object):
20 class appended_to_syspath(object):
30 """A context for appending a directory to sys.path for a second."""
21 """A context for appending a directory to sys.path for a second."""
31
22
32 def __init__(self, dir):
23 def __init__(self, dir):
33 self.dir = cast_bytes_py2(dir, sys.getdefaultencoding())
24 self.dir = dir
34
25
35 def __enter__(self):
26 def __enter__(self):
36 if self.dir not in sys.path:
27 if self.dir not in sys.path:
37 sys.path.append(self.dir)
28 sys.path.append(self.dir)
38 self.added = True
29 self.added = True
39 else:
30 else:
40 self.added = False
31 self.added = False
41
32
42 def __exit__(self, type, value, traceback):
33 def __exit__(self, type, value, traceback):
43 if self.added:
34 if self.added:
44 try:
35 try:
45 sys.path.remove(self.dir)
36 sys.path.remove(self.dir)
46 except ValueError:
37 except ValueError:
47 pass
38 pass
48 # Returning False causes any exceptions to be re-raised.
39 # Returning False causes any exceptions to be re-raised.
49 return False
40 return False
50
41
51 class prepended_to_syspath(object):
42 class prepended_to_syspath(object):
52 """A context for prepending a directory to sys.path for a second."""
43 """A context for prepending a directory to sys.path for a second."""
53
44
54 def __init__(self, dir):
45 def __init__(self, dir):
55 self.dir = cast_bytes_py2(dir, sys.getdefaultencoding())
46 self.dir = dir
56
47
57 def __enter__(self):
48 def __enter__(self):
58 if self.dir not in sys.path:
49 if self.dir not in sys.path:
59 sys.path.insert(0,self.dir)
50 sys.path.insert(0,self.dir)
60 self.added = True
51 self.added = True
61 else:
52 else:
62 self.added = False
53 self.added = False
63
54
64 def __exit__(self, type, value, traceback):
55 def __exit__(self, type, value, traceback):
65 if self.added:
56 if self.added:
66 try:
57 try:
67 sys.path.remove(self.dir)
58 sys.path.remove(self.dir)
68 except ValueError:
59 except ValueError:
69 pass
60 pass
70 # Returning False causes any exceptions to be re-raised.
61 # Returning False causes any exceptions to be re-raised.
71 return False
62 return False
General Comments 0
You need to be logged in to leave comments. Login now