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