##// END OF EJS Templates
Merge remote-tracking branch 'public-upstream/master' into links-rebase...
Jason Grout -
r19202:bab26ab3 merge
parent child Browse files
Show More

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

1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,18 +1,22 b''
1 1 MANIFEST
2 2 build
3 3 dist
4 4 _build
5 5 docs/man/*.gz
6 6 docs/source/api/generated
7 7 docs/source/config/options
8 docs/source/interactive/magics-generated.txt
8 9 docs/gh-pages
9 10 IPython/html/notebook/static/mathjax
10 11 IPython/html/static/style/*.map
11 12 *.py[co]
12 13 __pycache__
13 14 *.egg-info
14 15 *~
15 16 *.bak
16 17 .ipynb_checkpoints
17 18 .tox
18 19 .DS_Store
20 \#*#
21 .#*
22 .coverage
@@ -1,28 +1,29 b''
1 1 # http://travis-ci.org/#!/ipython/ipython
2 2 language: python
3 3 python:
4 4 - 3.4
5 5 - 2.7
6 6 - 3.3
7 7 env:
8 8 - GROUP=js
9 9 - GROUP=
10 10 before_install:
11 11 # workaround for https://github.com/travis-ci/travis-cookbooks/issues/155
12 12 - sudo rm -rf /dev/shm && sudo ln -s /run/shm /dev/shm
13 13 # Pierre Carrier's PPA for PhantomJS and CasperJS
14 - time sudo add-apt-repository -y ppa:pcarrier/ppa
15 - time sudo apt-get update
16 - time sudo apt-get install pandoc casperjs libzmq3-dev
17 # pin tornado < 4 for js tests while phantom is on super old webkit
18 - if [[ $GROUP == 'js' ]]; then pip install 'tornado<4'; fi
19 - time pip install -f https://nipy.bic.berkeley.edu/wheelhouse/travis jinja2 sphinx pygments tornado requests mock pyzmq jsonschema jsonpointer mistune
14 - sudo add-apt-repository -y ppa:pcarrier/ppa
15 # Needed to get recent version of pandoc in ubntu 12.04
16 - sudo add-apt-repository -y ppa:marutter/c2d4u
17 - sudo apt-get update
18 - sudo apt-get install pandoc casperjs libzmq3-dev
19 - git clone --quiet --depth 1 https://github.com/minrk/travis-wheels travis-wheels
20 - 'if [[ $GROUP == js* ]]; then python -m IPython.external.mathjax; fi'
20 21 install:
21 - time python setup.py install -q
22 - pip install -f travis-wheels/wheelhouse file://$PWD#egg=ipython[all]
22 23 script:
23 24 - cd /tmp && iptest $GROUP
24 25
25 26 matrix:
26 27 exclude:
27 28 - python: 3.3
28 29 env: GROUP=js
@@ -1,46 +1,66 b''
1 1 # Installs IPython from the current branch
2 2 # Another Docker container should build from this one to get services like the notebook
3 3
4 4 FROM ubuntu:14.04
5 5
6 6 MAINTAINER IPython Project <ipython-dev@scipy.org>
7 7
8 # Make sure apt is up to date
9 RUN apt-get update
10 RUN apt-get upgrade -y
8 ENV DEBIAN_FRONTEND noninteractive
11 9
12 10 # Not essential, but wise to set the lang
13 11 # Note: Users with other languages should set this in their derivative image
14 RUN apt-get install -y language-pack-en
12 RUN apt-get update && apt-get install -y language-pack-en
15 13 ENV LANGUAGE en_US.UTF-8
16 14 ENV LANG en_US.UTF-8
17 15 ENV LC_ALL en_US.UTF-8
18 16
19 17 RUN locale-gen en_US.UTF-8
20 18 RUN dpkg-reconfigure locales
21 19
22 20 # Python binary dependencies, developer tools
23 RUN apt-get install -y -q build-essential make gcc zlib1g-dev git && \
24 apt-get install -y -q python python-dev python-pip python3-dev python3-pip && \
25 apt-get install -y -q libzmq3-dev sqlite3 libsqlite3-dev pandoc libcurl4-openssl-dev nodejs nodejs-legacy npm
21 RUN apt-get update && apt-get install -y -q \
22 build-essential \
23 make \
24 gcc \
25 zlib1g-dev \
26 git \
27 python \
28 python-dev \
29 python-pip \
30 python3-dev \
31 python3-pip \
32 python-sphinx \
33 python3-sphinx \
34 libzmq3-dev \
35 sqlite3 \
36 libsqlite3-dev \
37 pandoc \
38 libcurl4-openssl-dev \
39 nodejs \
40 nodejs-legacy \
41 npm
26 42
27 43 # In order to build from source, need less
28 RUN npm install -g less
44 RUN npm install -g less@1.7.5
29 45
30 RUN apt-get -y install fabric
46 RUN pip install invoke
31 47
32 48 RUN mkdir -p /srv/
33 49 WORKDIR /srv/
34 50 ADD . /srv/ipython
35 51 WORKDIR /srv/ipython/
36 52 RUN chmod -R +rX /srv/ipython
37 53
38 54 # .[all] only works with -e, so use file://path#egg
39 55 # Can't use -e because ipython2 and ipython3 will clobber each other
40 RUN pip2 install --upgrade file:///srv/ipython#egg=ipython[all]
41 RUN pip3 install --upgrade file:///srv/ipython#egg=ipython[all]
56 RUN pip2 install file:///srv/ipython#egg=ipython[all]
57 RUN pip3 install file:///srv/ipython#egg=ipython[all]
42 58
43 59 # install kernels
44 60 RUN python2 -m IPython kernelspec install-self --system
45 61 RUN python3 -m IPython kernelspec install-self --system
46 62
63 WORKDIR /tmp/
64
65 RUN iptest2
66 RUN iptest3
@@ -1,586 +1,611 b''
1 1 # encoding: utf-8
2 2 """A base class for a configurable application."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 from __future__ import print_function
8 8
9 import json
9 10 import logging
10 11 import os
11 12 import re
12 13 import sys
13 14 from copy import deepcopy
14 15 from collections import defaultdict
15 16
16 17 from IPython.external.decorator import decorator
17 18
18 19 from IPython.config.configurable import SingletonConfigurable
19 20 from IPython.config.loader import (
20 21 KVArgParseConfigLoader, PyFileConfigLoader, Config, ArgumentError, ConfigFileNotFound, JSONFileConfigLoader
21 22 )
22 23
23 24 from IPython.utils.traitlets import (
24 25 Unicode, List, Enum, Dict, Instance, TraitError
25 26 )
26 27 from IPython.utils.importstring import import_item
27 28 from IPython.utils.text import indent, wrap_paragraphs, dedent
28 29 from IPython.utils import py3compat
29 30 from IPython.utils.py3compat import string_types, iteritems
30 31
31 32 #-----------------------------------------------------------------------------
32 33 # Descriptions for the various sections
33 34 #-----------------------------------------------------------------------------
34 35
35 36 # merge flags&aliases into options
36 37 option_description = """
37 38 Arguments that take values are actually convenience aliases to full
38 39 Configurables, whose aliases are listed on the help line. For more information
39 40 on full configurables, see '--help-all'.
40 41 """.strip() # trim newlines of front and back
41 42
42 43 keyvalue_description = """
43 44 Parameters are set from command-line arguments of the form:
44 45 `--Class.trait=value`.
45 46 This line is evaluated in Python, so simple expressions are allowed, e.g.::
46 47 `--C.a='range(3)'` For setting C.a=[0,1,2].
47 48 """.strip() # trim newlines of front and back
48 49
49 50 # sys.argv can be missing, for example when python is embedded. See the docs
50 51 # for details: http://docs.python.org/2/c-api/intro.html#embedding-python
51 52 if not hasattr(sys, "argv"):
52 53 sys.argv = [""]
53 54
54 55 subcommand_description = """
55 56 Subcommands are launched as `{app} cmd [args]`. For information on using
56 57 subcommand 'cmd', do: `{app} cmd -h`.
57 58 """
58 59 # get running program name
59 60
60 61 #-----------------------------------------------------------------------------
61 62 # Application class
62 63 #-----------------------------------------------------------------------------
63 64
64 65 @decorator
65 66 def catch_config_error(method, app, *args, **kwargs):
66 67 """Method decorator for catching invalid config (Trait/ArgumentErrors) during init.
67 68
68 69 On a TraitError (generally caused by bad config), this will print the trait's
69 70 message, and exit the app.
70 71
71 72 For use on init methods, to prevent invoking excepthook on invalid input.
72 73 """
73 74 try:
74 75 return method(app, *args, **kwargs)
75 76 except (TraitError, ArgumentError) as e:
76 77 app.print_help()
77 78 app.log.fatal("Bad config encountered during initialization:")
78 79 app.log.fatal(str(e))
79 80 app.log.debug("Config at the time: %s", app.config)
80 81 app.exit(1)
81 82
82 83
83 84 class ApplicationError(Exception):
84 85 pass
85 86
86 87 class LevelFormatter(logging.Formatter):
87 88 """Formatter with additional `highlevel` record
88 89
89 90 This field is empty if log level is less than highlevel_limit,
90 91 otherwise it is formatted with self.highlevel_format.
91 92
92 93 Useful for adding 'WARNING' to warning messages,
93 94 without adding 'INFO' to info, etc.
94 95 """
95 96 highlevel_limit = logging.WARN
96 97 highlevel_format = " %(levelname)s |"
97 98
98 99 def format(self, record):
99 100 if record.levelno >= self.highlevel_limit:
100 101 record.highlevel = self.highlevel_format % record.__dict__
101 102 else:
102 103 record.highlevel = ""
103 104 return super(LevelFormatter, self).format(record)
104 105
105 106
106 107 class Application(SingletonConfigurable):
107 108 """A singleton application with full configuration support."""
108 109
109 110 # The name of the application, will usually match the name of the command
110 111 # line application
111 112 name = Unicode(u'application')
112 113
113 114 # The description of the application that is printed at the beginning
114 115 # of the help.
115 116 description = Unicode(u'This is an application.')
116 117 # default section descriptions
117 118 option_description = Unicode(option_description)
118 119 keyvalue_description = Unicode(keyvalue_description)
119 120 subcommand_description = Unicode(subcommand_description)
120 121
121 122 # The usage and example string that goes at the end of the help string.
122 123 examples = Unicode()
123 124
124 125 # A sequence of Configurable subclasses whose config=True attributes will
125 126 # be exposed at the command line.
126 classes = List([])
127 classes = []
128 @property
129 def _help_classes(self):
130 """Define `App.help_classes` if CLI classes should differ from config file classes"""
131 return getattr(self, 'help_classes', self.classes)
132
133 @property
134 def _config_classes(self):
135 """Define `App.config_classes` if config file classes should differ from CLI classes."""
136 return getattr(self, 'config_classes', self.classes)
127 137
128 138 # The version string of this application.
129 139 version = Unicode(u'0.0')
130 140
131 141 # the argv used to initialize the application
132 142 argv = List()
133 143
134 144 # The log level for the application
135 145 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
136 146 default_value=logging.WARN,
137 147 config=True,
138 148 help="Set the log level by value or name.")
139 149 def _log_level_changed(self, name, old, new):
140 150 """Adjust the log level when log_level is set."""
141 151 if isinstance(new, string_types):
142 152 new = getattr(logging, new)
143 153 self.log_level = new
144 154 self.log.setLevel(new)
145 155
146 156 _log_formatter_cls = LevelFormatter
147 157
148 158 log_datefmt = Unicode("%Y-%m-%d %H:%M:%S", config=True,
149 159 help="The date format used by logging formatters for %(asctime)s"
150 160 )
151 161 def _log_datefmt_changed(self, name, old, new):
152 162 self._log_format_changed()
153 163
154 164 log_format = Unicode("[%(name)s]%(highlevel)s %(message)s", config=True,
155 165 help="The Logging format template",
156 166 )
157 167 def _log_format_changed(self, name, old, new):
158 168 """Change the log formatter when log_format is set."""
159 169 _log_handler = self.log.handlers[0]
160 170 _log_formatter = self._log_formatter_cls(fmt=new, datefmt=self.log_datefmt)
161 171 _log_handler.setFormatter(_log_formatter)
162 172
163 173
164 174 log = Instance(logging.Logger)
165 175 def _log_default(self):
166 176 """Start logging for this application.
167 177
168 178 The default is to log to stderr using a StreamHandler, if no default
169 179 handler already exists. The log level starts at logging.WARN, but this
170 180 can be adjusted by setting the ``log_level`` attribute.
171 181 """
172 182 log = logging.getLogger(self.__class__.__name__)
173 183 log.setLevel(self.log_level)
174 184 log.propagate = False
175 185 _log = log # copied from Logger.hasHandlers() (new in Python 3.2)
176 186 while _log:
177 187 if _log.handlers:
178 188 return log
179 189 if not _log.propagate:
180 190 break
181 191 else:
182 192 _log = _log.parent
183 193 if sys.executable.endswith('pythonw.exe'):
184 194 # this should really go to a file, but file-logging is only
185 195 # hooked up in parallel applications
186 196 _log_handler = logging.StreamHandler(open(os.devnull, 'w'))
187 197 else:
188 198 _log_handler = logging.StreamHandler()
189 199 _log_formatter = self._log_formatter_cls(fmt=self.log_format, datefmt=self.log_datefmt)
190 200 _log_handler.setFormatter(_log_formatter)
191 201 log.addHandler(_log_handler)
192 202 return log
193 203
194 204 # the alias map for configurables
195 205 aliases = Dict({'log-level' : 'Application.log_level'})
196 206
197 207 # flags for loading Configurables or store_const style flags
198 208 # flags are loaded from this dict by '--key' flags
199 209 # this must be a dict of two-tuples, the first element being the Config/dict
200 210 # and the second being the help string for the flag
201 211 flags = Dict()
202 212 def _flags_changed(self, name, old, new):
203 213 """ensure flags dict is valid"""
204 214 for key,value in iteritems(new):
205 215 assert len(value) == 2, "Bad flag: %r:%s"%(key,value)
206 216 assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value)
207 217 assert isinstance(value[1], string_types), "Bad flag: %r:%s"%(key,value)
208 218
209 219
210 220 # subcommands for launching other applications
211 221 # if this is not empty, this will be a parent Application
212 222 # this must be a dict of two-tuples,
213 223 # the first element being the application class/import string
214 224 # and the second being the help string for the subcommand
215 225 subcommands = Dict()
216 226 # parse_command_line will initialize a subapp, if requested
217 227 subapp = Instance('IPython.config.application.Application', allow_none=True)
218 228
219 229 # extra command-line arguments that don't set config values
220 230 extra_args = List(Unicode)
221 231
222 232
223 233 def __init__(self, **kwargs):
224 234 SingletonConfigurable.__init__(self, **kwargs)
225 235 # Ensure my class is in self.classes, so my attributes appear in command line
226 236 # options and config files.
227 237 if self.__class__ not in self.classes:
228 238 self.classes.insert(0, self.__class__)
229 239
230 240 def _config_changed(self, name, old, new):
231 241 SingletonConfigurable._config_changed(self, name, old, new)
232 242 self.log.debug('Config changed:')
233 243 self.log.debug(repr(new))
234 244
235 245 @catch_config_error
236 246 def initialize(self, argv=None):
237 247 """Do the basic steps to configure me.
238 248
239 249 Override in subclasses.
240 250 """
241 251 self.parse_command_line(argv)
242 252
243 253
244 254 def start(self):
245 255 """Start the app mainloop.
246 256
247 257 Override in subclasses.
248 258 """
249 259 if self.subapp is not None:
250 260 return self.subapp.start()
251 261
252 262 def print_alias_help(self):
253 263 """Print the alias part of the help."""
254 264 if not self.aliases:
255 265 return
256 266
257 267 lines = []
258 268 classdict = {}
259 for cls in self.classes:
269 for cls in self._help_classes:
260 270 # include all parents (up to, but excluding Configurable) in available names
261 271 for c in cls.mro()[:-3]:
262 272 classdict[c.__name__] = c
263 273
264 274 for alias, longname in iteritems(self.aliases):
265 275 classname, traitname = longname.split('.',1)
266 276 cls = classdict[classname]
267 277
268 278 trait = cls.class_traits(config=True)[traitname]
269 279 help = cls.class_get_trait_help(trait).splitlines()
270 280 # reformat first line
271 281 help[0] = help[0].replace(longname, alias) + ' (%s)'%longname
272 282 if len(alias) == 1:
273 283 help[0] = help[0].replace('--%s='%alias, '-%s '%alias)
274 284 lines.extend(help)
275 285 # lines.append('')
276 286 print(os.linesep.join(lines))
277 287
278 288 def print_flag_help(self):
279 289 """Print the flag part of the help."""
280 290 if not self.flags:
281 291 return
282 292
283 293 lines = []
284 294 for m, (cfg,help) in iteritems(self.flags):
285 295 prefix = '--' if len(m) > 1 else '-'
286 296 lines.append(prefix+m)
287 297 lines.append(indent(dedent(help.strip())))
288 298 # lines.append('')
289 299 print(os.linesep.join(lines))
290 300
291 301 def print_options(self):
292 302 if not self.flags and not self.aliases:
293 303 return
294 304 lines = ['Options']
295 305 lines.append('-'*len(lines[0]))
296 306 lines.append('')
297 307 for p in wrap_paragraphs(self.option_description):
298 308 lines.append(p)
299 309 lines.append('')
300 310 print(os.linesep.join(lines))
301 311 self.print_flag_help()
302 312 self.print_alias_help()
303 313 print()
304 314
305 315 def print_subcommands(self):
306 316 """Print the subcommand part of the help."""
307 317 if not self.subcommands:
308 318 return
309 319
310 320 lines = ["Subcommands"]
311 321 lines.append('-'*len(lines[0]))
312 322 lines.append('')
313 323 for p in wrap_paragraphs(self.subcommand_description.format(
314 324 app=self.name)):
315 325 lines.append(p)
316 326 lines.append('')
317 327 for subc, (cls, help) in iteritems(self.subcommands):
318 328 lines.append(subc)
319 329 if help:
320 330 lines.append(indent(dedent(help.strip())))
321 331 lines.append('')
322 332 print(os.linesep.join(lines))
323 333
324 334 def print_help(self, classes=False):
325 335 """Print the help for each Configurable class in self.classes.
326 336
327 337 If classes=False (the default), only flags and aliases are printed.
328 338 """
329 339 self.print_description()
330 340 self.print_subcommands()
331 341 self.print_options()
332 342
333 343 if classes:
334 if self.classes:
344 help_classes = self._help_classes
345 if help_classes:
335 346 print("Class parameters")
336 347 print("----------------")
337 348 print()
338 349 for p in wrap_paragraphs(self.keyvalue_description):
339 350 print(p)
340 351 print()
341 352
342 for cls in self.classes:
353 for cls in help_classes:
343 354 cls.class_print_help()
344 355 print()
345 356 else:
346 357 print("To see all available configurables, use `--help-all`")
347 358 print()
348 359
349 360 self.print_examples()
350 361
351 362
352 363 def print_description(self):
353 364 """Print the application description."""
354 365 for p in wrap_paragraphs(self.description):
355 366 print(p)
356 367 print()
357 368
358 369 def print_examples(self):
359 370 """Print usage and examples.
360 371
361 372 This usage string goes at the end of the command line help string
362 373 and should contain examples of the application's usage.
363 374 """
364 375 if self.examples:
365 376 print("Examples")
366 377 print("--------")
367 378 print()
368 379 print(indent(dedent(self.examples.strip())))
369 380 print()
370 381
371 382 def print_version(self):
372 383 """Print the version string."""
373 384 print(self.version)
374 385
375 386 def update_config(self, config):
376 387 """Fire the traits events when the config is updated."""
377 388 # Save a copy of the current config.
378 389 newconfig = deepcopy(self.config)
379 390 # Merge the new config into the current one.
380 391 newconfig.merge(config)
381 392 # Save the combined config as self.config, which triggers the traits
382 393 # events.
383 394 self.config = newconfig
384 395
385 396 @catch_config_error
386 397 def initialize_subcommand(self, subc, argv=None):
387 398 """Initialize a subcommand with argv."""
388 399 subapp,help = self.subcommands.get(subc)
389 400
390 401 if isinstance(subapp, string_types):
391 402 subapp = import_item(subapp)
392 403
393 404 # clear existing instances
394 405 self.__class__.clear_instance()
395 406 # instantiate
396 407 self.subapp = subapp.instance(config=self.config)
397 408 # and initialize subapp
398 409 self.subapp.initialize(argv)
399 410
400 411 def flatten_flags(self):
401 412 """flatten flags and aliases, so cl-args override as expected.
402 413
403 414 This prevents issues such as an alias pointing to InteractiveShell,
404 415 but a config file setting the same trait in TerminalInteraciveShell
405 416 getting inappropriate priority over the command-line arg.
406 417
407 418 Only aliases with exactly one descendent in the class list
408 419 will be promoted.
409 420
410 421 """
411 422 # build a tree of classes in our list that inherit from a particular
412 423 # it will be a dict by parent classname of classes in our list
413 424 # that are descendents
414 425 mro_tree = defaultdict(list)
415 for cls in self.classes:
426 for cls in self._help_classes:
416 427 clsname = cls.__name__
417 428 for parent in cls.mro()[1:-3]:
418 429 # exclude cls itself and Configurable,HasTraits,object
419 430 mro_tree[parent.__name__].append(clsname)
420 431 # flatten aliases, which have the form:
421 432 # { 'alias' : 'Class.trait' }
422 433 aliases = {}
423 434 for alias, cls_trait in iteritems(self.aliases):
424 435 cls,trait = cls_trait.split('.',1)
425 436 children = mro_tree[cls]
426 437 if len(children) == 1:
427 438 # exactly one descendent, promote alias
428 439 cls = children[0]
429 440 aliases[alias] = '.'.join([cls,trait])
430 441
431 442 # flatten flags, which are of the form:
432 443 # { 'key' : ({'Cls' : {'trait' : value}}, 'help')}
433 444 flags = {}
434 445 for key, (flagdict, help) in iteritems(self.flags):
435 446 newflag = {}
436 447 for cls, subdict in iteritems(flagdict):
437 448 children = mro_tree[cls]
438 449 # exactly one descendent, promote flag section
439 450 if len(children) == 1:
440 451 cls = children[0]
441 452 newflag[cls] = subdict
442 453 flags[key] = (newflag, help)
443 454 return flags, aliases
444 455
445 456 @catch_config_error
446 457 def parse_command_line(self, argv=None):
447 458 """Parse the command line arguments."""
448 459 argv = sys.argv[1:] if argv is None else argv
449 460 self.argv = [ py3compat.cast_unicode(arg) for arg in argv ]
450 461
451 462 if argv and argv[0] == 'help':
452 463 # turn `ipython help notebook` into `ipython notebook -h`
453 464 argv = argv[1:] + ['-h']
454 465
455 466 if self.subcommands and len(argv) > 0:
456 467 # we have subcommands, and one may have been specified
457 468 subc, subargv = argv[0], argv[1:]
458 469 if re.match(r'^\w(\-?\w)*$', subc) and subc in self.subcommands:
459 470 # it's a subcommand, and *not* a flag or class parameter
460 471 return self.initialize_subcommand(subc, subargv)
461 472
462 473 # Arguments after a '--' argument are for the script IPython may be
463 474 # about to run, not IPython iteslf. For arguments parsed here (help and
464 475 # version), we want to only search the arguments up to the first
465 476 # occurrence of '--', which we're calling interpreted_argv.
466 477 try:
467 478 interpreted_argv = argv[:argv.index('--')]
468 479 except ValueError:
469 480 interpreted_argv = argv
470 481
471 482 if any(x in interpreted_argv for x in ('-h', '--help-all', '--help')):
472 483 self.print_help('--help-all' in interpreted_argv)
473 484 self.exit(0)
474 485
475 486 if '--version' in interpreted_argv or '-V' in interpreted_argv:
476 487 self.print_version()
477 488 self.exit(0)
478 489
479 490 # flatten flags&aliases, so cl-args get appropriate priority:
480 491 flags,aliases = self.flatten_flags()
481 492 loader = KVArgParseConfigLoader(argv=argv, aliases=aliases,
482 493 flags=flags, log=self.log)
483 494 config = loader.load_config()
484 495 self.update_config(config)
485 496 # store unparsed args in extra_args
486 497 self.extra_args = loader.extra_args
487 498
488 499 @classmethod
489 500 def _load_config_files(cls, basefilename, path=None, log=None):
490 501 """Load config files (py,json) by filename and path.
491 502
492 503 yield each config object in turn.
493 504 """
494 pyloader = PyFileConfigLoader(basefilename+'.py', path=path, log=log)
495 jsonloader = JSONFileConfigLoader(basefilename+'.json', path=path, log=log)
496 config = None
497 for loader in [pyloader, jsonloader]:
498 try:
499 config = loader.load_config()
500 except ConfigFileNotFound:
501 pass
502 except Exception:
503 # try to get the full filename, but it will be empty in the
504 # unlikely event that the error raised before filefind finished
505 filename = loader.full_filename or basefilename
506 # problem while running the file
507 if log:
508 log.error("Exception while loading config file %s",
509 filename, exc_info=True)
510 else:
511 if log:
512 log.debug("Loaded config file: %s", loader.full_filename)
513 if config:
514 yield config
505
506 if not isinstance(path, list):
507 path = [path]
508 for path in path[::-1]:
509 # path list is in descending priority order, so load files backwards:
510 pyloader = PyFileConfigLoader(basefilename+'.py', path=path, log=log)
511 jsonloader = JSONFileConfigLoader(basefilename+'.json', path=path, log=log)
512 config = None
513 for loader in [pyloader, jsonloader]:
514 try:
515 config = loader.load_config()
516 except ConfigFileNotFound:
517 pass
518 except Exception:
519 # try to get the full filename, but it will be empty in the
520 # unlikely event that the error raised before filefind finished
521 filename = loader.full_filename or basefilename
522 # problem while running the file
523 if log:
524 log.error("Exception while loading config file %s",
525 filename, exc_info=True)
526 else:
527 if log:
528 log.debug("Loaded config file: %s", loader.full_filename)
529 if config:
530 yield config
515 531
516 532 raise StopIteration
517 533
518 534
519 535 @catch_config_error
520 536 def load_config_file(self, filename, path=None):
521 537 """Load config files by filename and path."""
522 538 filename, ext = os.path.splitext(filename)
539 loaded = []
523 540 for config in self._load_config_files(filename, path=path, log=self.log):
541 loaded.append(config)
524 542 self.update_config(config)
543 if len(loaded) > 1:
544 collisions = loaded[0].collisions(loaded[1])
545 if collisions:
546 self.log.warn("Collisions detected in {0}.py and {0}.json config files."
547 " {0}.json has higher priority: {1}".format(
548 filename, json.dumps(collisions, indent=2),
549 ))
525 550
526 551
527 552 def generate_config_file(self):
528 553 """generate default config file from Configurables"""
529 554 lines = ["# Configuration file for %s."%self.name]
530 555 lines.append('')
531 556 lines.append('c = get_config()')
532 557 lines.append('')
533 for cls in self.classes:
558 for cls in self._config_classes:
534 559 lines.append(cls.class_config_section())
535 560 return '\n'.join(lines)
536 561
537 562 def exit(self, exit_status=0):
538 563 self.log.debug("Exiting application: %s" % self.name)
539 564 sys.exit(exit_status)
540 565
541 566 @classmethod
542 567 def launch_instance(cls, argv=None, **kwargs):
543 568 """Launch a global instance of this Application
544 569
545 570 If a global instance already exists, this reinitializes and starts it
546 571 """
547 572 app = cls.instance(**kwargs)
548 573 app.initialize(argv)
549 574 app.start()
550 575
551 576 #-----------------------------------------------------------------------------
552 577 # utility functions, for convenience
553 578 #-----------------------------------------------------------------------------
554 579
555 580 def boolean_flag(name, configurable, set_help='', unset_help=''):
556 581 """Helper for building basic --trait, --no-trait flags.
557 582
558 583 Parameters
559 584 ----------
560 585
561 586 name : str
562 587 The name of the flag.
563 588 configurable : str
564 589 The 'Class.trait' string of the trait to be set/unset with the flag
565 590 set_help : unicode
566 591 help string for --name flag
567 592 unset_help : unicode
568 593 help string for --no-name flag
569 594
570 595 Returns
571 596 -------
572 597
573 598 cfg : dict
574 599 A dict with two keys: 'name', and 'no-name', for setting and unsetting
575 600 the trait, respectively.
576 601 """
577 602 # default helpstrings
578 603 set_help = set_help or "set %s=True"%configurable
579 604 unset_help = unset_help or "set %s=False"%configurable
580 605
581 606 cls,trait = configurable.split('.')
582 607
583 608 setter = {cls : {trait : True}}
584 609 unsetter = {cls : {trait : False}}
585 610 return {name : (setter, set_help), 'no-'+name : (unsetter, unset_help)}
586 611
@@ -1,824 +1,844 b''
1 1 # encoding: utf-8
2 2 """A simple configuration system."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 import argparse
8 8 import copy
9 9 import logging
10 10 import os
11 11 import re
12 12 import sys
13 13 import json
14 14
15 15 from IPython.utils.path import filefind, get_ipython_dir
16 16 from IPython.utils import py3compat
17 17 from IPython.utils.encoding import DEFAULT_ENCODING
18 18 from IPython.utils.py3compat import unicode_type, iteritems
19 19 from IPython.utils.traitlets import HasTraits, List, Any
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Exceptions
23 23 #-----------------------------------------------------------------------------
24 24
25 25
26 26 class ConfigError(Exception):
27 27 pass
28 28
29 29 class ConfigLoaderError(ConfigError):
30 30 pass
31 31
32 32 class ConfigFileNotFound(ConfigError):
33 33 pass
34 34
35 35 class ArgumentError(ConfigLoaderError):
36 36 pass
37 37
38 38 #-----------------------------------------------------------------------------
39 39 # Argparse fix
40 40 #-----------------------------------------------------------------------------
41 41
42 42 # Unfortunately argparse by default prints help messages to stderr instead of
43 43 # stdout. This makes it annoying to capture long help screens at the command
44 44 # line, since one must know how to pipe stderr, which many users don't know how
45 45 # to do. So we override the print_help method with one that defaults to
46 46 # stdout and use our class instead.
47 47
48 48 class ArgumentParser(argparse.ArgumentParser):
49 49 """Simple argparse subclass that prints help to stdout by default."""
50 50
51 51 def print_help(self, file=None):
52 52 if file is None:
53 53 file = sys.stdout
54 54 return super(ArgumentParser, self).print_help(file)
55 55
56 56 print_help.__doc__ = argparse.ArgumentParser.print_help.__doc__
57 57
58 58 #-----------------------------------------------------------------------------
59 59 # Config class for holding config information
60 60 #-----------------------------------------------------------------------------
61 61
62 62 class LazyConfigValue(HasTraits):
63 63 """Proxy object for exposing methods on configurable containers
64 64
65 65 Exposes:
66 66
67 67 - append, extend, insert on lists
68 68 - update on dicts
69 69 - update, add on sets
70 70 """
71 71
72 72 _value = None
73 73
74 74 # list methods
75 75 _extend = List()
76 76 _prepend = List()
77 77
78 78 def append(self, obj):
79 79 self._extend.append(obj)
80 80
81 81 def extend(self, other):
82 82 self._extend.extend(other)
83 83
84 84 def prepend(self, other):
85 85 """like list.extend, but for the front"""
86 86 self._prepend[:0] = other
87 87
88 88 _inserts = List()
89 89 def insert(self, index, other):
90 90 if not isinstance(index, int):
91 91 raise TypeError("An integer is required")
92 92 self._inserts.append((index, other))
93 93
94 94 # dict methods
95 95 # update is used for both dict and set
96 96 _update = Any()
97 97 def update(self, other):
98 98 if self._update is None:
99 99 if isinstance(other, dict):
100 100 self._update = {}
101 101 else:
102 102 self._update = set()
103 103 self._update.update(other)
104 104
105 105 # set methods
106 106 def add(self, obj):
107 107 self.update({obj})
108 108
109 109 def get_value(self, initial):
110 110 """construct the value from the initial one
111 111
112 112 after applying any insert / extend / update changes
113 113 """
114 114 if self._value is not None:
115 115 return self._value
116 116 value = copy.deepcopy(initial)
117 117 if isinstance(value, list):
118 118 for idx, obj in self._inserts:
119 119 value.insert(idx, obj)
120 120 value[:0] = self._prepend
121 121 value.extend(self._extend)
122 122
123 123 elif isinstance(value, dict):
124 124 if self._update:
125 125 value.update(self._update)
126 126 elif isinstance(value, set):
127 127 if self._update:
128 128 value.update(self._update)
129 129 self._value = value
130 130 return value
131 131
132 132 def to_dict(self):
133 133 """return JSONable dict form of my data
134 134
135 135 Currently update as dict or set, extend, prepend as lists, and inserts as list of tuples.
136 136 """
137 137 d = {}
138 138 if self._update:
139 139 d['update'] = self._update
140 140 if self._extend:
141 141 d['extend'] = self._extend
142 142 if self._prepend:
143 143 d['prepend'] = self._prepend
144 144 elif self._inserts:
145 145 d['inserts'] = self._inserts
146 146 return d
147 147
148 148
149 149 def _is_section_key(key):
150 150 """Is a Config key a section name (does it start with a capital)?"""
151 151 if key and key[0].upper()==key[0] and not key.startswith('_'):
152 152 return True
153 153 else:
154 154 return False
155 155
156 156
157 157 class Config(dict):
158 158 """An attribute based dict that can do smart merges."""
159 159
160 160 def __init__(self, *args, **kwds):
161 161 dict.__init__(self, *args, **kwds)
162 162 self._ensure_subconfig()
163 163
164 164 def _ensure_subconfig(self):
165 165 """ensure that sub-dicts that should be Config objects are
166 166
167 167 casts dicts that are under section keys to Config objects,
168 168 which is necessary for constructing Config objects from dict literals.
169 169 """
170 170 for key in self:
171 171 obj = self[key]
172 172 if _is_section_key(key) \
173 173 and isinstance(obj, dict) \
174 174 and not isinstance(obj, Config):
175 175 setattr(self, key, Config(obj))
176 176
177 177 def _merge(self, other):
178 178 """deprecated alias, use Config.merge()"""
179 179 self.merge(other)
180 180
181 181 def merge(self, other):
182 182 """merge another config object into this one"""
183 183 to_update = {}
184 184 for k, v in iteritems(other):
185 185 if k not in self:
186 186 to_update[k] = copy.deepcopy(v)
187 187 else: # I have this key
188 188 if isinstance(v, Config) and isinstance(self[k], Config):
189 189 # Recursively merge common sub Configs
190 190 self[k].merge(v)
191 191 else:
192 192 # Plain updates for non-Configs
193 193 to_update[k] = copy.deepcopy(v)
194 194
195 195 self.update(to_update)
196
196
197 def collisions(self, other):
198 """Check for collisions between two config objects.
199
200 Returns a dict of the form {"Class": {"trait": "collision message"}}`,
201 indicating which values have been ignored.
202
203 An empty dict indicates no collisions.
204 """
205 collisions = {}
206 for section in self:
207 if section not in other:
208 continue
209 mine = self[section]
210 theirs = other[section]
211 for key in mine:
212 if key in theirs and mine[key] != theirs[key]:
213 collisions.setdefault(section, {})
214 collisions[section][key] = "%r ignored, using %r" % (mine[key], theirs[key])
215 return collisions
216
197 217 def __contains__(self, key):
198 218 # allow nested contains of the form `"Section.key" in config`
199 219 if '.' in key:
200 220 first, remainder = key.split('.', 1)
201 221 if first not in self:
202 222 return False
203 223 return remainder in self[first]
204 224
205 225 return super(Config, self).__contains__(key)
206 226
207 227 # .has_key is deprecated for dictionaries.
208 228 has_key = __contains__
209 229
210 230 def _has_section(self, key):
211 231 return _is_section_key(key) and key in self
212 232
213 233 def copy(self):
214 234 return type(self)(dict.copy(self))
215 235
216 236 def __copy__(self):
217 237 return self.copy()
218 238
219 239 def __deepcopy__(self, memo):
220 240 import copy
221 241 return type(self)(copy.deepcopy(list(self.items())))
222 242
223 243 def __getitem__(self, key):
224 244 try:
225 245 return dict.__getitem__(self, key)
226 246 except KeyError:
227 247 if _is_section_key(key):
228 248 c = Config()
229 249 dict.__setitem__(self, key, c)
230 250 return c
231 251 elif not key.startswith('_'):
232 252 # undefined, create lazy value, used for container methods
233 253 v = LazyConfigValue()
234 254 dict.__setitem__(self, key, v)
235 255 return v
236 256 else:
237 257 raise KeyError
238 258
239 259 def __setitem__(self, key, value):
240 260 if _is_section_key(key):
241 261 if not isinstance(value, Config):
242 262 raise ValueError('values whose keys begin with an uppercase '
243 263 'char must be Config instances: %r, %r' % (key, value))
244 264 dict.__setitem__(self, key, value)
245 265
246 266 def __getattr__(self, key):
247 267 if key.startswith('__'):
248 268 return dict.__getattr__(self, key)
249 269 try:
250 270 return self.__getitem__(key)
251 271 except KeyError as e:
252 272 raise AttributeError(e)
253 273
254 274 def __setattr__(self, key, value):
255 275 if key.startswith('__'):
256 276 return dict.__setattr__(self, key, value)
257 277 try:
258 278 self.__setitem__(key, value)
259 279 except KeyError as e:
260 280 raise AttributeError(e)
261 281
262 282 def __delattr__(self, key):
263 283 if key.startswith('__'):
264 284 return dict.__delattr__(self, key)
265 285 try:
266 286 dict.__delitem__(self, key)
267 287 except KeyError as e:
268 288 raise AttributeError(e)
269 289
270 290
271 291 #-----------------------------------------------------------------------------
272 292 # Config loading classes
273 293 #-----------------------------------------------------------------------------
274 294
275 295
276 296 class ConfigLoader(object):
277 297 """A object for loading configurations from just about anywhere.
278 298
279 299 The resulting configuration is packaged as a :class:`Config`.
280 300
281 301 Notes
282 302 -----
283 303 A :class:`ConfigLoader` does one thing: load a config from a source
284 304 (file, command line arguments) and returns the data as a :class:`Config` object.
285 305 There are lots of things that :class:`ConfigLoader` does not do. It does
286 306 not implement complex logic for finding config files. It does not handle
287 307 default values or merge multiple configs. These things need to be
288 308 handled elsewhere.
289 309 """
290 310
291 311 def _log_default(self):
292 312 from IPython.utils.log import get_logger
293 313 return get_logger()
294 314
295 315 def __init__(self, log=None):
296 316 """A base class for config loaders.
297 317
298 318 log : instance of :class:`logging.Logger` to use.
299 319 By default loger of :meth:`IPython.config.application.Application.instance()`
300 320 will be used
301 321
302 322 Examples
303 323 --------
304 324
305 325 >>> cl = ConfigLoader()
306 326 >>> config = cl.load_config()
307 327 >>> config
308 328 {}
309 329 """
310 330 self.clear()
311 331 if log is None:
312 332 self.log = self._log_default()
313 333 self.log.debug('Using default logger')
314 334 else:
315 335 self.log = log
316 336
317 337 def clear(self):
318 338 self.config = Config()
319 339
320 340 def load_config(self):
321 341 """Load a config from somewhere, return a :class:`Config` instance.
322 342
323 343 Usually, this will cause self.config to be set and then returned.
324 344 However, in most cases, :meth:`ConfigLoader.clear` should be called
325 345 to erase any previous state.
326 346 """
327 347 self.clear()
328 348 return self.config
329 349
330 350
331 351 class FileConfigLoader(ConfigLoader):
332 352 """A base class for file based configurations.
333 353
334 354 As we add more file based config loaders, the common logic should go
335 355 here.
336 356 """
337 357
338 358 def __init__(self, filename, path=None, **kw):
339 359 """Build a config loader for a filename and path.
340 360
341 361 Parameters
342 362 ----------
343 363 filename : str
344 364 The file name of the config file.
345 365 path : str, list, tuple
346 366 The path to search for the config file on, or a sequence of
347 367 paths to try in order.
348 368 """
349 369 super(FileConfigLoader, self).__init__(**kw)
350 370 self.filename = filename
351 371 self.path = path
352 372 self.full_filename = ''
353 373
354 374 def _find_file(self):
355 375 """Try to find the file by searching the paths."""
356 376 self.full_filename = filefind(self.filename, self.path)
357 377
358 378 class JSONFileConfigLoader(FileConfigLoader):
359 379 """A Json file loader for config"""
360 380
361 381 def load_config(self):
362 382 """Load the config from a file and return it as a Config object."""
363 383 self.clear()
364 384 try:
365 385 self._find_file()
366 386 except IOError as e:
367 387 raise ConfigFileNotFound(str(e))
368 388 dct = self._read_file_as_dict()
369 389 self.config = self._convert_to_config(dct)
370 390 return self.config
371 391
372 392 def _read_file_as_dict(self):
373 393 with open(self.full_filename) as f:
374 394 return json.load(f)
375 395
376 396 def _convert_to_config(self, dictionary):
377 397 if 'version' in dictionary:
378 398 version = dictionary.pop('version')
379 399 else:
380 400 version = 1
381 401 self.log.warn("Unrecognized JSON config file version, assuming version {}".format(version))
382 402
383 403 if version == 1:
384 404 return Config(dictionary)
385 405 else:
386 406 raise ValueError('Unknown version of JSON config file: {version}'.format(version=version))
387 407
388 408
389 409 class PyFileConfigLoader(FileConfigLoader):
390 410 """A config loader for pure python files.
391 411
392 412 This is responsible for locating a Python config file by filename and
393 413 path, then executing it to construct a Config object.
394 414 """
395 415
396 416 def load_config(self):
397 417 """Load the config from a file and return it as a Config object."""
398 418 self.clear()
399 419 try:
400 420 self._find_file()
401 421 except IOError as e:
402 422 raise ConfigFileNotFound(str(e))
403 423 self._read_file_as_dict()
404 424 return self.config
405 425
406 426
407 427 def _read_file_as_dict(self):
408 428 """Load the config file into self.config, with recursive loading."""
409 429 # This closure is made available in the namespace that is used
410 430 # to exec the config file. It allows users to call
411 431 # load_subconfig('myconfig.py') to load config files recursively.
412 432 # It needs to be a closure because it has references to self.path
413 433 # and self.config. The sub-config is loaded with the same path
414 434 # as the parent, but it uses an empty config which is then merged
415 435 # with the parents.
416 436
417 437 # If a profile is specified, the config file will be loaded
418 438 # from that profile
419 439
420 440 def load_subconfig(fname, profile=None):
421 441 # import here to prevent circular imports
422 442 from IPython.core.profiledir import ProfileDir, ProfileDirError
423 443 if profile is not None:
424 444 try:
425 445 profile_dir = ProfileDir.find_profile_dir_by_name(
426 446 get_ipython_dir(),
427 447 profile,
428 448 )
429 449 except ProfileDirError:
430 450 return
431 451 path = profile_dir.location
432 452 else:
433 453 path = self.path
434 454 loader = PyFileConfigLoader(fname, path)
435 455 try:
436 456 sub_config = loader.load_config()
437 457 except ConfigFileNotFound:
438 458 # Pass silently if the sub config is not there. This happens
439 459 # when a user s using a profile, but not the default config.
440 460 pass
441 461 else:
442 462 self.config.merge(sub_config)
443 463
444 464 # Again, this needs to be a closure and should be used in config
445 465 # files to get the config being loaded.
446 466 def get_config():
447 467 return self.config
448 468
449 469 namespace = dict(
450 470 load_subconfig=load_subconfig,
451 471 get_config=get_config,
452 472 __file__=self.full_filename,
453 473 )
454 474 fs_encoding = sys.getfilesystemencoding() or 'ascii'
455 475 conf_filename = self.full_filename.encode(fs_encoding)
456 476 py3compat.execfile(conf_filename, namespace)
457 477
458 478
459 479 class CommandLineConfigLoader(ConfigLoader):
460 480 """A config loader for command line arguments.
461 481
462 482 As we add more command line based loaders, the common logic should go
463 483 here.
464 484 """
465 485
466 486 def _exec_config_str(self, lhs, rhs):
467 487 """execute self.config.<lhs> = <rhs>
468 488
469 489 * expands ~ with expanduser
470 490 * tries to assign with raw eval, otherwise assigns with just the string,
471 491 allowing `--C.a=foobar` and `--C.a="foobar"` to be equivalent. *Not*
472 492 equivalent are `--C.a=4` and `--C.a='4'`.
473 493 """
474 494 rhs = os.path.expanduser(rhs)
475 495 try:
476 496 # Try to see if regular Python syntax will work. This
477 497 # won't handle strings as the quote marks are removed
478 498 # by the system shell.
479 499 value = eval(rhs)
480 500 except (NameError, SyntaxError):
481 501 # This case happens if the rhs is a string.
482 502 value = rhs
483 503
484 504 exec(u'self.config.%s = value' % lhs)
485 505
486 506 def _load_flag(self, cfg):
487 507 """update self.config from a flag, which can be a dict or Config"""
488 508 if isinstance(cfg, (dict, Config)):
489 509 # don't clobber whole config sections, update
490 510 # each section from config:
491 511 for sec,c in iteritems(cfg):
492 512 self.config[sec].update(c)
493 513 else:
494 514 raise TypeError("Invalid flag: %r" % cfg)
495 515
496 516 # raw --identifier=value pattern
497 517 # but *also* accept '-' as wordsep, for aliases
498 518 # accepts: --foo=a
499 519 # --Class.trait=value
500 520 # --alias-name=value
501 521 # rejects: -foo=value
502 522 # --foo
503 523 # --Class.trait
504 524 kv_pattern = re.compile(r'\-\-[A-Za-z][\w\-]*(\.[\w\-]+)*\=.*')
505 525
506 526 # just flags, no assignments, with two *or one* leading '-'
507 527 # accepts: --foo
508 528 # -foo-bar-again
509 529 # rejects: --anything=anything
510 530 # --two.word
511 531
512 532 flag_pattern = re.compile(r'\-\-?\w+[\-\w]*$')
513 533
514 534 class KeyValueConfigLoader(CommandLineConfigLoader):
515 535 """A config loader that loads key value pairs from the command line.
516 536
517 537 This allows command line options to be gives in the following form::
518 538
519 539 ipython --profile="foo" --InteractiveShell.autocall=False
520 540 """
521 541
522 542 def __init__(self, argv=None, aliases=None, flags=None, **kw):
523 543 """Create a key value pair config loader.
524 544
525 545 Parameters
526 546 ----------
527 547 argv : list
528 548 A list that has the form of sys.argv[1:] which has unicode
529 549 elements of the form u"key=value". If this is None (default),
530 550 then sys.argv[1:] will be used.
531 551 aliases : dict
532 552 A dict of aliases for configurable traits.
533 553 Keys are the short aliases, Values are the resolved trait.
534 554 Of the form: `{'alias' : 'Configurable.trait'}`
535 555 flags : dict
536 556 A dict of flags, keyed by str name. Vaues can be Config objects,
537 557 dicts, or "key=value" strings. If Config or dict, when the flag
538 558 is triggered, The flag is loaded as `self.config.update(m)`.
539 559
540 560 Returns
541 561 -------
542 562 config : Config
543 563 The resulting Config object.
544 564
545 565 Examples
546 566 --------
547 567
548 568 >>> from IPython.config.loader import KeyValueConfigLoader
549 569 >>> cl = KeyValueConfigLoader()
550 570 >>> d = cl.load_config(["--A.name='brian'","--B.number=0"])
551 571 >>> sorted(d.items())
552 572 [('A', {'name': 'brian'}), ('B', {'number': 0})]
553 573 """
554 574 super(KeyValueConfigLoader, self).__init__(**kw)
555 575 if argv is None:
556 576 argv = sys.argv[1:]
557 577 self.argv = argv
558 578 self.aliases = aliases or {}
559 579 self.flags = flags or {}
560 580
561 581
562 582 def clear(self):
563 583 super(KeyValueConfigLoader, self).clear()
564 584 self.extra_args = []
565 585
566 586
567 587 def _decode_argv(self, argv, enc=None):
568 """decode argv if bytes, using stin.encoding, falling back on default enc"""
588 """decode argv if bytes, using stdin.encoding, falling back on default enc"""
569 589 uargv = []
570 590 if enc is None:
571 591 enc = DEFAULT_ENCODING
572 592 for arg in argv:
573 593 if not isinstance(arg, unicode_type):
574 594 # only decode if not already decoded
575 595 arg = arg.decode(enc)
576 596 uargv.append(arg)
577 597 return uargv
578 598
579 599
580 600 def load_config(self, argv=None, aliases=None, flags=None):
581 601 """Parse the configuration and generate the Config object.
582 602
583 603 After loading, any arguments that are not key-value or
584 604 flags will be stored in self.extra_args - a list of
585 605 unparsed command-line arguments. This is used for
586 606 arguments such as input files or subcommands.
587 607
588 608 Parameters
589 609 ----------
590 610 argv : list, optional
591 611 A list that has the form of sys.argv[1:] which has unicode
592 612 elements of the form u"key=value". If this is None (default),
593 613 then self.argv will be used.
594 614 aliases : dict
595 615 A dict of aliases for configurable traits.
596 616 Keys are the short aliases, Values are the resolved trait.
597 617 Of the form: `{'alias' : 'Configurable.trait'}`
598 618 flags : dict
599 619 A dict of flags, keyed by str name. Values can be Config objects
600 620 or dicts. When the flag is triggered, The config is loaded as
601 621 `self.config.update(cfg)`.
602 622 """
603 623 self.clear()
604 624 if argv is None:
605 625 argv = self.argv
606 626 if aliases is None:
607 627 aliases = self.aliases
608 628 if flags is None:
609 629 flags = self.flags
610 630
611 631 # ensure argv is a list of unicode strings:
612 632 uargv = self._decode_argv(argv)
613 633 for idx,raw in enumerate(uargv):
614 634 # strip leading '-'
615 635 item = raw.lstrip('-')
616 636
617 637 if raw == '--':
618 638 # don't parse arguments after '--'
619 639 # this is useful for relaying arguments to scripts, e.g.
620 640 # ipython -i foo.py --matplotlib=qt -- args after '--' go-to-foo.py
621 641 self.extra_args.extend(uargv[idx+1:])
622 642 break
623 643
624 644 if kv_pattern.match(raw):
625 645 lhs,rhs = item.split('=',1)
626 646 # Substitute longnames for aliases.
627 647 if lhs in aliases:
628 648 lhs = aliases[lhs]
629 649 if '.' not in lhs:
630 650 # probably a mistyped alias, but not technically illegal
631 651 self.log.warn("Unrecognized alias: '%s', it will probably have no effect.", raw)
632 652 try:
633 653 self._exec_config_str(lhs, rhs)
634 654 except Exception:
635 655 raise ArgumentError("Invalid argument: '%s'" % raw)
636 656
637 657 elif flag_pattern.match(raw):
638 658 if item in flags:
639 659 cfg,help = flags[item]
640 660 self._load_flag(cfg)
641 661 else:
642 662 raise ArgumentError("Unrecognized flag: '%s'"%raw)
643 663 elif raw.startswith('-'):
644 664 kv = '--'+item
645 665 if kv_pattern.match(kv):
646 666 raise ArgumentError("Invalid argument: '%s', did you mean '%s'?"%(raw, kv))
647 667 else:
648 668 raise ArgumentError("Invalid argument: '%s'"%raw)
649 669 else:
650 670 # keep all args that aren't valid in a list,
651 671 # in case our parent knows what to do with them.
652 672 self.extra_args.append(item)
653 673 return self.config
654 674
655 675 class ArgParseConfigLoader(CommandLineConfigLoader):
656 676 """A loader that uses the argparse module to load from the command line."""
657 677
658 678 def __init__(self, argv=None, aliases=None, flags=None, log=None, *parser_args, **parser_kw):
659 679 """Create a config loader for use with argparse.
660 680
661 681 Parameters
662 682 ----------
663 683
664 684 argv : optional, list
665 685 If given, used to read command-line arguments from, otherwise
666 686 sys.argv[1:] is used.
667 687
668 688 parser_args : tuple
669 689 A tuple of positional arguments that will be passed to the
670 690 constructor of :class:`argparse.ArgumentParser`.
671 691
672 692 parser_kw : dict
673 693 A tuple of keyword arguments that will be passed to the
674 694 constructor of :class:`argparse.ArgumentParser`.
675 695
676 696 Returns
677 697 -------
678 698 config : Config
679 699 The resulting Config object.
680 700 """
681 701 super(CommandLineConfigLoader, self).__init__(log=log)
682 702 self.clear()
683 703 if argv is None:
684 704 argv = sys.argv[1:]
685 705 self.argv = argv
686 706 self.aliases = aliases or {}
687 707 self.flags = flags or {}
688 708
689 709 self.parser_args = parser_args
690 710 self.version = parser_kw.pop("version", None)
691 711 kwargs = dict(argument_default=argparse.SUPPRESS)
692 712 kwargs.update(parser_kw)
693 713 self.parser_kw = kwargs
694 714
695 715 def load_config(self, argv=None, aliases=None, flags=None):
696 716 """Parse command line arguments and return as a Config object.
697 717
698 718 Parameters
699 719 ----------
700 720
701 721 args : optional, list
702 722 If given, a list with the structure of sys.argv[1:] to parse
703 723 arguments from. If not given, the instance's self.argv attribute
704 724 (given at construction time) is used."""
705 725 self.clear()
706 726 if argv is None:
707 727 argv = self.argv
708 728 if aliases is None:
709 729 aliases = self.aliases
710 730 if flags is None:
711 731 flags = self.flags
712 732 self._create_parser(aliases, flags)
713 733 self._parse_args(argv)
714 734 self._convert_to_config()
715 735 return self.config
716 736
717 737 def get_extra_args(self):
718 738 if hasattr(self, 'extra_args'):
719 739 return self.extra_args
720 740 else:
721 741 return []
722 742
723 743 def _create_parser(self, aliases=None, flags=None):
724 744 self.parser = ArgumentParser(*self.parser_args, **self.parser_kw)
725 745 self._add_arguments(aliases, flags)
726 746
727 747 def _add_arguments(self, aliases=None, flags=None):
728 748 raise NotImplementedError("subclasses must implement _add_arguments")
729 749
730 750 def _parse_args(self, args):
731 751 """self.parser->self.parsed_data"""
732 752 # decode sys.argv to support unicode command-line options
733 753 enc = DEFAULT_ENCODING
734 754 uargs = [py3compat.cast_unicode(a, enc) for a in args]
735 755 self.parsed_data, self.extra_args = self.parser.parse_known_args(uargs)
736 756
737 757 def _convert_to_config(self):
738 758 """self.parsed_data->self.config"""
739 759 for k, v in iteritems(vars(self.parsed_data)):
740 760 exec("self.config.%s = v"%k, locals(), globals())
741 761
742 762 class KVArgParseConfigLoader(ArgParseConfigLoader):
743 763 """A config loader that loads aliases and flags with argparse,
744 764 but will use KVLoader for the rest. This allows better parsing
745 765 of common args, such as `ipython -c 'print 5'`, but still gets
746 766 arbitrary config with `ipython --InteractiveShell.use_readline=False`"""
747 767
748 768 def _add_arguments(self, aliases=None, flags=None):
749 769 self.alias_flags = {}
750 770 # print aliases, flags
751 771 if aliases is None:
752 772 aliases = self.aliases
753 773 if flags is None:
754 774 flags = self.flags
755 775 paa = self.parser.add_argument
756 776 for key,value in iteritems(aliases):
757 777 if key in flags:
758 778 # flags
759 779 nargs = '?'
760 780 else:
761 781 nargs = None
762 782 if len(key) is 1:
763 783 paa('-'+key, '--'+key, type=unicode_type, dest=value, nargs=nargs)
764 784 else:
765 785 paa('--'+key, type=unicode_type, dest=value, nargs=nargs)
766 786 for key, (value, help) in iteritems(flags):
767 787 if key in self.aliases:
768 788 #
769 789 self.alias_flags[self.aliases[key]] = value
770 790 continue
771 791 if len(key) is 1:
772 792 paa('-'+key, '--'+key, action='append_const', dest='_flags', const=value)
773 793 else:
774 794 paa('--'+key, action='append_const', dest='_flags', const=value)
775 795
776 796 def _convert_to_config(self):
777 797 """self.parsed_data->self.config, parse unrecognized extra args via KVLoader."""
778 798 # remove subconfigs list from namespace before transforming the Namespace
779 799 if '_flags' in self.parsed_data:
780 800 subcs = self.parsed_data._flags
781 801 del self.parsed_data._flags
782 802 else:
783 803 subcs = []
784 804
785 805 for k, v in iteritems(vars(self.parsed_data)):
786 806 if v is None:
787 807 # it was a flag that shares the name of an alias
788 808 subcs.append(self.alias_flags[k])
789 809 else:
790 810 # eval the KV assignment
791 811 self._exec_config_str(k, v)
792 812
793 813 for subc in subcs:
794 814 self._load_flag(subc)
795 815
796 816 if self.extra_args:
797 817 sub_parser = KeyValueConfigLoader(log=self.log)
798 818 sub_parser.load_config(self.extra_args)
799 819 self.config.merge(sub_parser.config)
800 820 self.extra_args = sub_parser.extra_args
801 821
802 822
803 823 def load_pyconfig_files(config_files, path):
804 824 """Load multiple Python config files, merging each of them in turn.
805 825
806 826 Parameters
807 827 ==========
808 828 config_files : list of str
809 829 List of config files names to load and merge into the config.
810 830 path : unicode
811 831 The full path to the location of the config files.
812 832 """
813 833 config = Config()
814 834 for cf in config_files:
815 835 loader = PyFileConfigLoader(cf, path=path)
816 836 try:
817 837 next_config = loader.load_config()
818 838 except ConfigFileNotFound:
819 839 pass
820 840 except:
821 841 raise
822 842 else:
823 843 config.merge(next_config)
824 844 return config
@@ -1,193 +1,198 b''
1 1 # coding: utf-8
2 2 """
3 3 Tests for IPython.config.application.Application
4
5 Authors:
6
7 * Brian Granger
8 4 """
9 5
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2008-2011 The IPython Development Team
12 #
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
15 #-----------------------------------------------------------------------------
16
17 #-----------------------------------------------------------------------------
18 # Imports
19 #-----------------------------------------------------------------------------
6 # Copyright (c) IPython Development Team.
7 # Distributed under the terms of the Modified BSD License.
20 8
21 9 import logging
10 import os
22 11 from io import StringIO
23 12 from unittest import TestCase
24 13
14 pjoin = os.path.join
15
25 16 import nose.tools as nt
26 17
27 18 from IPython.config.configurable import Configurable
28 19 from IPython.config.loader import Config
29 20
30 21 from IPython.config.application import (
31 22 Application
32 23 )
33 24
25 from IPython.utils.tempdir import TemporaryDirectory
34 26 from IPython.utils.traitlets import (
35 27 Bool, Unicode, Integer, List, Dict
36 28 )
37 29
38 #-----------------------------------------------------------------------------
39 # Code
40 #-----------------------------------------------------------------------------
41 30
42 31 class Foo(Configurable):
43 32
44 33 i = Integer(0, config=True, help="The integer i.")
45 34 j = Integer(1, config=True, help="The integer j.")
46 35 name = Unicode(u'Brian', config=True, help="First name.")
47 36
48 37
49 38 class Bar(Configurable):
50 39
51 40 b = Integer(0, config=True, help="The integer b.")
52 41 enabled = Bool(True, config=True, help="Enable bar.")
53 42
54 43
55 44 class MyApp(Application):
56 45
57 46 name = Unicode(u'myapp')
58 47 running = Bool(False, config=True,
59 48 help="Is the app running?")
60 49 classes = List([Bar, Foo])
61 50 config_file = Unicode(u'', config=True,
62 51 help="Load this config file")
63 52
64 53 aliases = Dict({
65 54 'i' : 'Foo.i',
66 55 'j' : 'Foo.j',
67 56 'name' : 'Foo.name',
68 57 'enabled' : 'Bar.enabled',
69 58 'log-level' : 'Application.log_level',
70 59 })
71 60
72 61 flags = Dict(dict(enable=({'Bar': {'enabled' : True}}, "Set Bar.enabled to True"),
73 62 disable=({'Bar': {'enabled' : False}}, "Set Bar.enabled to False"),
74 63 crit=({'Application' : {'log_level' : logging.CRITICAL}},
75 64 "set level=CRITICAL"),
76 65 ))
77 66
78 67 def init_foo(self):
79 68 self.foo = Foo(parent=self)
80 69
81 70 def init_bar(self):
82 71 self.bar = Bar(parent=self)
83 72
84 73
85 74 class TestApplication(TestCase):
86 75
87 76 def test_log(self):
88 77 stream = StringIO()
89 78 app = MyApp(log_level=logging.INFO)
90 79 handler = logging.StreamHandler(stream)
91 80 # trigger reconstruction of the log formatter
92 81 app.log.handlers = [handler]
93 82 app.log_format = "%(message)s"
94 83 app.log.info("hello")
95 84 nt.assert_in("hello", stream.getvalue())
96 85
97 86 def test_basic(self):
98 87 app = MyApp()
99 88 self.assertEqual(app.name, u'myapp')
100 89 self.assertEqual(app.running, False)
101 90 self.assertEqual(app.classes, [MyApp,Bar,Foo])
102 91 self.assertEqual(app.config_file, u'')
103 92
104 93 def test_config(self):
105 94 app = MyApp()
106 95 app.parse_command_line(["--i=10","--Foo.j=10","--enabled=False","--log-level=50"])
107 96 config = app.config
108 97 self.assertEqual(config.Foo.i, 10)
109 98 self.assertEqual(config.Foo.j, 10)
110 99 self.assertEqual(config.Bar.enabled, False)
111 100 self.assertEqual(config.MyApp.log_level,50)
112 101
113 102 def test_config_propagation(self):
114 103 app = MyApp()
115 104 app.parse_command_line(["--i=10","--Foo.j=10","--enabled=False","--log-level=50"])
116 105 app.init_foo()
117 106 app.init_bar()
118 107 self.assertEqual(app.foo.i, 10)
119 108 self.assertEqual(app.foo.j, 10)
120 109 self.assertEqual(app.bar.enabled, False)
121 110
122 111 def test_flags(self):
123 112 app = MyApp()
124 113 app.parse_command_line(["--disable"])
125 114 app.init_bar()
126 115 self.assertEqual(app.bar.enabled, False)
127 116 app.parse_command_line(["--enable"])
128 117 app.init_bar()
129 118 self.assertEqual(app.bar.enabled, True)
130 119
131 120 def test_aliases(self):
132 121 app = MyApp()
133 122 app.parse_command_line(["--i=5", "--j=10"])
134 123 app.init_foo()
135 124 self.assertEqual(app.foo.i, 5)
136 125 app.init_foo()
137 126 self.assertEqual(app.foo.j, 10)
138 127
139 128 def test_flag_clobber(self):
140 129 """test that setting flags doesn't clobber existing settings"""
141 130 app = MyApp()
142 131 app.parse_command_line(["--Bar.b=5", "--disable"])
143 132 app.init_bar()
144 133 self.assertEqual(app.bar.enabled, False)
145 134 self.assertEqual(app.bar.b, 5)
146 135 app.parse_command_line(["--enable", "--Bar.b=10"])
147 136 app.init_bar()
148 137 self.assertEqual(app.bar.enabled, True)
149 138 self.assertEqual(app.bar.b, 10)
150 139
151 140 def test_flatten_flags(self):
152 141 cfg = Config()
153 142 cfg.MyApp.log_level = logging.WARN
154 143 app = MyApp()
155 144 app.update_config(cfg)
156 145 self.assertEqual(app.log_level, logging.WARN)
157 146 self.assertEqual(app.config.MyApp.log_level, logging.WARN)
158 147 app.initialize(["--crit"])
159 148 self.assertEqual(app.log_level, logging.CRITICAL)
160 149 # this would be app.config.Application.log_level if it failed:
161 150 self.assertEqual(app.config.MyApp.log_level, logging.CRITICAL)
162 151
163 152 def test_flatten_aliases(self):
164 153 cfg = Config()
165 154 cfg.MyApp.log_level = logging.WARN
166 155 app = MyApp()
167 156 app.update_config(cfg)
168 157 self.assertEqual(app.log_level, logging.WARN)
169 158 self.assertEqual(app.config.MyApp.log_level, logging.WARN)
170 159 app.initialize(["--log-level", "CRITICAL"])
171 160 self.assertEqual(app.log_level, logging.CRITICAL)
172 161 # this would be app.config.Application.log_level if it failed:
173 162 self.assertEqual(app.config.MyApp.log_level, "CRITICAL")
174 163
175 164 def test_extra_args(self):
176 165 app = MyApp()
177 166 app.parse_command_line(["--Bar.b=5", 'extra', "--disable", 'args'])
178 167 app.init_bar()
179 168 self.assertEqual(app.bar.enabled, False)
180 169 self.assertEqual(app.bar.b, 5)
181 170 self.assertEqual(app.extra_args, ['extra', 'args'])
182 171 app = MyApp()
183 172 app.parse_command_line(["--Bar.b=5", '--', 'extra', "--disable", 'args'])
184 173 app.init_bar()
185 174 self.assertEqual(app.bar.enabled, True)
186 175 self.assertEqual(app.bar.b, 5)
187 176 self.assertEqual(app.extra_args, ['extra', '--disable', 'args'])
188 177
189 178 def test_unicode_argv(self):
190 179 app = MyApp()
191 180 app.parse_command_line(['ünîcødé'])
192
181
182 def test_multi_file(self):
183 app = MyApp()
184 app.log = logging.getLogger()
185 name = 'config.py'
186 with TemporaryDirectory('_1') as td1:
187 with open(pjoin(td1, name), 'w') as f1:
188 f1.write("get_config().MyApp.Bar.b = 1")
189 with TemporaryDirectory('_2') as td2:
190 with open(pjoin(td2, name), 'w') as f2:
191 f2.write("get_config().MyApp.Bar.b = 2")
192 app.load_config_file(name, path=[td2, td1])
193 app.init_bar()
194 self.assertEqual(app.bar.b, 2)
195 app.load_config_file(name, path=[td1, td2])
196 app.init_bar()
197 self.assertEqual(app.bar.b, 1)
193 198
@@ -1,396 +1,404 b''
1 1 # encoding: utf-8
2 """
3 Tests for IPython.config.loader
4
5 Authors:
6
7 * Brian Granger
8 * Fernando Perez (design help)
9 """
2 """Tests for IPython.config.loader"""
10 3
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008 The IPython Development Team
13 #
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
17
18 #-----------------------------------------------------------------------------
19 # Imports
20 #-----------------------------------------------------------------------------
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
21 6
22 7 import os
23 8 import pickle
24 9 import sys
25 import json
26 10
27 11 from tempfile import mkstemp
28 12 from unittest import TestCase
29 13
30 14 from nose import SkipTest
31 15 import nose.tools as nt
32 16
33 17
34 18
35 19 from IPython.config.loader import (
36 20 Config,
37 21 LazyConfigValue,
38 22 PyFileConfigLoader,
39 23 JSONFileConfigLoader,
40 24 KeyValueConfigLoader,
41 25 ArgParseConfigLoader,
42 26 KVArgParseConfigLoader,
43 27 ConfigError,
44 28 )
45 29
46 #-----------------------------------------------------------------------------
47 # Actual tests
48 #-----------------------------------------------------------------------------
49
50 30
51 31 pyfile = """
52 32 c = get_config()
53 33 c.a=10
54 34 c.b=20
55 35 c.Foo.Bar.value=10
56 36 c.Foo.Bam.value=list(range(10)) # list() is just so it's the same on Python 3
57 37 c.D.C.value='hi there'
58 38 """
59 39
60 40 json1file = """
61 41 {
62 42 "version": 1,
63 43 "a": 10,
64 44 "b": 20,
65 45 "Foo": {
66 46 "Bam": {
67 47 "value": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
68 48 },
69 49 "Bar": {
70 50 "value": 10
71 51 }
72 52 },
73 53 "D": {
74 54 "C": {
75 55 "value": "hi there"
76 56 }
77 57 }
78 58 }
79 59 """
80 60
81 61 # should not load
82 62 json2file = """
83 63 {
84 64 "version": 2
85 65 }
86 66 """
87 67
88 68 import logging
89 69 log = logging.getLogger('devnull')
90 70 log.setLevel(0)
91 71
92 72 class TestFileCL(TestCase):
93 73
94 74 def _check_conf(self, config):
95 75 self.assertEqual(config.a, 10)
96 76 self.assertEqual(config.b, 20)
97 77 self.assertEqual(config.Foo.Bar.value, 10)
98 78 self.assertEqual(config.Foo.Bam.value, list(range(10)))
99 79 self.assertEqual(config.D.C.value, 'hi there')
100 80
101 81 def test_python(self):
102 82 fd, fname = mkstemp('.py')
103 83 f = os.fdopen(fd, 'w')
104 84 f.write(pyfile)
105 85 f.close()
106 86 # Unlink the file
107 87 cl = PyFileConfigLoader(fname, log=log)
108 88 config = cl.load_config()
109 89 self._check_conf(config)
110 90
111 91 def test_json(self):
112 92 fd, fname = mkstemp('.json')
113 93 f = os.fdopen(fd, 'w')
114 94 f.write(json1file)
115 95 f.close()
116 96 # Unlink the file
117 97 cl = JSONFileConfigLoader(fname, log=log)
118 98 config = cl.load_config()
119 99 self._check_conf(config)
100
101 def test_collision(self):
102 a = Config()
103 b = Config()
104 self.assertEqual(a.collisions(b), {})
105 a.A.trait1 = 1
106 b.A.trait2 = 2
107 self.assertEqual(a.collisions(b), {})
108 b.A.trait1 = 1
109 self.assertEqual(a.collisions(b), {})
110 b.A.trait1 = 0
111 self.assertEqual(a.collisions(b), {
112 'A': {
113 'trait1': "1 ignored, using 0",
114 }
115 })
116 self.assertEqual(b.collisions(a), {
117 'A': {
118 'trait1': "0 ignored, using 1",
119 }
120 })
121 a.A.trait2 = 3
122 self.assertEqual(b.collisions(a), {
123 'A': {
124 'trait1': "0 ignored, using 1",
125 'trait2': "2 ignored, using 3",
126 }
127 })
120 128
121 129 def test_v2raise(self):
122 130 fd, fname = mkstemp('.json')
123 131 f = os.fdopen(fd, 'w')
124 132 f.write(json2file)
125 133 f.close()
126 134 # Unlink the file
127 135 cl = JSONFileConfigLoader(fname, log=log)
128 136 with nt.assert_raises(ValueError):
129 137 cl.load_config()
130 138
131 139
132 140 class MyLoader1(ArgParseConfigLoader):
133 141 def _add_arguments(self, aliases=None, flags=None):
134 142 p = self.parser
135 143 p.add_argument('-f', '--foo', dest='Global.foo', type=str)
136 144 p.add_argument('-b', dest='MyClass.bar', type=int)
137 145 p.add_argument('-n', dest='n', action='store_true')
138 146 p.add_argument('Global.bam', type=str)
139 147
140 148 class MyLoader2(ArgParseConfigLoader):
141 149 def _add_arguments(self, aliases=None, flags=None):
142 150 subparsers = self.parser.add_subparsers(dest='subparser_name')
143 151 subparser1 = subparsers.add_parser('1')
144 152 subparser1.add_argument('-x',dest='Global.x')
145 153 subparser2 = subparsers.add_parser('2')
146 154 subparser2.add_argument('y')
147 155
148 156 class TestArgParseCL(TestCase):
149 157
150 158 def test_basic(self):
151 159 cl = MyLoader1()
152 160 config = cl.load_config('-f hi -b 10 -n wow'.split())
153 161 self.assertEqual(config.Global.foo, 'hi')
154 162 self.assertEqual(config.MyClass.bar, 10)
155 163 self.assertEqual(config.n, True)
156 164 self.assertEqual(config.Global.bam, 'wow')
157 165 config = cl.load_config(['wow'])
158 166 self.assertEqual(list(config.keys()), ['Global'])
159 167 self.assertEqual(list(config.Global.keys()), ['bam'])
160 168 self.assertEqual(config.Global.bam, 'wow')
161 169
162 170 def test_add_arguments(self):
163 171 cl = MyLoader2()
164 172 config = cl.load_config('2 frobble'.split())
165 173 self.assertEqual(config.subparser_name, '2')
166 174 self.assertEqual(config.y, 'frobble')
167 175 config = cl.load_config('1 -x frobble'.split())
168 176 self.assertEqual(config.subparser_name, '1')
169 177 self.assertEqual(config.Global.x, 'frobble')
170 178
171 179 def test_argv(self):
172 180 cl = MyLoader1(argv='-f hi -b 10 -n wow'.split())
173 181 config = cl.load_config()
174 182 self.assertEqual(config.Global.foo, 'hi')
175 183 self.assertEqual(config.MyClass.bar, 10)
176 184 self.assertEqual(config.n, True)
177 185 self.assertEqual(config.Global.bam, 'wow')
178 186
179 187
180 188 class TestKeyValueCL(TestCase):
181 189 klass = KeyValueConfigLoader
182 190
183 191 def test_basic(self):
184 192 cl = self.klass(log=log)
185 193 argv = ['--'+s.strip('c.') for s in pyfile.split('\n')[2:-1]]
186 194 config = cl.load_config(argv)
187 195 self.assertEqual(config.a, 10)
188 196 self.assertEqual(config.b, 20)
189 197 self.assertEqual(config.Foo.Bar.value, 10)
190 198 self.assertEqual(config.Foo.Bam.value, list(range(10)))
191 199 self.assertEqual(config.D.C.value, 'hi there')
192 200
193 201 def test_expanduser(self):
194 202 cl = self.klass(log=log)
195 203 argv = ['--a=~/1/2/3', '--b=~', '--c=~/', '--d="~/"']
196 204 config = cl.load_config(argv)
197 205 self.assertEqual(config.a, os.path.expanduser('~/1/2/3'))
198 206 self.assertEqual(config.b, os.path.expanduser('~'))
199 207 self.assertEqual(config.c, os.path.expanduser('~/'))
200 208 self.assertEqual(config.d, '~/')
201 209
202 210 def test_extra_args(self):
203 211 cl = self.klass(log=log)
204 212 config = cl.load_config(['--a=5', 'b', '--c=10', 'd'])
205 213 self.assertEqual(cl.extra_args, ['b', 'd'])
206 214 self.assertEqual(config.a, 5)
207 215 self.assertEqual(config.c, 10)
208 216 config = cl.load_config(['--', '--a=5', '--c=10'])
209 217 self.assertEqual(cl.extra_args, ['--a=5', '--c=10'])
210 218
211 219 def test_unicode_args(self):
212 220 cl = self.klass(log=log)
213 221 argv = [u'--a=épsîlön']
214 222 config = cl.load_config(argv)
215 223 self.assertEqual(config.a, u'épsîlön')
216 224
217 225 def test_unicode_bytes_args(self):
218 226 uarg = u'--a=é'
219 227 try:
220 228 barg = uarg.encode(sys.stdin.encoding)
221 229 except (TypeError, UnicodeEncodeError):
222 230 raise SkipTest("sys.stdin.encoding can't handle 'é'")
223 231
224 232 cl = self.klass(log=log)
225 233 config = cl.load_config([barg])
226 234 self.assertEqual(config.a, u'é')
227 235
228 236 def test_unicode_alias(self):
229 237 cl = self.klass(log=log)
230 238 argv = [u'--a=épsîlön']
231 239 config = cl.load_config(argv, aliases=dict(a='A.a'))
232 240 self.assertEqual(config.A.a, u'épsîlön')
233 241
234 242
235 243 class TestArgParseKVCL(TestKeyValueCL):
236 244 klass = KVArgParseConfigLoader
237 245
238 246 def test_expanduser2(self):
239 247 cl = self.klass(log=log)
240 248 argv = ['-a', '~/1/2/3', '--b', "'~/1/2/3'"]
241 249 config = cl.load_config(argv, aliases=dict(a='A.a', b='A.b'))
242 250 self.assertEqual(config.A.a, os.path.expanduser('~/1/2/3'))
243 251 self.assertEqual(config.A.b, '~/1/2/3')
244 252
245 253 def test_eval(self):
246 254 cl = self.klass(log=log)
247 255 argv = ['-c', 'a=5']
248 256 config = cl.load_config(argv, aliases=dict(c='A.c'))
249 257 self.assertEqual(config.A.c, u"a=5")
250 258
251 259
252 260 class TestConfig(TestCase):
253 261
254 262 def test_setget(self):
255 263 c = Config()
256 264 c.a = 10
257 265 self.assertEqual(c.a, 10)
258 266 self.assertEqual('b' in c, False)
259 267
260 268 def test_auto_section(self):
261 269 c = Config()
262 270 self.assertNotIn('A', c)
263 271 assert not c._has_section('A')
264 272 A = c.A
265 273 A.foo = 'hi there'
266 274 self.assertIn('A', c)
267 275 assert c._has_section('A')
268 276 self.assertEqual(c.A.foo, 'hi there')
269 277 del c.A
270 278 self.assertEqual(c.A, Config())
271 279
272 280 def test_merge_doesnt_exist(self):
273 281 c1 = Config()
274 282 c2 = Config()
275 283 c2.bar = 10
276 284 c2.Foo.bar = 10
277 285 c1.merge(c2)
278 286 self.assertEqual(c1.Foo.bar, 10)
279 287 self.assertEqual(c1.bar, 10)
280 288 c2.Bar.bar = 10
281 289 c1.merge(c2)
282 290 self.assertEqual(c1.Bar.bar, 10)
283 291
284 292 def test_merge_exists(self):
285 293 c1 = Config()
286 294 c2 = Config()
287 295 c1.Foo.bar = 10
288 296 c1.Foo.bam = 30
289 297 c2.Foo.bar = 20
290 298 c2.Foo.wow = 40
291 299 c1.merge(c2)
292 300 self.assertEqual(c1.Foo.bam, 30)
293 301 self.assertEqual(c1.Foo.bar, 20)
294 302 self.assertEqual(c1.Foo.wow, 40)
295 303 c2.Foo.Bam.bam = 10
296 304 c1.merge(c2)
297 305 self.assertEqual(c1.Foo.Bam.bam, 10)
298 306
299 307 def test_deepcopy(self):
300 308 c1 = Config()
301 309 c1.Foo.bar = 10
302 310 c1.Foo.bam = 30
303 311 c1.a = 'asdf'
304 312 c1.b = range(10)
305 313 import copy
306 314 c2 = copy.deepcopy(c1)
307 315 self.assertEqual(c1, c2)
308 316 self.assertTrue(c1 is not c2)
309 317 self.assertTrue(c1.Foo is not c2.Foo)
310 318
311 319 def test_builtin(self):
312 320 c1 = Config()
313 321 c1.format = "json"
314 322
315 323 def test_fromdict(self):
316 324 c1 = Config({'Foo' : {'bar' : 1}})
317 325 self.assertEqual(c1.Foo.__class__, Config)
318 326 self.assertEqual(c1.Foo.bar, 1)
319 327
320 328 def test_fromdictmerge(self):
321 329 c1 = Config()
322 330 c2 = Config({'Foo' : {'bar' : 1}})
323 331 c1.merge(c2)
324 332 self.assertEqual(c1.Foo.__class__, Config)
325 333 self.assertEqual(c1.Foo.bar, 1)
326 334
327 335 def test_fromdictmerge2(self):
328 336 c1 = Config({'Foo' : {'baz' : 2}})
329 337 c2 = Config({'Foo' : {'bar' : 1}})
330 338 c1.merge(c2)
331 339 self.assertEqual(c1.Foo.__class__, Config)
332 340 self.assertEqual(c1.Foo.bar, 1)
333 341 self.assertEqual(c1.Foo.baz, 2)
334 342 self.assertNotIn('baz', c2.Foo)
335 343
336 344 def test_contains(self):
337 345 c1 = Config({'Foo' : {'baz' : 2}})
338 346 c2 = Config({'Foo' : {'bar' : 1}})
339 347 self.assertIn('Foo', c1)
340 348 self.assertIn('Foo.baz', c1)
341 349 self.assertIn('Foo.bar', c2)
342 350 self.assertNotIn('Foo.bar', c1)
343 351
344 352 def test_pickle_config(self):
345 353 cfg = Config()
346 354 cfg.Foo.bar = 1
347 355 pcfg = pickle.dumps(cfg)
348 356 cfg2 = pickle.loads(pcfg)
349 357 self.assertEqual(cfg2, cfg)
350 358
351 359 def test_getattr_section(self):
352 360 cfg = Config()
353 361 self.assertNotIn('Foo', cfg)
354 362 Foo = cfg.Foo
355 363 assert isinstance(Foo, Config)
356 364 self.assertIn('Foo', cfg)
357 365
358 366 def test_getitem_section(self):
359 367 cfg = Config()
360 368 self.assertNotIn('Foo', cfg)
361 369 Foo = cfg['Foo']
362 370 assert isinstance(Foo, Config)
363 371 self.assertIn('Foo', cfg)
364 372
365 373 def test_getattr_not_section(self):
366 374 cfg = Config()
367 375 self.assertNotIn('foo', cfg)
368 376 foo = cfg.foo
369 377 assert isinstance(foo, LazyConfigValue)
370 378 self.assertIn('foo', cfg)
371 379
372 380 def test_getattr_private_missing(self):
373 381 cfg = Config()
374 382 self.assertNotIn('_repr_html_', cfg)
375 383 with self.assertRaises(AttributeError):
376 384 _ = cfg._repr_html_
377 385 self.assertNotIn('_repr_html_', cfg)
378 386 self.assertEqual(len(cfg), 0)
379 387
380 388 def test_getitem_not_section(self):
381 389 cfg = Config()
382 390 self.assertNotIn('foo', cfg)
383 391 foo = cfg['foo']
384 392 assert isinstance(foo, LazyConfigValue)
385 393 self.assertIn('foo', cfg)
386 394
387 395 def test_merge_copies(self):
388 396 c = Config()
389 397 c2 = Config()
390 398 c2.Foo.trait = []
391 399 c.merge(c2)
392 400 c2.Foo.trait.append(1)
393 401 self.assertIsNot(c.Foo, c2.Foo)
394 402 self.assertEqual(c.Foo.trait, [])
395 403 self.assertEqual(c2.Foo.trait, [1])
396 404
@@ -1,353 +1,345 b''
1 1 """ A minimal application base mixin for all ZMQ based IPython frontends.
2 2
3 3 This is not a complete console app, as subprocess will not be able to receive
4 4 input, there is no real readline support, among other limitations. This is a
5 5 refactoring of what used to be the IPython/qt/console/qtconsoleapp.py
6 6 """
7 7 # Copyright (c) IPython Development Team.
8 8 # Distributed under the terms of the Modified BSD License.
9 9
10 #-----------------------------------------------------------------------------
11 # Imports
12 #-----------------------------------------------------------------------------
13
14 # stdlib imports
15 10 import atexit
16 11 import os
17 12 import signal
18 13 import sys
19 14 import uuid
20 15
21 16
22 # Local imports
23 17 from IPython.config.application import boolean_flag
24 18 from IPython.core.profiledir import ProfileDir
25 19 from IPython.kernel.blocking import BlockingKernelClient
26 20 from IPython.kernel import KernelManager
27 21 from IPython.kernel import tunnel_to_kernel, find_connection_file, swallow_argv
28 22 from IPython.kernel.kernelspec import NoSuchKernel
29 23 from IPython.utils.path import filefind
30 24 from IPython.utils.traitlets import (
31 25 Dict, List, Unicode, CUnicode, CBool, Any
32 26 )
33 27 from IPython.kernel.zmq.kernelapp import (
34 28 kernel_flags,
35 29 kernel_aliases,
36 30 IPKernelApp
37 31 )
38 32 from IPython.kernel.zmq.pylab.config import InlineBackend
39 33 from IPython.kernel.zmq.session import Session, default_secure
40 34 from IPython.kernel.zmq.zmqshell import ZMQInteractiveShell
41 35 from IPython.kernel.connect import ConnectionFileMixin
42 36
43 #-----------------------------------------------------------------------------
44 # Network Constants
45 #-----------------------------------------------------------------------------
46
47 37 from IPython.utils.localinterfaces import localhost
48 38
49 39 #-----------------------------------------------------------------------------
50 # Globals
51 #-----------------------------------------------------------------------------
52
53
54 #-----------------------------------------------------------------------------
55 40 # Aliases and Flags
56 41 #-----------------------------------------------------------------------------
57 42
58 43 flags = dict(kernel_flags)
59 44
60 45 # the flags that are specific to the frontend
61 46 # these must be scrubbed before being passed to the kernel,
62 47 # or it will raise an error on unrecognized flags
63 48 app_flags = {
64 49 'existing' : ({'IPythonConsoleApp' : {'existing' : 'kernel*.json'}},
65 50 "Connect to an existing kernel. If no argument specified, guess most recent"),
66 51 }
67 52 app_flags.update(boolean_flag(
68 53 'confirm-exit', 'IPythonConsoleApp.confirm_exit',
69 54 """Set to display confirmation dialog on exit. You can always use 'exit' or 'quit',
70 55 to force a direct exit without any confirmation.
71 56 """,
72 57 """Don't prompt the user when exiting. This will terminate the kernel
73 58 if it is owned by the frontend, and leave it alive if it is external.
74 59 """
75 60 ))
76 61 flags.update(app_flags)
77 62
78 63 aliases = dict(kernel_aliases)
79 64
80 65 # also scrub aliases from the frontend
81 66 app_aliases = dict(
82 67 ip = 'IPythonConsoleApp.ip',
83 68 transport = 'IPythonConsoleApp.transport',
84 69 hb = 'IPythonConsoleApp.hb_port',
85 70 shell = 'IPythonConsoleApp.shell_port',
86 71 iopub = 'IPythonConsoleApp.iopub_port',
87 72 stdin = 'IPythonConsoleApp.stdin_port',
88 73 existing = 'IPythonConsoleApp.existing',
89 74 f = 'IPythonConsoleApp.connection_file',
90 75
91 76 kernel = 'IPythonConsoleApp.kernel_name',
92 77
93 78 ssh = 'IPythonConsoleApp.sshserver',
94 79 )
95 80 aliases.update(app_aliases)
96 81
97 82 #-----------------------------------------------------------------------------
98 83 # Classes
99 84 #-----------------------------------------------------------------------------
100 85
101 #-----------------------------------------------------------------------------
102 # IPythonConsole
103 #-----------------------------------------------------------------------------
104
105 classes = [IPKernelApp, ZMQInteractiveShell, KernelManager, ProfileDir, Session, InlineBackend]
86 classes = [KernelManager, ProfileDir, Session]
106 87
107 88 class IPythonConsoleApp(ConnectionFileMixin):
108 89 name = 'ipython-console-mixin'
109 90
110 91 description = """
111 92 The IPython Mixin Console.
112 93
113 94 This class contains the common portions of console client (QtConsole,
114 95 ZMQ-based terminal console, etc). It is not a full console, in that
115 96 launched terminal subprocesses will not be able to accept input.
116 97
117 98 The Console using this mixing supports various extra features beyond
118 99 the single-process Terminal IPython shell, such as connecting to
119 100 existing kernel, via:
120 101
121 102 ipython <appname> --existing
122 103
123 104 as well as tunnel via SSH
124 105
125 106 """
126 107
127 108 classes = classes
128 109 flags = Dict(flags)
129 110 aliases = Dict(aliases)
130 111 kernel_manager_class = KernelManager
131 112 kernel_client_class = BlockingKernelClient
132 113
133 114 kernel_argv = List(Unicode)
134 115 # frontend flags&aliases to be stripped when building kernel_argv
135 116 frontend_flags = Any(app_flags)
136 117 frontend_aliases = Any(app_aliases)
137 118
138 119 # create requested profiles by default, if they don't exist:
139 120 auto_create = CBool(True)
140 121 # connection info:
141 122
142 123 sshserver = Unicode('', config=True,
143 124 help="""The SSH server to use to connect to the kernel.""")
144 125 sshkey = Unicode('', config=True,
145 126 help="""Path to the ssh key to use for logging in to the ssh server.""")
146 127
147 128 def _connection_file_default(self):
148 129 return 'kernel-%i.json' % os.getpid()
149 130
150 131 existing = CUnicode('', config=True,
151 132 help="""Connect to an already running kernel""")
152 133
153 134 kernel_name = Unicode('python', config=True,
154 135 help="""The name of the default kernel to start.""")
155 136
156 137 confirm_exit = CBool(True, config=True,
157 138 help="""
158 139 Set to display confirmation dialog on exit. You can always use 'exit' or 'quit',
159 140 to force a direct exit without any confirmation.""",
160 141 )
161
162
142
143 @property
144 def help_classes(self):
145 """ConsoleApps can configure kernels on the command-line
146
147 But this shouldn't be written to a file
148 """
149 return self.classes + [IPKernelApp] + IPKernelApp.classes
150
163 151 def build_kernel_argv(self, argv=None):
164 152 """build argv to be passed to kernel subprocess"""
165 153 if argv is None:
166 154 argv = sys.argv[1:]
167 155 self.kernel_argv = swallow_argv(argv, self.frontend_aliases, self.frontend_flags)
168 156
169 157 def init_connection_file(self):
170 158 """find the connection file, and load the info if found.
171 159
172 160 The current working directory and the current profile's security
173 161 directory will be searched for the file if it is not given by
174 162 absolute path.
175 163
176 164 When attempting to connect to an existing kernel and the `--existing`
177 165 argument does not match an existing file, it will be interpreted as a
178 166 fileglob, and the matching file in the current profile's security dir
179 167 with the latest access time will be used.
180 168
181 169 After this method is called, self.connection_file contains the *full path*
182 170 to the connection file, never just its name.
183 171 """
184 172 if self.existing:
185 173 try:
186 174 cf = find_connection_file(self.existing)
187 175 except Exception:
188 176 self.log.critical("Could not find existing kernel connection file %s", self.existing)
189 177 self.exit(1)
190 178 self.log.debug("Connecting to existing kernel: %s" % cf)
191 179 self.connection_file = cf
192 180 else:
193 181 # not existing, check if we are going to write the file
194 182 # and ensure that self.connection_file is a full path, not just the shortname
195 183 try:
196 184 cf = find_connection_file(self.connection_file)
197 185 except Exception:
198 186 # file might not exist
199 187 if self.connection_file == os.path.basename(self.connection_file):
200 188 # just shortname, put it in security dir
201 189 cf = os.path.join(self.profile_dir.security_dir, self.connection_file)
202 190 else:
203 191 cf = self.connection_file
204 192 self.connection_file = cf
205 193 try:
206 194 self.connection_file = filefind(self.connection_file, ['.', self.profile_dir.security_dir])
207 195 except IOError:
208 196 self.log.debug("Connection File not found: %s", self.connection_file)
209 197 return
210 198
211 199 # should load_connection_file only be used for existing?
212 200 # as it is now, this allows reusing ports if an existing
213 201 # file is requested
214 202 try:
215 203 self.load_connection_file()
216 204 except Exception:
217 205 self.log.error("Failed to load connection file: %r", self.connection_file, exc_info=True)
218 206 self.exit(1)
219 207
220 208 def init_ssh(self):
221 209 """set up ssh tunnels, if needed."""
222 210 if not self.existing or (not self.sshserver and not self.sshkey):
223 211 return
224 212 self.load_connection_file()
225 213
226 214 transport = self.transport
227 215 ip = self.ip
228 216
229 217 if transport != 'tcp':
230 218 self.log.error("Can only use ssh tunnels with TCP sockets, not %s", transport)
231 219 sys.exit(-1)
232 220
233 221 if self.sshkey and not self.sshserver:
234 222 # specifying just the key implies that we are connecting directly
235 223 self.sshserver = ip
236 224 ip = localhost()
237 225
238 226 # build connection dict for tunnels:
239 227 info = dict(ip=ip,
240 228 shell_port=self.shell_port,
241 229 iopub_port=self.iopub_port,
242 230 stdin_port=self.stdin_port,
243 231 hb_port=self.hb_port
244 232 )
245 233
246 234 self.log.info("Forwarding connections to %s via %s"%(ip, self.sshserver))
247 235
248 236 # tunnels return a new set of ports, which will be on localhost:
249 237 self.ip = localhost()
250 238 try:
251 239 newports = tunnel_to_kernel(info, self.sshserver, self.sshkey)
252 240 except:
253 241 # even catch KeyboardInterrupt
254 242 self.log.error("Could not setup tunnels", exc_info=True)
255 243 self.exit(1)
256 244
257 245 self.shell_port, self.iopub_port, self.stdin_port, self.hb_port = newports
258 246
259 247 cf = self.connection_file
260 248 base,ext = os.path.splitext(cf)
261 249 base = os.path.basename(base)
262 250 self.connection_file = os.path.basename(base)+'-ssh'+ext
263 251 self.log.info("To connect another client via this tunnel, use:")
264 252 self.log.info("--existing %s" % self.connection_file)
265 253
266 254 def _new_connection_file(self):
267 255 cf = ''
268 256 while not cf:
269 257 # we don't need a 128b id to distinguish kernels, use more readable
270 258 # 48b node segment (12 hex chars). Users running more than 32k simultaneous
271 259 # kernels can subclass.
272 260 ident = str(uuid.uuid4()).split('-')[-1]
273 261 cf = os.path.join(self.profile_dir.security_dir, 'kernel-%s.json' % ident)
274 262 # only keep if it's actually new. Protect against unlikely collision
275 263 # in 48b random search space
276 264 cf = cf if not os.path.exists(cf) else ''
277 265 return cf
278 266
279 267 def init_kernel_manager(self):
280 268 # Don't let Qt or ZMQ swallow KeyboardInterupts.
281 269 if self.existing:
282 270 self.kernel_manager = None
283 271 return
284 272 signal.signal(signal.SIGINT, signal.SIG_DFL)
285 273
286 274 # Create a KernelManager and start a kernel.
287 275 try:
288 276 self.kernel_manager = self.kernel_manager_class(
289 277 ip=self.ip,
290 278 session=self.session,
291 279 transport=self.transport,
292 280 shell_port=self.shell_port,
293 281 iopub_port=self.iopub_port,
294 282 stdin_port=self.stdin_port,
295 283 hb_port=self.hb_port,
296 284 connection_file=self.connection_file,
297 285 kernel_name=self.kernel_name,
298 286 parent=self,
299 287 ipython_dir=self.ipython_dir,
300 288 )
301 289 except NoSuchKernel:
302 290 self.log.critical("Could not find kernel %s", self.kernel_name)
303 291 self.exit(1)
304 292
305 293 self.kernel_manager.client_factory = self.kernel_client_class
306 self.kernel_manager.start_kernel(extra_arguments=self.kernel_argv)
294 # FIXME: remove special treatment of IPython kernels
295 kwargs = {}
296 if self.kernel_manager.ipython_kernel:
297 kwargs['extra_arguments'] = self.kernel_argv
298 self.kernel_manager.start_kernel(**kwargs)
307 299 atexit.register(self.kernel_manager.cleanup_ipc_files)
308 300
309 301 if self.sshserver:
310 302 # ssh, write new connection file
311 303 self.kernel_manager.write_connection_file()
312 304
313 305 # in case KM defaults / ssh writing changes things:
314 306 km = self.kernel_manager
315 307 self.shell_port=km.shell_port
316 308 self.iopub_port=km.iopub_port
317 309 self.stdin_port=km.stdin_port
318 310 self.hb_port=km.hb_port
319 311 self.connection_file = km.connection_file
320 312
321 313 atexit.register(self.kernel_manager.cleanup_connection_file)
322 314
323 315 def init_kernel_client(self):
324 316 if self.kernel_manager is not None:
325 317 self.kernel_client = self.kernel_manager.client()
326 318 else:
327 319 self.kernel_client = self.kernel_client_class(
328 320 session=self.session,
329 321 ip=self.ip,
330 322 transport=self.transport,
331 323 shell_port=self.shell_port,
332 324 iopub_port=self.iopub_port,
333 325 stdin_port=self.stdin_port,
334 326 hb_port=self.hb_port,
335 327 connection_file=self.connection_file,
336 328 parent=self,
337 329 )
338 330
339 331 self.kernel_client.start_channels()
340 332
341 333
342 334
343 335 def initialize(self, argv=None):
344 336 """
345 337 Classes which mix this class in should call:
346 338 IPythonConsoleApp.initialize(self,argv)
347 339 """
348 340 self.init_connection_file()
349 341 default_secure(self.config)
350 342 self.init_ssh()
351 343 self.init_kernel_manager()
352 344 self.init_kernel_client()
353 345
@@ -1,238 +1,253 b''
1 1 # encoding: utf-8
2 2 """
3 3 System command aliases.
4 4
5 5 Authors:
6 6
7 7 * Fernando Perez
8 8 * Brian Granger
9 9 """
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Copyright (C) 2008-2011 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License.
15 15 #
16 16 # The full license is in the file COPYING.txt, distributed with this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 23 import os
24 24 import re
25 25 import sys
26 26
27 27 from IPython.config.configurable import Configurable
28 28 from IPython.core.error import UsageError
29 29
30 30 from IPython.utils.py3compat import string_types
31 31 from IPython.utils.traitlets import List, Instance
32 32 from IPython.utils.warn import error
33 33
34 34 #-----------------------------------------------------------------------------
35 35 # Utilities
36 36 #-----------------------------------------------------------------------------
37 37
38 38 # This is used as the pattern for calls to split_user_input.
39 39 shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)')
40 40
41 41 def default_aliases():
42 42 """Return list of shell aliases to auto-define.
43 43 """
44 44 # Note: the aliases defined here should be safe to use on a kernel
45 45 # regardless of what frontend it is attached to. Frontends that use a
46 46 # kernel in-process can define additional aliases that will only work in
47 47 # their case. For example, things like 'less' or 'clear' that manipulate
48 48 # the terminal should NOT be declared here, as they will only work if the
49 49 # kernel is running inside a true terminal, and not over the network.
50 50
51 51 if os.name == 'posix':
52 52 default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
53 53 ('mv', 'mv'), ('rm', 'rm'), ('cp', 'cp'),
54 54 ('cat', 'cat'),
55 55 ]
56 56 # Useful set of ls aliases. The GNU and BSD options are a little
57 57 # different, so we make aliases that provide as similar as possible
58 58 # behavior in ipython, by passing the right flags for each platform
59 59 if sys.platform.startswith('linux'):
60 60 ls_aliases = [('ls', 'ls -F --color'),
61 61 # long ls
62 62 ('ll', 'ls -F -o --color'),
63 63 # ls normal files only
64 64 ('lf', 'ls -F -o --color %l | grep ^-'),
65 65 # ls symbolic links
66 66 ('lk', 'ls -F -o --color %l | grep ^l'),
67 67 # directories or links to directories,
68 68 ('ldir', 'ls -F -o --color %l | grep /$'),
69 69 # things which are executable
70 70 ('lx', 'ls -F -o --color %l | grep ^-..x'),
71 71 ]
72 elif sys.platform.startswith('openbsd') or sys.platform.startswith('netbsd'):
73 # OpenBSD, NetBSD. The ls implementation on these platforms do not support
74 # the -G switch and lack the ability to use colorized output.
75 ls_aliases = [('ls', 'ls -F'),
76 # long ls
77 ('ll', 'ls -F -l'),
78 # ls normal files only
79 ('lf', 'ls -F -l %l | grep ^-'),
80 # ls symbolic links
81 ('lk', 'ls -F -l %l | grep ^l'),
82 # directories or links to directories,
83 ('ldir', 'ls -F -l %l | grep /$'),
84 # things which are executable
85 ('lx', 'ls -F -l %l | grep ^-..x'),
86 ]
72 87 else:
73 88 # BSD, OSX, etc.
74 89 ls_aliases = [('ls', 'ls -F -G'),
75 90 # long ls
76 91 ('ll', 'ls -F -l -G'),
77 92 # ls normal files only
78 93 ('lf', 'ls -F -l -G %l | grep ^-'),
79 94 # ls symbolic links
80 95 ('lk', 'ls -F -l -G %l | grep ^l'),
81 96 # directories or links to directories,
82 97 ('ldir', 'ls -F -G -l %l | grep /$'),
83 98 # things which are executable
84 99 ('lx', 'ls -F -l -G %l | grep ^-..x'),
85 100 ]
86 101 default_aliases = default_aliases + ls_aliases
87 102 elif os.name in ['nt', 'dos']:
88 103 default_aliases = [('ls', 'dir /on'),
89 104 ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'),
90 105 ('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
91 106 ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'),
92 107 ]
93 108 else:
94 109 default_aliases = []
95 110
96 111 return default_aliases
97 112
98 113
99 114 class AliasError(Exception):
100 115 pass
101 116
102 117
103 118 class InvalidAliasError(AliasError):
104 119 pass
105 120
106 121 class Alias(object):
107 122 """Callable object storing the details of one alias.
108 123
109 124 Instances are registered as magic functions to allow use of aliases.
110 125 """
111 126
112 127 # Prepare blacklist
113 128 blacklist = {'cd','popd','pushd','dhist','alias','unalias'}
114 129
115 130 def __init__(self, shell, name, cmd):
116 131 self.shell = shell
117 132 self.name = name
118 133 self.cmd = cmd
119 134 self.nargs = self.validate()
120 135
121 136 def validate(self):
122 137 """Validate the alias, and return the number of arguments."""
123 138 if self.name in self.blacklist:
124 139 raise InvalidAliasError("The name %s can't be aliased "
125 140 "because it is a keyword or builtin." % self.name)
126 141 try:
127 142 caller = self.shell.magics_manager.magics['line'][self.name]
128 143 except KeyError:
129 144 pass
130 145 else:
131 146 if not isinstance(caller, Alias):
132 147 raise InvalidAliasError("The name %s can't be aliased "
133 148 "because it is another magic command." % self.name)
134 149
135 150 if not (isinstance(self.cmd, string_types)):
136 151 raise InvalidAliasError("An alias command must be a string, "
137 152 "got: %r" % self.cmd)
138 153
139 154 nargs = self.cmd.count('%s')
140 155
141 156 if (nargs > 0) and (self.cmd.find('%l') >= 0):
142 157 raise InvalidAliasError('The %s and %l specifiers are mutually '
143 158 'exclusive in alias definitions.')
144 159
145 160 return nargs
146 161
147 162 def __repr__(self):
148 163 return "<alias {} for {!r}>".format(self.name, self.cmd)
149 164
150 165 def __call__(self, rest=''):
151 166 cmd = self.cmd
152 167 nargs = self.nargs
153 168 # Expand the %l special to be the user's input line
154 169 if cmd.find('%l') >= 0:
155 170 cmd = cmd.replace('%l', rest)
156 171 rest = ''
157 172 if nargs==0:
158 173 # Simple, argument-less aliases
159 174 cmd = '%s %s' % (cmd, rest)
160 175 else:
161 176 # Handle aliases with positional arguments
162 177 args = rest.split(None, nargs)
163 178 if len(args) < nargs:
164 179 raise UsageError('Alias <%s> requires %s arguments, %s given.' %
165 180 (self.name, nargs, len(args)))
166 181 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
167 182
168 183 self.shell.system(cmd)
169 184
170 185 #-----------------------------------------------------------------------------
171 186 # Main AliasManager class
172 187 #-----------------------------------------------------------------------------
173 188
174 189 class AliasManager(Configurable):
175 190
176 191 default_aliases = List(default_aliases(), config=True)
177 192 user_aliases = List(default_value=[], config=True)
178 193 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
179 194
180 195 def __init__(self, shell=None, **kwargs):
181 196 super(AliasManager, self).__init__(shell=shell, **kwargs)
182 197 # For convenient access
183 198 self.linemagics = self.shell.magics_manager.magics['line']
184 199 self.init_aliases()
185 200
186 201 def init_aliases(self):
187 202 # Load default & user aliases
188 203 for name, cmd in self.default_aliases + self.user_aliases:
189 204 self.soft_define_alias(name, cmd)
190 205
191 206 @property
192 207 def aliases(self):
193 208 return [(n, func.cmd) for (n, func) in self.linemagics.items()
194 209 if isinstance(func, Alias)]
195 210
196 211 def soft_define_alias(self, name, cmd):
197 212 """Define an alias, but don't raise on an AliasError."""
198 213 try:
199 214 self.define_alias(name, cmd)
200 215 except AliasError as e:
201 216 error("Invalid alias: %s" % e)
202 217
203 218 def define_alias(self, name, cmd):
204 219 """Define a new alias after validating it.
205 220
206 221 This will raise an :exc:`AliasError` if there are validation
207 222 problems.
208 223 """
209 224 caller = Alias(shell=self.shell, name=name, cmd=cmd)
210 225 self.shell.magics_manager.register_function(caller, magic_kind='line',
211 226 magic_name=name)
212 227
213 228 def get_alias(self, name):
214 229 """Return an alias, or None if no alias by that name exists."""
215 230 aname = self.linemagics.get(name, None)
216 231 return aname if isinstance(aname, Alias) else None
217 232
218 233 def is_alias(self, name):
219 234 """Return whether or not a given name has been defined as an alias"""
220 235 return self.get_alias(name) is not None
221 236
222 237 def undefine_alias(self, name):
223 238 if self.is_alias(name):
224 239 del self.linemagics[name]
225 240 else:
226 241 raise ValueError('%s is not an alias' % name)
227 242
228 243 def clear_aliases(self):
229 244 for name, cmd in self.aliases:
230 245 self.undefine_alias(name)
231 246
232 247 def retrieve_alias(self, name):
233 248 """Retrieve the command to which an alias expands."""
234 249 caller = self.get_alias(name)
235 250 if caller:
236 251 return caller.cmd
237 252 else:
238 253 raise ValueError('%s is not an alias' % name)
@@ -1,389 +1,380 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
11 Authors:
12
13 * Brian Granger
14 * Fernando Perez
15 * Min RK
16
17 10 """
18 11
19 #-----------------------------------------------------------------------------
20 # Copyright (C) 2008 The IPython Development Team
21 #
22 # Distributed under the terms of the BSD License. The full license is in
23 # the file COPYING, distributed as part of this software.
24 #-----------------------------------------------------------------------------
25
26 #-----------------------------------------------------------------------------
27 # Imports
28 #-----------------------------------------------------------------------------
12 # Copyright (c) IPython Development Team.
13 # Distributed under the terms of the Modified BSD License.
29 14
30 15 import atexit
31 16 import glob
32 17 import logging
33 18 import os
34 19 import shutil
35 20 import sys
36 21
37 22 from IPython.config.application import Application, catch_config_error
38 23 from IPython.config.loader import ConfigFileNotFound
39 24 from IPython.core import release, crashhandler
40 25 from IPython.core.profiledir import ProfileDir, ProfileDirError
41 26 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir, ensure_dir_exists
42 27 from IPython.utils import py3compat
43 28 from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict, Set, Instance
44 29
45 #-----------------------------------------------------------------------------
46 # Classes and functions
47 #-----------------------------------------------------------------------------
48
30 if os.name == 'nt':
31 programdata = os.environ.get('PROGRAMDATA', None)
32 if programdata:
33 SYSTEM_CONFIG_DIRS = [os.path.join(programdata, 'ipython')]
34 else: # PROGRAMDATA is not defined by default on XP.
35 SYSTEM_CONFIG_DIRS = []
36 else:
37 SYSTEM_CONFIG_DIRS = [
38 "/usr/local/etc/ipython",
39 "/etc/ipython",
40 ]
49 41
50 #-----------------------------------------------------------------------------
51 # Base Application Class
52 #-----------------------------------------------------------------------------
53 42
54 43 # aliases and flags
55 44
56 45 base_aliases = {
57 46 'profile-dir' : 'ProfileDir.location',
58 47 'profile' : 'BaseIPythonApplication.profile',
59 48 'ipython-dir' : 'BaseIPythonApplication.ipython_dir',
60 49 'log-level' : 'Application.log_level',
61 50 'config' : 'BaseIPythonApplication.extra_config_file',
62 51 }
63 52
64 53 base_flags = dict(
65 54 debug = ({'Application' : {'log_level' : logging.DEBUG}},
66 55 "set log level to logging.DEBUG (maximize logging output)"),
67 56 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
68 57 "set log level to logging.CRITICAL (minimize logging output)"),
69 58 init = ({'BaseIPythonApplication' : {
70 59 'copy_config_files' : True,
71 60 'auto_create' : True}
72 61 }, """Initialize profile with default config files. This is equivalent
73 62 to running `ipython profile create <profile>` prior to startup.
74 63 """)
75 64 )
76 65
77 66
78 67 class BaseIPythonApplication(Application):
79 68
80 69 name = Unicode(u'ipython')
81 70 description = Unicode(u'IPython: an enhanced interactive Python shell.')
82 71 version = Unicode(release.version)
83 72
84 73 aliases = Dict(base_aliases)
85 74 flags = Dict(base_flags)
86 75 classes = List([ProfileDir])
87 76
88 77 # Track whether the config_file has changed,
89 78 # because some logic happens only if we aren't using the default.
90 79 config_file_specified = Set()
91 80
92 81 config_file_name = Unicode()
93 82 def _config_file_name_default(self):
94 83 return self.name.replace('-','_') + u'_config.py'
95 84 def _config_file_name_changed(self, name, old, new):
96 85 if new != old:
97 86 self.config_file_specified.add(new)
98 87
99 88 # The directory that contains IPython's builtin profiles.
100 89 builtin_profile_dir = Unicode(
101 90 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
102 91 )
103
92
104 93 config_file_paths = List(Unicode)
105 94 def _config_file_paths_default(self):
106 95 return [py3compat.getcwd()]
107 96
108 97 extra_config_file = Unicode(config=True,
109 98 help="""Path to an extra config file to load.
110 99
111 100 If specified, load this config file in addition to any other IPython config.
112 101 """)
113 102 def _extra_config_file_changed(self, name, old, new):
114 103 try:
115 104 self.config_files.remove(old)
116 105 except ValueError:
117 106 pass
118 107 self.config_file_specified.add(new)
119 108 self.config_files.append(new)
120 109
121 110 profile = Unicode(u'default', config=True,
122 111 help="""The IPython profile to use."""
123 112 )
124 113
125 114 def _profile_changed(self, name, old, new):
126 115 self.builtin_profile_dir = os.path.join(
127 116 get_ipython_package_dir(), u'config', u'profile', new
128 117 )
129 118
130 119 ipython_dir = Unicode(config=True,
131 120 help="""
132 121 The name of the IPython directory. This directory is used for logging
133 122 configuration (through profiles), history storage, etc. The default
134 123 is usually $HOME/.ipython. This option can also be specified through
135 124 the environment variable IPYTHONDIR.
136 125 """
137 126 )
138 127 def _ipython_dir_default(self):
139 128 d = get_ipython_dir()
140 129 self._ipython_dir_changed('ipython_dir', d, d)
141 130 return d
142 131
143 132 _in_init_profile_dir = False
144 133 profile_dir = Instance(ProfileDir)
145 134 def _profile_dir_default(self):
146 135 # avoid recursion
147 136 if self._in_init_profile_dir:
148 137 return
149 138 # profile_dir requested early, force initialization
150 139 self.init_profile_dir()
151 140 return self.profile_dir
152 141
153 142 overwrite = Bool(False, config=True,
154 143 help="""Whether to overwrite existing config files when copying""")
155 144 auto_create = Bool(False, config=True,
156 145 help="""Whether to create profile dir if it doesn't exist""")
157 146
158 147 config_files = List(Unicode)
159 148 def _config_files_default(self):
160 149 return [self.config_file_name]
161 150
162 151 copy_config_files = Bool(False, config=True,
163 152 help="""Whether to install the default config files into the profile dir.
164 153 If a new profile is being created, and IPython contains config files for that
165 154 profile, then they will be staged into the new directory. Otherwise,
166 155 default config files will be automatically generated.
167 156 """)
168 157
169 158 verbose_crash = Bool(False, config=True,
170 159 help="""Create a massive crash report when IPython encounters what may be an
171 160 internal error. The default is to append a short message to the
172 161 usual traceback""")
173 162
174 163 # The class to use as the crash handler.
175 164 crash_handler_class = Type(crashhandler.CrashHandler)
176 165
177 166 @catch_config_error
178 167 def __init__(self, **kwargs):
179 168 super(BaseIPythonApplication, self).__init__(**kwargs)
180 169 # ensure current working directory exists
181 170 try:
182 171 directory = py3compat.getcwd()
183 172 except:
184 173 # raise exception
185 174 self.log.error("Current working directory doesn't exist.")
186 175 raise
187 176
188 177 #-------------------------------------------------------------------------
189 178 # Various stages of Application creation
190 179 #-------------------------------------------------------------------------
191 180
192 181 def init_crash_handler(self):
193 182 """Create a crash handler, typically setting sys.excepthook to it."""
194 183 self.crash_handler = self.crash_handler_class(self)
195 184 sys.excepthook = self.excepthook
196 185 def unset_crashhandler():
197 186 sys.excepthook = sys.__excepthook__
198 187 atexit.register(unset_crashhandler)
199 188
200 189 def excepthook(self, etype, evalue, tb):
201 190 """this is sys.excepthook after init_crashhandler
202 191
203 192 set self.verbose_crash=True to use our full crashhandler, instead of
204 193 a regular traceback with a short message (crash_handler_lite)
205 194 """
206 195
207 196 if self.verbose_crash:
208 197 return self.crash_handler(etype, evalue, tb)
209 198 else:
210 199 return crashhandler.crash_handler_lite(etype, evalue, tb)
211 200
212 201 def _ipython_dir_changed(self, name, old, new):
213 str_old = py3compat.cast_bytes_py2(os.path.abspath(old),
214 sys.getfilesystemencoding()
215 )
216 if str_old in sys.path:
217 sys.path.remove(str_old)
202 if old is not None:
203 str_old = py3compat.cast_bytes_py2(os.path.abspath(old),
204 sys.getfilesystemencoding()
205 )
206 if str_old in sys.path:
207 sys.path.remove(str_old)
218 208 str_path = py3compat.cast_bytes_py2(os.path.abspath(new),
219 209 sys.getfilesystemencoding()
220 210 )
221 211 sys.path.append(str_path)
222 212 ensure_dir_exists(new)
223 213 readme = os.path.join(new, 'README')
224 214 readme_src = os.path.join(get_ipython_package_dir(), u'config', u'profile', 'README')
225 215 if not os.path.exists(readme) and os.path.exists(readme_src):
226 216 shutil.copy(readme_src, readme)
227 217 for d in ('extensions', 'nbextensions'):
228 218 path = os.path.join(new, d)
229 219 try:
230 220 ensure_dir_exists(path)
231 221 except OSError:
232 222 # this will not be EEXIST
233 223 self.log.error("couldn't create path %s: %s", path, e)
234 224 self.log.debug("IPYTHONDIR set to: %s" % new)
235 225
236 226 def load_config_file(self, suppress_errors=True):
237 227 """Load the config file.
238 228
239 229 By default, errors in loading config are handled, and a warning
240 230 printed on screen. For testing, the suppress_errors option is set
241 231 to False, so errors will make tests fail.
242 232 """
243 233 self.log.debug("Searching path %s for config files", self.config_file_paths)
244 234 base_config = 'ipython_config.py'
245 235 self.log.debug("Attempting to load config file: %s" %
246 236 base_config)
247 237 try:
248 238 Application.load_config_file(
249 239 self,
250 240 base_config,
251 241 path=self.config_file_paths
252 242 )
253 243 except ConfigFileNotFound:
254 244 # ignore errors loading parent
255 245 self.log.debug("Config file %s not found", base_config)
256 246 pass
257 247
258 248 for config_file_name in self.config_files:
259 249 if not config_file_name or config_file_name == base_config:
260 250 continue
261 251 self.log.debug("Attempting to load config file: %s" %
262 252 self.config_file_name)
263 253 try:
264 254 Application.load_config_file(
265 255 self,
266 256 config_file_name,
267 257 path=self.config_file_paths
268 258 )
269 259 except ConfigFileNotFound:
270 260 # Only warn if the default config file was NOT being used.
271 261 if config_file_name in self.config_file_specified:
272 262 msg = self.log.warn
273 263 else:
274 264 msg = self.log.debug
275 265 msg("Config file not found, skipping: %s", config_file_name)
276 266 except:
277 267 # For testing purposes.
278 268 if not suppress_errors:
279 269 raise
280 270 self.log.warn("Error loading config file: %s" %
281 271 self.config_file_name, exc_info=True)
282 272
283 273 def init_profile_dir(self):
284 274 """initialize the profile dir"""
285 275 self._in_init_profile_dir = True
286 276 if self.profile_dir is not None:
287 277 # already ran
288 278 return
289 279 if 'ProfileDir.location' not in self.config:
290 280 # location not specified, find by profile name
291 281 try:
292 282 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
293 283 except ProfileDirError:
294 284 # not found, maybe create it (always create default profile)
295 285 if self.auto_create or self.profile == 'default':
296 286 try:
297 287 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
298 288 except ProfileDirError:
299 289 self.log.fatal("Could not create profile: %r"%self.profile)
300 290 self.exit(1)
301 291 else:
302 292 self.log.info("Created profile dir: %r"%p.location)
303 293 else:
304 294 self.log.fatal("Profile %r not found."%self.profile)
305 295 self.exit(1)
306 296 else:
307 297 self.log.info("Using existing profile dir: %r"%p.location)
308 298 else:
309 299 location = self.config.ProfileDir.location
310 300 # location is fully specified
311 301 try:
312 302 p = ProfileDir.find_profile_dir(location, self.config)
313 303 except ProfileDirError:
314 304 # not found, maybe create it
315 305 if self.auto_create:
316 306 try:
317 307 p = ProfileDir.create_profile_dir(location, self.config)
318 308 except ProfileDirError:
319 309 self.log.fatal("Could not create profile directory: %r"%location)
320 310 self.exit(1)
321 311 else:
322 312 self.log.info("Creating new profile dir: %r"%location)
323 313 else:
324 314 self.log.fatal("Profile directory %r not found."%location)
325 315 self.exit(1)
326 316 else:
327 317 self.log.info("Using existing profile dir: %r"%location)
328 318 # if profile_dir is specified explicitly, set profile name
329 319 dir_name = os.path.basename(p.location)
330 320 if dir_name.startswith('profile_'):
331 321 self.profile = dir_name[8:]
332 322
333 323 self.profile_dir = p
334 324 self.config_file_paths.append(p.location)
335 325 self._in_init_profile_dir = False
336 326
337 327 def init_config_files(self):
338 328 """[optionally] copy default config files into profile dir."""
329 self.config_file_paths.extend(SYSTEM_CONFIG_DIRS)
339 330 # copy config files
340 331 path = self.builtin_profile_dir
341 332 if self.copy_config_files:
342 333 src = self.profile
343 334
344 335 cfg = self.config_file_name
345 336 if path and os.path.exists(os.path.join(path, cfg)):
346 337 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
347 338 cfg, src, self.profile_dir.location, self.overwrite)
348 339 )
349 340 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
350 341 else:
351 342 self.stage_default_config_file()
352 343 else:
353 344 # Still stage *bundled* config files, but not generated ones
354 345 # This is necessary for `ipython profile=sympy` to load the profile
355 346 # on the first go
356 347 files = glob.glob(os.path.join(path, '*.py'))
357 348 for fullpath in files:
358 349 cfg = os.path.basename(fullpath)
359 350 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
360 351 # file was copied
361 352 self.log.warn("Staging bundled %s from %s into %r"%(
362 353 cfg, self.profile, self.profile_dir.location)
363 354 )
364 355
365 356
366 357 def stage_default_config_file(self):
367 358 """auto generate default config file, and stage it into the profile."""
368 359 s = self.generate_config_file()
369 360 fname = os.path.join(self.profile_dir.location, self.config_file_name)
370 361 if self.overwrite or not os.path.exists(fname):
371 362 self.log.warn("Generating default config file: %r"%(fname))
372 363 with open(fname, 'w') as f:
373 364 f.write(s)
374 365
375 366 @catch_config_error
376 367 def initialize(self, argv=None):
377 368 # don't hook up crash handler before parsing command-line
378 369 self.parse_command_line(argv)
379 370 self.init_crash_handler()
380 371 if self.subapp is not None:
381 372 # stop here if subapp is taking over
382 373 return
383 374 cl_config = self.config
384 375 self.init_profile_dir()
385 376 self.init_config_files()
386 377 self.load_config_file()
387 378 # enforce cl-opts override configfile opts:
388 379 self.update_config(cl_config)
389 380
@@ -1,591 +1,591 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Pdb debugger class.
4 4
5 5 Modified from the standard pdb.Pdb class to avoid including readline, so that
6 6 the command line completion of other programs which include this isn't
7 7 damaged.
8 8
9 9 In the future, this class will be expanded with improvements over the standard
10 10 pdb.
11 11
12 12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
13 13 changes. Licensing should therefore be under the standard Python terms. For
14 14 details on the PSF (Python Software Foundation) standard license, see:
15 15
16 16 http://www.python.org/2.2.3/license.html"""
17 17
18 18 #*****************************************************************************
19 19 #
20 20 # This file is licensed under the PSF license.
21 21 #
22 22 # Copyright (C) 2001 Python Software Foundation, www.python.org
23 23 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
24 24 #
25 25 #
26 26 #*****************************************************************************
27 27 from __future__ import print_function
28 28
29 29 import bdb
30 30 import functools
31 31 import linecache
32 32 import sys
33 33
34 34 from IPython import get_ipython
35 35 from IPython.utils import PyColorize, ulinecache
36 36 from IPython.utils import coloransi, io, py3compat
37 37 from IPython.core.excolors import exception_colors
38 38 from IPython.testing.skipdoctest import skip_doctest
39 39
40 40 # See if we can use pydb.
41 41 has_pydb = False
42 42 prompt = 'ipdb> '
43 43 #We have to check this directly from sys.argv, config struct not yet available
44 44 if '--pydb' in sys.argv:
45 45 try:
46 46 import pydb
47 47 if hasattr(pydb.pydb, "runl") and pydb.version>'1.17':
48 48 # Version 1.17 is broken, and that's what ships with Ubuntu Edgy, so we
49 49 # better protect against it.
50 50 has_pydb = True
51 51 except ImportError:
52 52 print("Pydb (http://bashdb.sourceforge.net/pydb/) does not seem to be available")
53 53
54 54 if has_pydb:
55 55 from pydb import Pdb as OldPdb
56 56 #print "Using pydb for %run -d and post-mortem" #dbg
57 57 prompt = 'ipydb> '
58 58 else:
59 59 from pdb import Pdb as OldPdb
60 60
61 61 # Allow the set_trace code to operate outside of an ipython instance, even if
62 62 # it does so with some limitations. The rest of this support is implemented in
63 63 # the Tracer constructor.
64 64 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
65 65 """Exception hook which handles `BdbQuit` exceptions.
66 66
67 67 All other exceptions are processed using the `excepthook`
68 68 parameter.
69 69 """
70 70 if et==bdb.BdbQuit:
71 71 print('Exiting Debugger.')
72 72 elif excepthook is not None:
73 73 excepthook(et, ev, tb)
74 74 else:
75 75 # Backwards compatibility. Raise deprecation warning?
76 76 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
77 77
78 78 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
79 79 print('Exiting Debugger.')
80 80
81 81
82 82 class Tracer(object):
83 83 """Class for local debugging, similar to pdb.set_trace.
84 84
85 85 Instances of this class, when called, behave like pdb.set_trace, but
86 86 providing IPython's enhanced capabilities.
87 87
88 88 This is implemented as a class which must be initialized in your own code
89 89 and not as a standalone function because we need to detect at runtime
90 90 whether IPython is already active or not. That detection is done in the
91 91 constructor, ensuring that this code plays nicely with a running IPython,
92 92 while functioning acceptably (though with limitations) if outside of it.
93 93 """
94 94
95 95 @skip_doctest
96 96 def __init__(self,colors=None):
97 97 """Create a local debugger instance.
98 98
99 99 Parameters
100 100 ----------
101 101
102 102 colors : str, optional
103 103 The name of the color scheme to use, it must be one of IPython's
104 104 valid color schemes. If not given, the function will default to
105 105 the current IPython scheme when running inside IPython, and to
106 106 'NoColor' otherwise.
107 107
108 108 Examples
109 109 --------
110 110 ::
111 111
112 112 from IPython.core.debugger import Tracer; debug_here = Tracer()
113 113
114 114 Later in your code::
115 115
116 116 debug_here() # -> will open up the debugger at that point.
117 117
118 118 Once the debugger activates, you can use all of its regular commands to
119 119 step through code, set breakpoints, etc. See the pdb documentation
120 120 from the Python standard library for usage details.
121 121 """
122 122
123 123 ip = get_ipython()
124 124 if ip is None:
125 125 # Outside of ipython, we set our own exception hook manually
126 126 sys.excepthook = functools.partial(BdbQuit_excepthook,
127 127 excepthook=sys.excepthook)
128 128 def_colors = 'NoColor'
129 129 try:
130 130 # Limited tab completion support
131 131 import readline
132 132 readline.parse_and_bind('tab: complete')
133 133 except ImportError:
134 134 pass
135 135 else:
136 136 # In ipython, we use its custom exception handler mechanism
137 137 def_colors = ip.colors
138 138 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
139 139
140 140 if colors is None:
141 141 colors = def_colors
142 142
143 143 # The stdlib debugger internally uses a modified repr from the `repr`
144 144 # module, that limits the length of printed strings to a hardcoded
145 145 # limit of 30 characters. That much trimming is too aggressive, let's
146 146 # at least raise that limit to 80 chars, which should be enough for
147 147 # most interactive uses.
148 148 try:
149 149 try:
150 150 from reprlib import aRepr # Py 3
151 151 except ImportError:
152 152 from repr import aRepr # Py 2
153 153 aRepr.maxstring = 80
154 154 except:
155 155 # This is only a user-facing convenience, so any error we encounter
156 156 # here can be warned about but can be otherwise ignored. These
157 157 # printouts will tell us about problems if this API changes
158 158 import traceback
159 159 traceback.print_exc()
160 160
161 161 self.debugger = Pdb(colors)
162 162
163 163 def __call__(self):
164 164 """Starts an interactive debugger at the point where called.
165 165
166 166 This is similar to the pdb.set_trace() function from the std lib, but
167 167 using IPython's enhanced debugger."""
168 168
169 169 self.debugger.set_trace(sys._getframe().f_back)
170 170
171 171
172 172 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
173 173 """Make new_fn have old_fn's doc string. This is particularly useful
174 174 for the ``do_...`` commands that hook into the help system.
175 175 Adapted from from a comp.lang.python posting
176 176 by Duncan Booth."""
177 177 def wrapper(*args, **kw):
178 178 return new_fn(*args, **kw)
179 179 if old_fn.__doc__:
180 180 wrapper.__doc__ = old_fn.__doc__ + additional_text
181 181 return wrapper
182 182
183 183
184 184 def _file_lines(fname):
185 185 """Return the contents of a named file as a list of lines.
186 186
187 187 This function never raises an IOError exception: if the file can't be
188 188 read, it simply returns an empty list."""
189 189
190 190 try:
191 191 outfile = open(fname)
192 192 except IOError:
193 193 return []
194 194 else:
195 195 out = outfile.readlines()
196 196 outfile.close()
197 197 return out
198 198
199 199
200 200 class Pdb(OldPdb):
201 201 """Modified Pdb class, does not load readline."""
202 202
203 203 def __init__(self,color_scheme='NoColor',completekey=None,
204 204 stdin=None, stdout=None):
205 205
206 206 # Parent constructor:
207 207 if has_pydb and completekey is None:
208 208 OldPdb.__init__(self,stdin=stdin,stdout=io.stdout)
209 209 else:
210 210 OldPdb.__init__(self,completekey,stdin,stdout)
211 211
212 212 self.prompt = prompt # The default prompt is '(Pdb)'
213 213
214 214 # IPython changes...
215 215 self.is_pydb = has_pydb
216 216
217 217 self.shell = get_ipython()
218 218
219 219 if self.shell is None:
220 220 # No IPython instance running, we must create one
221 221 from IPython.terminal.interactiveshell import \
222 222 TerminalInteractiveShell
223 223 self.shell = TerminalInteractiveShell.instance()
224 224
225 225 if self.is_pydb:
226 226
227 227 # interactiveshell.py's ipalias seems to want pdb's checkline
228 228 # which located in pydb.fn
229 229 import pydb.fns
230 230 self.checkline = lambda filename, lineno: \
231 231 pydb.fns.checkline(self, filename, lineno)
232 232
233 233 self.curframe = None
234 234 self.do_restart = self.new_do_restart
235 235
236 236 self.old_all_completions = self.shell.Completer.all_completions
237 237 self.shell.Completer.all_completions=self.all_completions
238 238
239 239 self.do_list = decorate_fn_with_doc(self.list_command_pydb,
240 240 OldPdb.do_list)
241 241 self.do_l = self.do_list
242 242 self.do_frame = decorate_fn_with_doc(self.new_do_frame,
243 243 OldPdb.do_frame)
244 244
245 245 self.aliases = {}
246 246
247 247 # Create color table: we copy the default one from the traceback
248 248 # module and add a few attributes needed for debugging
249 249 self.color_scheme_table = exception_colors()
250 250
251 251 # shorthands
252 252 C = coloransi.TermColors
253 253 cst = self.color_scheme_table
254 254
255 255 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
256 256 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
257 257
258 258 cst['Linux'].colors.breakpoint_enabled = C.LightRed
259 259 cst['Linux'].colors.breakpoint_disabled = C.Red
260 260
261 261 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
262 262 cst['LightBG'].colors.breakpoint_disabled = C.Red
263 263
264 264 self.set_colors(color_scheme)
265 265
266 266 # Add a python parser so we can syntax highlight source while
267 267 # debugging.
268 268 self.parser = PyColorize.Parser()
269 269
270 270 def set_colors(self, scheme):
271 271 """Shorthand access to the color table scheme selector method."""
272 272 self.color_scheme_table.set_active_scheme(scheme)
273 273
274 274 def interaction(self, frame, traceback):
275 275 self.shell.set_completer_frame(frame)
276 276 while True:
277 277 try:
278 278 OldPdb.interaction(self, frame, traceback)
279 279 except KeyboardInterrupt:
280 self.shell.write("\nKeyboardInterrupt\n")
280 self.shell.write('\n' + self.shell.get_exception_only())
281 281 break
282 282 else:
283 283 break
284 284
285 285 def new_do_up(self, arg):
286 286 OldPdb.do_up(self, arg)
287 287 self.shell.set_completer_frame(self.curframe)
288 288 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
289 289
290 290 def new_do_down(self, arg):
291 291 OldPdb.do_down(self, arg)
292 292 self.shell.set_completer_frame(self.curframe)
293 293
294 294 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
295 295
296 296 def new_do_frame(self, arg):
297 297 OldPdb.do_frame(self, arg)
298 298 self.shell.set_completer_frame(self.curframe)
299 299
300 300 def new_do_quit(self, arg):
301 301
302 302 if hasattr(self, 'old_all_completions'):
303 303 self.shell.Completer.all_completions=self.old_all_completions
304 304
305 305
306 306 return OldPdb.do_quit(self, arg)
307 307
308 308 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
309 309
310 310 def new_do_restart(self, arg):
311 311 """Restart command. In the context of ipython this is exactly the same
312 312 thing as 'quit'."""
313 313 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
314 314 return self.do_quit(arg)
315 315
316 316 def postloop(self):
317 317 self.shell.set_completer_frame(None)
318 318
319 319 def print_stack_trace(self):
320 320 try:
321 321 for frame_lineno in self.stack:
322 322 self.print_stack_entry(frame_lineno, context = 5)
323 323 except KeyboardInterrupt:
324 324 pass
325 325
326 326 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
327 327 context = 3):
328 328 #frame, lineno = frame_lineno
329 329 print(self.format_stack_entry(frame_lineno, '', context), file=io.stdout)
330 330
331 331 # vds: >>
332 332 frame, lineno = frame_lineno
333 333 filename = frame.f_code.co_filename
334 334 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
335 335 # vds: <<
336 336
337 337 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
338 338 try:
339 339 import reprlib # Py 3
340 340 except ImportError:
341 341 import repr as reprlib # Py 2
342 342
343 343 ret = []
344 344
345 345 Colors = self.color_scheme_table.active_colors
346 346 ColorsNormal = Colors.Normal
347 347 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
348 348 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
349 349 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
350 350 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
351 351 ColorsNormal)
352 352
353 353 frame, lineno = frame_lineno
354 354
355 355 return_value = ''
356 356 if '__return__' in frame.f_locals:
357 357 rv = frame.f_locals['__return__']
358 358 #return_value += '->'
359 359 return_value += reprlib.repr(rv) + '\n'
360 360 ret.append(return_value)
361 361
362 362 #s = filename + '(' + `lineno` + ')'
363 363 filename = self.canonic(frame.f_code.co_filename)
364 364 link = tpl_link % py3compat.cast_unicode(filename)
365 365
366 366 if frame.f_code.co_name:
367 367 func = frame.f_code.co_name
368 368 else:
369 369 func = "<lambda>"
370 370
371 371 call = ''
372 372 if func != '?':
373 373 if '__args__' in frame.f_locals:
374 374 args = reprlib.repr(frame.f_locals['__args__'])
375 375 else:
376 376 args = '()'
377 377 call = tpl_call % (func, args)
378 378
379 379 # The level info should be generated in the same format pdb uses, to
380 380 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
381 381 if frame is self.curframe:
382 382 ret.append('> ')
383 383 else:
384 384 ret.append(' ')
385 385 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
386 386
387 387 start = lineno - 1 - context//2
388 388 lines = ulinecache.getlines(filename)
389 389 start = min(start, len(lines) - context)
390 390 start = max(start, 0)
391 391 lines = lines[start : start + context]
392 392
393 393 for i,line in enumerate(lines):
394 394 show_arrow = (start + 1 + i == lineno)
395 395 linetpl = (frame is self.curframe or show_arrow) \
396 396 and tpl_line_em \
397 397 or tpl_line
398 398 ret.append(self.__format_line(linetpl, filename,
399 399 start + 1 + i, line,
400 400 arrow = show_arrow) )
401 401 return ''.join(ret)
402 402
403 403 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
404 404 bp_mark = ""
405 405 bp_mark_color = ""
406 406
407 407 scheme = self.color_scheme_table.active_scheme_name
408 408 new_line, err = self.parser.format2(line, 'str', scheme)
409 409 if not err: line = new_line
410 410
411 411 bp = None
412 412 if lineno in self.get_file_breaks(filename):
413 413 bps = self.get_breaks(filename, lineno)
414 414 bp = bps[-1]
415 415
416 416 if bp:
417 417 Colors = self.color_scheme_table.active_colors
418 418 bp_mark = str(bp.number)
419 419 bp_mark_color = Colors.breakpoint_enabled
420 420 if not bp.enabled:
421 421 bp_mark_color = Colors.breakpoint_disabled
422 422
423 423 numbers_width = 7
424 424 if arrow:
425 425 # This is the line with the error
426 426 pad = numbers_width - len(str(lineno)) - len(bp_mark)
427 427 if pad >= 3:
428 428 marker = '-'*(pad-3) + '-> '
429 429 elif pad == 2:
430 430 marker = '> '
431 431 elif pad == 1:
432 432 marker = '>'
433 433 else:
434 434 marker = ''
435 435 num = '%s%s' % (marker, str(lineno))
436 436 line = tpl_line % (bp_mark_color + bp_mark, num, line)
437 437 else:
438 438 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
439 439 line = tpl_line % (bp_mark_color + bp_mark, num, line)
440 440
441 441 return line
442 442
443 443 def list_command_pydb(self, arg):
444 444 """List command to use if we have a newer pydb installed"""
445 445 filename, first, last = OldPdb.parse_list_cmd(self, arg)
446 446 if filename is not None:
447 447 self.print_list_lines(filename, first, last)
448 448
449 449 def print_list_lines(self, filename, first, last):
450 450 """The printing (as opposed to the parsing part of a 'list'
451 451 command."""
452 452 try:
453 453 Colors = self.color_scheme_table.active_colors
454 454 ColorsNormal = Colors.Normal
455 455 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
456 456 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
457 457 src = []
458 458 if filename == "<string>" and hasattr(self, "_exec_filename"):
459 459 filename = self._exec_filename
460 460
461 461 for lineno in range(first, last+1):
462 462 line = ulinecache.getline(filename, lineno)
463 463 if not line:
464 464 break
465 465
466 466 if lineno == self.curframe.f_lineno:
467 467 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
468 468 else:
469 469 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
470 470
471 471 src.append(line)
472 472 self.lineno = lineno
473 473
474 474 print(''.join(src), file=io.stdout)
475 475
476 476 except KeyboardInterrupt:
477 477 pass
478 478
479 479 def do_list(self, arg):
480 480 self.lastcmd = 'list'
481 481 last = None
482 482 if arg:
483 483 try:
484 484 x = eval(arg, {}, {})
485 485 if type(x) == type(()):
486 486 first, last = x
487 487 first = int(first)
488 488 last = int(last)
489 489 if last < first:
490 490 # Assume it's a count
491 491 last = first + last
492 492 else:
493 493 first = max(1, int(x) - 5)
494 494 except:
495 495 print('*** Error in argument:', repr(arg))
496 496 return
497 497 elif self.lineno is None:
498 498 first = max(1, self.curframe.f_lineno - 5)
499 499 else:
500 500 first = self.lineno + 1
501 501 if last is None:
502 502 last = first + 10
503 503 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
504 504
505 505 # vds: >>
506 506 lineno = first
507 507 filename = self.curframe.f_code.co_filename
508 508 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
509 509 # vds: <<
510 510
511 511 do_l = do_list
512 512
513 513 def do_pdef(self, arg):
514 514 """Print the call signature for any callable object.
515 515
516 516 The debugger interface to %pdef"""
517 517 namespaces = [('Locals', self.curframe.f_locals),
518 518 ('Globals', self.curframe.f_globals)]
519 519 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
520 520
521 521 def do_pdoc(self, arg):
522 522 """Print the docstring for an object.
523 523
524 524 The debugger interface to %pdoc."""
525 525 namespaces = [('Locals', self.curframe.f_locals),
526 526 ('Globals', self.curframe.f_globals)]
527 527 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
528 528
529 529 def do_pfile(self, arg):
530 530 """Print (or run through pager) the file where an object is defined.
531 531
532 532 The debugger interface to %pfile.
533 533 """
534 534 namespaces = [('Locals', self.curframe.f_locals),
535 535 ('Globals', self.curframe.f_globals)]
536 536 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
537 537
538 538 def do_pinfo(self, arg):
539 539 """Provide detailed information about an object.
540 540
541 541 The debugger interface to %pinfo, i.e., obj?."""
542 542 namespaces = [('Locals', self.curframe.f_locals),
543 543 ('Globals', self.curframe.f_globals)]
544 544 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
545 545
546 546 def do_pinfo2(self, arg):
547 547 """Provide extra detailed information about an object.
548 548
549 549 The debugger interface to %pinfo2, i.e., obj??."""
550 550 namespaces = [('Locals', self.curframe.f_locals),
551 551 ('Globals', self.curframe.f_globals)]
552 552 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
553 553
554 554 def do_psource(self, arg):
555 555 """Print (or run through pager) the source code for an object."""
556 556 namespaces = [('Locals', self.curframe.f_locals),
557 557 ('Globals', self.curframe.f_globals)]
558 558 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
559 559
560 560 def checkline(self, filename, lineno):
561 561 """Check whether specified line seems to be executable.
562 562
563 563 Return `lineno` if it is, 0 if not (e.g. a docstring, comment, blank
564 564 line or EOF). Warning: testing is not comprehensive.
565 565 """
566 566 #######################################################################
567 567 # XXX Hack! Use python-2.5 compatible code for this call, because with
568 568 # all of our changes, we've drifted from the pdb api in 2.6. For now,
569 569 # changing:
570 570 #
571 571 #line = linecache.getline(filename, lineno, self.curframe.f_globals)
572 572 # to:
573 573 #
574 574 line = linecache.getline(filename, lineno)
575 575 #
576 576 # does the trick. But in reality, we need to fix this by reconciling
577 577 # our updates with the new Pdb APIs in Python 2.6.
578 578 #
579 579 # End hack. The rest of this method is copied verbatim from 2.6 pdb.py
580 580 #######################################################################
581 581
582 582 if not line:
583 583 print('End of file', file=self.stdout)
584 584 return 0
585 585 line = line.strip()
586 586 # Don't allow setting breakpoint at a blank line
587 587 if (not line or (line[0] == '#') or
588 588 (line[:3] == '"""') or line[:3] == "'''"):
589 589 print('*** Blank or comment', file=self.stdout)
590 590 return 0
591 591 return lineno
@@ -1,859 +1,944 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Top-level display functions for displaying object in different formats.
3 3
4 4 Authors:
5 5
6 6 * Brian Granger
7 7 """
8 8
9 9 #-----------------------------------------------------------------------------
10 10 # Copyright (C) 2013 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19
20 20 from __future__ import print_function
21 21
22 22 import os
23 23 import struct
24 import mimetypes
24 25
25 26 from IPython.core.formatters import _safe_get_formatter_method
26 27 from IPython.utils.py3compat import (string_types, cast_bytes_py2, cast_unicode,
27 28 unicode_type)
28 29 from IPython.testing.skipdoctest import skip_doctest
29 30
30 31 __all__ = ['display', 'display_pretty', 'display_html', 'display_markdown',
31 32 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
32 33 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
33 34 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'JSON', 'Javascript',
34 35 'Image', 'clear_output', 'set_matplotlib_formats', 'set_matplotlib_close',
35 36 'publish_display_data']
36 37
37 38 #-----------------------------------------------------------------------------
38 39 # utility functions
39 40 #-----------------------------------------------------------------------------
40 41
41 42 def _safe_exists(path):
42 43 """Check path, but don't let exceptions raise"""
43 44 try:
44 45 return os.path.exists(path)
45 46 except Exception:
46 47 return False
47 48
48 49 def _merge(d1, d2):
49 50 """Like update, but merges sub-dicts instead of clobbering at the top level.
50 51
51 52 Updates d1 in-place
52 53 """
53 54
54 55 if not isinstance(d2, dict) or not isinstance(d1, dict):
55 56 return d2
56 57 for key, value in d2.items():
57 58 d1[key] = _merge(d1.get(key), value)
58 59 return d1
59 60
60 61 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
61 62 """internal implementation of all display_foo methods
62 63
63 64 Parameters
64 65 ----------
65 66 mimetype : str
66 67 The mimetype to be published (e.g. 'image/png')
67 68 objs : tuple of objects
68 69 The Python objects to display, or if raw=True raw text data to
69 70 display.
70 71 raw : bool
71 72 Are the data objects raw data or Python objects that need to be
72 73 formatted before display? [default: False]
73 74 metadata : dict (optional)
74 75 Metadata to be associated with the specific mimetype output.
75 76 """
76 77 if metadata:
77 78 metadata = {mimetype: metadata}
78 79 if raw:
79 80 # turn list of pngdata into list of { 'image/png': pngdata }
80 81 objs = [ {mimetype: obj} for obj in objs ]
81 82 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
82 83
83 84 #-----------------------------------------------------------------------------
84 85 # Main functions
85 86 #-----------------------------------------------------------------------------
86 87
87 88 def publish_display_data(data, metadata=None, source=None):
88 89 """Publish data and metadata to all frontends.
89 90
90 91 See the ``display_data`` message in the messaging documentation for
91 92 more details about this message type.
92 93
93 94 The following MIME types are currently implemented:
94 95
95 96 * text/plain
96 97 * text/html
97 98 * text/markdown
98 99 * text/latex
99 100 * application/json
100 101 * application/javascript
101 102 * image/png
102 103 * image/jpeg
103 104 * image/svg+xml
104 105
105 106 Parameters
106 107 ----------
107 108 data : dict
108 109 A dictionary having keys that are valid MIME types (like
109 110 'text/plain' or 'image/svg+xml') and values that are the data for
110 111 that MIME type. The data itself must be a JSON'able data
111 112 structure. Minimally all data should have the 'text/plain' data,
112 113 which can be displayed by all frontends. If more than the plain
113 114 text is given, it is up to the frontend to decide which
114 115 representation to use.
115 116 metadata : dict
116 117 A dictionary for metadata related to the data. This can contain
117 118 arbitrary key, value pairs that frontends can use to interpret
118 119 the data. mime-type keys matching those in data can be used
119 120 to specify metadata about particular representations.
120 121 source : str, deprecated
121 122 Unused.
122 123 """
123 124 from IPython.core.interactiveshell import InteractiveShell
124 125 InteractiveShell.instance().display_pub.publish(
125 126 data=data,
126 127 metadata=metadata,
127 128 )
128 129
129 130 def display(*objs, **kwargs):
130 131 """Display a Python object in all frontends.
131 132
132 133 By default all representations will be computed and sent to the frontends.
133 134 Frontends can decide which representation is used and how.
134 135
135 136 Parameters
136 137 ----------
137 138 objs : tuple of objects
138 139 The Python objects to display.
139 140 raw : bool, optional
140 141 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
141 142 or Python objects that need to be formatted before display? [default: False]
142 143 include : list or tuple, optional
143 144 A list of format type strings (MIME types) to include in the
144 145 format data dict. If this is set *only* the format types included
145 146 in this list will be computed.
146 147 exclude : list or tuple, optional
147 148 A list of format type strings (MIME types) to exclude in the format
148 149 data dict. If this is set all format types will be computed,
149 150 except for those included in this argument.
150 151 metadata : dict, optional
151 152 A dictionary of metadata to associate with the output.
152 153 mime-type keys in this dictionary will be associated with the individual
153 154 representation formats, if they exist.
154 155 """
155 156 raw = kwargs.get('raw', False)
156 157 include = kwargs.get('include')
157 158 exclude = kwargs.get('exclude')
158 159 metadata = kwargs.get('metadata')
159 160
160 161 from IPython.core.interactiveshell import InteractiveShell
161 162
162 163 if not raw:
163 164 format = InteractiveShell.instance().display_formatter.format
164 165
165 166 for obj in objs:
166 167
167 168 # If _ipython_display_ is defined, use that to display this object.
168 169 display_method = _safe_get_formatter_method(obj, '_ipython_display_')
169 170 if display_method is not None:
170 171 try:
171 172 display_method(**kwargs)
172 173 except NotImplementedError:
173 174 pass
174 175 else:
175 176 continue
176 177 if raw:
177 178 publish_display_data(data=obj, metadata=metadata)
178 179 else:
179 180 format_dict, md_dict = format(obj, include=include, exclude=exclude)
180 181 if metadata:
181 182 # kwarg-specified metadata gets precedence
182 183 _merge(md_dict, metadata)
183 184 publish_display_data(data=format_dict, metadata=md_dict)
184 185
185 186
186 187 def display_pretty(*objs, **kwargs):
187 188 """Display the pretty (default) representation of an object.
188 189
189 190 Parameters
190 191 ----------
191 192 objs : tuple of objects
192 193 The Python objects to display, or if raw=True raw text data to
193 194 display.
194 195 raw : bool
195 196 Are the data objects raw data or Python objects that need to be
196 197 formatted before display? [default: False]
197 198 metadata : dict (optional)
198 199 Metadata to be associated with the specific mimetype output.
199 200 """
200 201 _display_mimetype('text/plain', objs, **kwargs)
201 202
202 203
203 204 def display_html(*objs, **kwargs):
204 205 """Display the HTML representation of an object.
205 206
206 207 Parameters
207 208 ----------
208 209 objs : tuple of objects
209 210 The Python objects to display, or if raw=True raw HTML data to
210 211 display.
211 212 raw : bool
212 213 Are the data objects raw data or Python objects that need to be
213 214 formatted before display? [default: False]
214 215 metadata : dict (optional)
215 216 Metadata to be associated with the specific mimetype output.
216 217 """
217 218 _display_mimetype('text/html', objs, **kwargs)
218 219
219 220
220 221 def display_markdown(*objs, **kwargs):
221 222 """Displays the Markdown representation of an object.
222 223
223 224 Parameters
224 225 ----------
225 226 objs : tuple of objects
226 227 The Python objects to display, or if raw=True raw markdown data to
227 228 display.
228 229 raw : bool
229 230 Are the data objects raw data or Python objects that need to be
230 231 formatted before display? [default: False]
231 232 metadata : dict (optional)
232 233 Metadata to be associated with the specific mimetype output.
233 234 """
234 235
235 236 _display_mimetype('text/markdown', objs, **kwargs)
236 237
237 238
238 239 def display_svg(*objs, **kwargs):
239 240 """Display the SVG representation of an object.
240 241
241 242 Parameters
242 243 ----------
243 244 objs : tuple of objects
244 245 The Python objects to display, or if raw=True raw svg data to
245 246 display.
246 247 raw : bool
247 248 Are the data objects raw data or Python objects that need to be
248 249 formatted before display? [default: False]
249 250 metadata : dict (optional)
250 251 Metadata to be associated with the specific mimetype output.
251 252 """
252 253 _display_mimetype('image/svg+xml', objs, **kwargs)
253 254
254 255
255 256 def display_png(*objs, **kwargs):
256 257 """Display the PNG representation of an object.
257 258
258 259 Parameters
259 260 ----------
260 261 objs : tuple of objects
261 262 The Python objects to display, or if raw=True raw png data to
262 263 display.
263 264 raw : bool
264 265 Are the data objects raw data or Python objects that need to be
265 266 formatted before display? [default: False]
266 267 metadata : dict (optional)
267 268 Metadata to be associated with the specific mimetype output.
268 269 """
269 270 _display_mimetype('image/png', objs, **kwargs)
270 271
271 272
272 273 def display_jpeg(*objs, **kwargs):
273 274 """Display the JPEG representation of an object.
274 275
275 276 Parameters
276 277 ----------
277 278 objs : tuple of objects
278 279 The Python objects to display, or if raw=True raw JPEG data to
279 280 display.
280 281 raw : bool
281 282 Are the data objects raw data or Python objects that need to be
282 283 formatted before display? [default: False]
283 284 metadata : dict (optional)
284 285 Metadata to be associated with the specific mimetype output.
285 286 """
286 287 _display_mimetype('image/jpeg', objs, **kwargs)
287 288
288 289
289 290 def display_latex(*objs, **kwargs):
290 291 """Display the LaTeX representation of an object.
291 292
292 293 Parameters
293 294 ----------
294 295 objs : tuple of objects
295 296 The Python objects to display, or if raw=True raw latex data to
296 297 display.
297 298 raw : bool
298 299 Are the data objects raw data or Python objects that need to be
299 300 formatted before display? [default: False]
300 301 metadata : dict (optional)
301 302 Metadata to be associated with the specific mimetype output.
302 303 """
303 304 _display_mimetype('text/latex', objs, **kwargs)
304 305
305 306
306 307 def display_json(*objs, **kwargs):
307 308 """Display the JSON representation of an object.
308 309
309 310 Note that not many frontends support displaying JSON.
310 311
311 312 Parameters
312 313 ----------
313 314 objs : tuple of objects
314 315 The Python objects to display, or if raw=True raw json data to
315 316 display.
316 317 raw : bool
317 318 Are the data objects raw data or Python objects that need to be
318 319 formatted before display? [default: False]
319 320 metadata : dict (optional)
320 321 Metadata to be associated with the specific mimetype output.
321 322 """
322 323 _display_mimetype('application/json', objs, **kwargs)
323 324
324 325
325 326 def display_javascript(*objs, **kwargs):
326 327 """Display the Javascript representation of an object.
327 328
328 329 Parameters
329 330 ----------
330 331 objs : tuple of objects
331 332 The Python objects to display, or if raw=True raw javascript data to
332 333 display.
333 334 raw : bool
334 335 Are the data objects raw data or Python objects that need to be
335 336 formatted before display? [default: False]
336 337 metadata : dict (optional)
337 338 Metadata to be associated with the specific mimetype output.
338 339 """
339 340 _display_mimetype('application/javascript', objs, **kwargs)
340 341
341 342
342 343 def display_pdf(*objs, **kwargs):
343 344 """Display the PDF representation of an object.
344 345
345 346 Parameters
346 347 ----------
347 348 objs : tuple of objects
348 349 The Python objects to display, or if raw=True raw javascript data to
349 350 display.
350 351 raw : bool
351 352 Are the data objects raw data or Python objects that need to be
352 353 formatted before display? [default: False]
353 354 metadata : dict (optional)
354 355 Metadata to be associated with the specific mimetype output.
355 356 """
356 357 _display_mimetype('application/pdf', objs, **kwargs)
357 358
358 359
359 360 #-----------------------------------------------------------------------------
360 361 # Smart classes
361 362 #-----------------------------------------------------------------------------
362 363
363 364
364 365 class DisplayObject(object):
365 366 """An object that wraps data to be displayed."""
366 367
367 368 _read_flags = 'r'
368 369 _show_mem_addr = False
369 370
370 371 def __init__(self, data=None, url=None, filename=None):
371 372 """Create a display object given raw data.
372 373
373 374 When this object is returned by an expression or passed to the
374 375 display function, it will result in the data being displayed
375 376 in the frontend. The MIME type of the data should match the
376 377 subclasses used, so the Png subclass should be used for 'image/png'
377 378 data. If the data is a URL, the data will first be downloaded
378 379 and then displayed. If
379 380
380 381 Parameters
381 382 ----------
382 383 data : unicode, str or bytes
383 384 The raw data or a URL or file to load the data from
384 385 url : unicode
385 386 A URL to download the data from.
386 387 filename : unicode
387 388 Path to a local file to load the data from.
388 389 """
389 390 if data is not None and isinstance(data, string_types):
390 391 if data.startswith('http') and url is None:
391 392 url = data
392 393 filename = None
393 394 data = None
394 395 elif _safe_exists(data) and filename is None:
395 396 url = None
396 397 filename = data
397 398 data = None
398 399
399 400 self.data = data
400 401 self.url = url
401 402 self.filename = None if filename is None else unicode_type(filename)
402 403
403 404 self.reload()
404 405 self._check_data()
405 406
406 407 def __repr__(self):
407 408 if not self._show_mem_addr:
408 409 cls = self.__class__
409 410 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
410 411 else:
411 412 r = super(DisplayObject, self).__repr__()
412 413 return r
413 414
414 415 def _check_data(self):
415 416 """Override in subclasses if there's something to check."""
416 417 pass
417 418
418 419 def reload(self):
419 420 """Reload the raw data from file or URL."""
420 421 if self.filename is not None:
421 422 with open(self.filename, self._read_flags) as f:
422 423 self.data = f.read()
423 424 elif self.url is not None:
424 425 try:
425 426 try:
426 427 from urllib.request import urlopen # Py3
427 428 except ImportError:
428 429 from urllib2 import urlopen
429 430 response = urlopen(self.url)
430 431 self.data = response.read()
431 432 # extract encoding from header, if there is one:
432 433 encoding = None
433 434 for sub in response.headers['content-type'].split(';'):
434 435 sub = sub.strip()
435 436 if sub.startswith('charset'):
436 437 encoding = sub.split('=')[-1].strip()
437 438 break
438 439 # decode data, if an encoding was specified
439 440 if encoding:
440 441 self.data = self.data.decode(encoding, 'replace')
441 442 except:
442 443 self.data = None
443 444
444 445 class TextDisplayObject(DisplayObject):
445 446 """Validate that display data is text"""
446 447 def _check_data(self):
447 448 if self.data is not None and not isinstance(self.data, string_types):
448 449 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
449 450
450 451 class Pretty(TextDisplayObject):
451 452
452 453 def _repr_pretty_(self):
453 454 return self.data
454 455
455 456
456 457 class HTML(TextDisplayObject):
457 458
458 459 def _repr_html_(self):
459 460 return self.data
460 461
461 462 def __html__(self):
462 463 """
463 464 This method exists to inform other HTML-using modules (e.g. Markupsafe,
464 465 htmltag, etc) that this object is HTML and does not need things like
465 466 special characters (<>&) escaped.
466 467 """
467 468 return self._repr_html_()
468 469
469 470
470 471 class Markdown(TextDisplayObject):
471 472
472 473 def _repr_markdown_(self):
473 474 return self.data
474 475
475 476
476 477 class Math(TextDisplayObject):
477 478
478 479 def _repr_latex_(self):
479 480 s = self.data.strip('$')
480 481 return "$$%s$$" % s
481 482
482 483
483 484 class Latex(TextDisplayObject):
484 485
485 486 def _repr_latex_(self):
486 487 return self.data
487 488
488 489
489 490 class SVG(DisplayObject):
490 491
491 492 # wrap data in a property, which extracts the <svg> tag, discarding
492 493 # document headers
493 494 _data = None
494 495
495 496 @property
496 497 def data(self):
497 498 return self._data
498 499
499 500 @data.setter
500 501 def data(self, svg):
501 502 if svg is None:
502 503 self._data = None
503 504 return
504 505 # parse into dom object
505 506 from xml.dom import minidom
506 507 svg = cast_bytes_py2(svg)
507 508 x = minidom.parseString(svg)
508 509 # get svg tag (should be 1)
509 510 found_svg = x.getElementsByTagName('svg')
510 511 if found_svg:
511 512 svg = found_svg[0].toxml()
512 513 else:
513 514 # fallback on the input, trust the user
514 515 # but this is probably an error.
515 516 pass
516 517 svg = cast_unicode(svg)
517 518 self._data = svg
518 519
519 520 def _repr_svg_(self):
520 521 return self.data
521 522
522 523
523 524 class JSON(TextDisplayObject):
524 525
525 526 def _repr_json_(self):
526 527 return self.data
527 528
528 529 css_t = """$("head").append($("<link/>").attr({
529 530 rel: "stylesheet",
530 531 type: "text/css",
531 532 href: "%s"
532 533 }));
533 534 """
534 535
535 536 lib_t1 = """$.getScript("%s", function () {
536 537 """
537 538 lib_t2 = """});
538 539 """
539 540
540 541 class Javascript(TextDisplayObject):
541 542
542 543 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
543 544 """Create a Javascript display object given raw data.
544 545
545 546 When this object is returned by an expression or passed to the
546 547 display function, it will result in the data being displayed
547 548 in the frontend. If the data is a URL, the data will first be
548 549 downloaded and then displayed.
549 550
550 551 In the Notebook, the containing element will be available as `element`,
551 552 and jQuery will be available. Content appended to `element` will be
552 553 visible in the output area.
553 554
554 555 Parameters
555 556 ----------
556 557 data : unicode, str or bytes
557 558 The Javascript source code or a URL to download it from.
558 559 url : unicode
559 560 A URL to download the data from.
560 561 filename : unicode
561 562 Path to a local file to load the data from.
562 563 lib : list or str
563 564 A sequence of Javascript library URLs to load asynchronously before
564 565 running the source code. The full URLs of the libraries should
565 566 be given. A single Javascript library URL can also be given as a
566 567 string.
567 568 css: : list or str
568 569 A sequence of css files to load before running the source code.
569 570 The full URLs of the css files should be given. A single css URL
570 571 can also be given as a string.
571 572 """
572 573 if isinstance(lib, string_types):
573 574 lib = [lib]
574 575 elif lib is None:
575 576 lib = []
576 577 if isinstance(css, string_types):
577 578 css = [css]
578 579 elif css is None:
579 580 css = []
580 581 if not isinstance(lib, (list,tuple)):
581 582 raise TypeError('expected sequence, got: %r' % lib)
582 583 if not isinstance(css, (list,tuple)):
583 584 raise TypeError('expected sequence, got: %r' % css)
584 585 self.lib = lib
585 586 self.css = css
586 587 super(Javascript, self).__init__(data=data, url=url, filename=filename)
587 588
588 589 def _repr_javascript_(self):
589 590 r = ''
590 591 for c in self.css:
591 592 r += css_t % c
592 593 for l in self.lib:
593 594 r += lib_t1 % l
594 595 r += self.data
595 596 r += lib_t2*len(self.lib)
596 597 return r
597 598
598 599 # constants for identifying png/jpeg data
599 600 _PNG = b'\x89PNG\r\n\x1a\n'
600 601 _JPEG = b'\xff\xd8'
601 602
602 603 def _pngxy(data):
603 604 """read the (width, height) from a PNG header"""
604 605 ihdr = data.index(b'IHDR')
605 606 # next 8 bytes are width/height
606 607 w4h4 = data[ihdr+4:ihdr+12]
607 608 return struct.unpack('>ii', w4h4)
608 609
609 610 def _jpegxy(data):
610 611 """read the (width, height) from a JPEG header"""
611 612 # adapted from http://www.64lines.com/jpeg-width-height
612 613
613 614 idx = 4
614 615 while True:
615 616 block_size = struct.unpack('>H', data[idx:idx+2])[0]
616 617 idx = idx + block_size
617 618 if data[idx:idx+2] == b'\xFF\xC0':
618 619 # found Start of Frame
619 620 iSOF = idx
620 621 break
621 622 else:
622 623 # read another block
623 624 idx += 2
624 625
625 626 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
626 627 return w, h
627 628
628 629 class Image(DisplayObject):
629 630
630 631 _read_flags = 'rb'
631 632 _FMT_JPEG = u'jpeg'
632 633 _FMT_PNG = u'png'
633 634 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
634 635
635 636 def __init__(self, data=None, url=None, filename=None, format=u'png', embed=None, width=None, height=None, retina=False):
636 637 """Create a PNG/JPEG image object given raw data.
637 638
638 639 When this object is returned by an input cell or passed to the
639 640 display function, it will result in the image being displayed
640 641 in the frontend.
641 642
642 643 Parameters
643 644 ----------
644 645 data : unicode, str or bytes
645 646 The raw image data or a URL or filename to load the data from.
646 647 This always results in embedded image data.
647 648 url : unicode
648 649 A URL to download the data from. If you specify `url=`,
649 650 the image data will not be embedded unless you also specify `embed=True`.
650 651 filename : unicode
651 652 Path to a local file to load the data from.
652 653 Images from a file are always embedded.
653 654 format : unicode
654 655 The format of the image data (png/jpeg/jpg). If a filename or URL is given
655 656 for format will be inferred from the filename extension.
656 657 embed : bool
657 658 Should the image data be embedded using a data URI (True) or be
658 659 loaded using an <img> tag. Set this to True if you want the image
659 660 to be viewable later with no internet connection in the notebook.
660 661
661 662 Default is `True`, unless the keyword argument `url` is set, then
662 663 default value is `False`.
663 664
664 665 Note that QtConsole is not able to display images if `embed` is set to `False`
665 666 width : int
666 667 Width to which to constrain the image in html
667 668 height : int
668 669 Height to which to constrain the image in html
669 670 retina : bool
670 671 Automatically set the width and height to half of the measured
671 672 width and height.
672 673 This only works for embedded images because it reads the width/height
673 674 from image data.
674 675 For non-embedded images, you can just set the desired display width
675 676 and height directly.
676 677
677 678 Examples
678 679 --------
679 680 # embedded image data, works in qtconsole and notebook
680 681 # when passed positionally, the first arg can be any of raw image data,
681 682 # a URL, or a filename from which to load image data.
682 683 # The result is always embedding image data for inline images.
683 684 Image('http://www.google.fr/images/srpr/logo3w.png')
684 685 Image('/path/to/image.jpg')
685 686 Image(b'RAW_PNG_DATA...')
686 687
687 688 # Specifying Image(url=...) does not embed the image data,
688 689 # it only generates `<img>` tag with a link to the source.
689 690 # This will not work in the qtconsole or offline.
690 691 Image(url='http://www.google.fr/images/srpr/logo3w.png')
691 692
692 693 """
693 694 if filename is not None:
694 695 ext = self._find_ext(filename)
695 696 elif url is not None:
696 697 ext = self._find_ext(url)
697 698 elif data is None:
698 699 raise ValueError("No image data found. Expecting filename, url, or data.")
699 700 elif isinstance(data, string_types) and (
700 701 data.startswith('http') or _safe_exists(data)
701 702 ):
702 703 ext = self._find_ext(data)
703 704 else:
704 705 ext = None
705 706
706 707 if ext is not None:
707 708 format = ext.lower()
708 709 if ext == u'jpg' or ext == u'jpeg':
709 710 format = self._FMT_JPEG
710 711 if ext == u'png':
711 712 format = self._FMT_PNG
712 713 elif isinstance(data, bytes) and format == 'png':
713 714 # infer image type from image data header,
714 715 # only if format might not have been specified.
715 716 if data[:2] == _JPEG:
716 717 format = 'jpeg'
717 718
718 719 self.format = unicode_type(format).lower()
719 720 self.embed = embed if embed is not None else (url is None)
720 721
721 722 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
722 723 raise ValueError("Cannot embed the '%s' image format" % (self.format))
723 724 self.width = width
724 725 self.height = height
725 726 self.retina = retina
726 727 super(Image, self).__init__(data=data, url=url, filename=filename)
727 728
728 729 if retina:
729 730 self._retina_shape()
730 731
731 732 def _retina_shape(self):
732 733 """load pixel-doubled width and height from image data"""
733 734 if not self.embed:
734 735 return
735 736 if self.format == 'png':
736 737 w, h = _pngxy(self.data)
737 738 elif self.format == 'jpeg':
738 739 w, h = _jpegxy(self.data)
739 740 else:
740 741 # retina only supports png
741 742 return
742 743 self.width = w // 2
743 744 self.height = h // 2
744 745
745 746 def reload(self):
746 747 """Reload the raw data from file or URL."""
747 748 if self.embed:
748 749 super(Image,self).reload()
749 750 if self.retina:
750 751 self._retina_shape()
751 752
752 753 def _repr_html_(self):
753 754 if not self.embed:
754 755 width = height = ''
755 756 if self.width:
756 757 width = ' width="%d"' % self.width
757 758 if self.height:
758 759 height = ' height="%d"' % self.height
759 760 return u'<img src="%s"%s%s/>' % (self.url, width, height)
760 761
761 762 def _data_and_metadata(self):
762 763 """shortcut for returning metadata with shape information, if defined"""
763 764 md = {}
764 765 if self.width:
765 766 md['width'] = self.width
766 767 if self.height:
767 768 md['height'] = self.height
768 769 if md:
769 770 return self.data, md
770 771 else:
771 772 return self.data
772 773
773 774 def _repr_png_(self):
774 775 if self.embed and self.format == u'png':
775 776 return self._data_and_metadata()
776 777
777 778 def _repr_jpeg_(self):
778 779 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
779 780 return self._data_and_metadata()
780 781
781 782 def _find_ext(self, s):
782 783 return unicode_type(s.split('.')[-1].lower())
783 784
785 class Video(DisplayObject):
786
787 def __init__(self, data=None, url=None, filename=None, embed=None, mimetype=None):
788 """Create a video object given raw data or an URL.
789
790 When this object is returned by an input cell or passed to the
791 display function, it will result in the video being displayed
792 in the frontend.
793
794 Parameters
795 ----------
796 data : unicode, str or bytes
797 The raw image data or a URL or filename to load the data from.
798 This always results in embedded image data.
799 url : unicode
800 A URL to download the data from. If you specify `url=`,
801 the image data will not be embedded unless you also specify `embed=True`.
802 filename : unicode
803 Path to a local file to load the data from.
804 Videos from a file are always embedded.
805 embed : bool
806 Should the image data be embedded using a data URI (True) or be
807 loaded using an <img> tag. Set this to True if you want the image
808 to be viewable later with no internet connection in the notebook.
809
810 Default is `True`, unless the keyword argument `url` is set, then
811 default value is `False`.
812
813 Note that QtConsole is not able to display images if `embed` is set to `False`
814 mimetype: unicode
815 Specify the mimetype in case you load in a encoded video.
816 Examples
817 --------
818 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
819 Video('path/to/video.mp4')
820 Video('path/to/video.mp4', embed=False)
821 """
822 if url is None and (data.startswith('http') or data.startswith('https')):
823 url = data
824 data = None
825 embed = False
826 elif os.path.exists(data):
827 filename = data
828 data = None
829
830 self.mimetype = mimetype
831 self.embed = embed if embed is not None else (filename is not None)
832 super(Video, self).__init__(data=data, url=url, filename=filename)
833
834 def _repr_html_(self):
835 # External URLs and potentially local files are not embedded into the
836 # notebook output.
837 if not self.embed:
838 url = self.url if self.url is not None else self.filename
839 output = """<video src="{0}" controls>
840 Your browser does not support the <code>video</code> element.
841 </video>""".format(url)
842 return output
843 # Embedded videos uses base64 encoded videos.
844 if self.filename is not None:
845 mimetypes.init()
846 mimetype, encoding = mimetypes.guess_type(self.filename)
847
848 video = open(self.filename, 'rb').read()
849 video_encoded = video.encode('base64')
850 else:
851 video_encoded = self.data
852 mimetype = self.mimetype
853 output = """<video controls>
854 <source src="data:{0};base64,{1}" type="{0}">
855 Your browser does not support the video tag.
856 </video>""".format(mimetype, video_encoded)
857 return output
858
859 def reload(self):
860 # TODO
861 pass
862
863 def _repr_png_(self):
864 # TODO
865 pass
866 def _repr_jpeg_(self):
867 # TODO
868 pass
784 869
785 870 def clear_output(wait=False):
786 871 """Clear the output of the current cell receiving output.
787 872
788 873 Parameters
789 874 ----------
790 875 wait : bool [default: false]
791 876 Wait to clear the output until new output is available to replace it."""
792 877 from IPython.core.interactiveshell import InteractiveShell
793 878 if InteractiveShell.initialized():
794 879 InteractiveShell.instance().display_pub.clear_output(wait)
795 880 else:
796 881 from IPython.utils import io
797 882 print('\033[2K\r', file=io.stdout, end='')
798 883 io.stdout.flush()
799 884 print('\033[2K\r', file=io.stderr, end='')
800 885 io.stderr.flush()
801 886
802 887
803 888 @skip_doctest
804 889 def set_matplotlib_formats(*formats, **kwargs):
805 890 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
806 891
807 892 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
808 893
809 894 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
810 895
811 896 To set this in your config files use the following::
812 897
813 898 c.InlineBackend.figure_formats = {'png', 'jpeg'}
814 899 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
815 900
816 901 Parameters
817 902 ----------
818 903 *formats : strs
819 904 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
820 905 **kwargs :
821 906 Keyword args will be relayed to ``figure.canvas.print_figure``.
822 907 """
823 908 from IPython.core.interactiveshell import InteractiveShell
824 909 from IPython.core.pylabtools import select_figure_formats
825 910 from IPython.kernel.zmq.pylab.config import InlineBackend
826 911 # build kwargs, starting with InlineBackend config
827 912 kw = {}
828 913 cfg = InlineBackend.instance()
829 914 kw.update(cfg.print_figure_kwargs)
830 915 kw.update(**kwargs)
831 916 shell = InteractiveShell.instance()
832 917 select_figure_formats(shell, formats, **kw)
833 918
834 919 @skip_doctest
835 920 def set_matplotlib_close(close=True):
836 921 """Set whether the inline backend closes all figures automatically or not.
837 922
838 923 By default, the inline backend used in the IPython Notebook will close all
839 924 matplotlib figures automatically after each cell is run. This means that
840 925 plots in different cells won't interfere. Sometimes, you may want to make
841 926 a plot in one cell and then refine it in later cells. This can be accomplished
842 927 by::
843 928
844 929 In [1]: set_matplotlib_close(False)
845 930
846 931 To set this in your config files use the following::
847 932
848 933 c.InlineBackend.close_figures = False
849 934
850 935 Parameters
851 936 ----------
852 937 close : bool
853 938 Should all matplotlib figures be automatically closed after each cell is
854 939 run?
855 940 """
856 941 from IPython.kernel.zmq.pylab.config import InlineBackend
857 942 cfg = InlineBackend.instance()
858 943 cfg.close_figures = close
859 944
@@ -1,285 +1,282 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Displayhook for IPython.
3 3
4 4 This defines a callable class that IPython uses for `sys.displayhook`.
5
6 Authors:
7
8 * Fernando Perez
9 * Brian Granger
10 * Robert Kern
11 5 """
12 6
13 #-----------------------------------------------------------------------------
14 # Copyright (C) 2008-2011 The IPython Development Team
15 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
16 #
17 # Distributed under the terms of the BSD License. The full license is in
18 # the file COPYING, distributed as part of this software.
19 #-----------------------------------------------------------------------------
20
21 #-----------------------------------------------------------------------------
22 # Imports
23 #-----------------------------------------------------------------------------
7 # Copyright (c) IPython Development Team.
8 # Distributed under the terms of the Modified BSD License.
9
24 10 from __future__ import print_function
25 11
26 12 import sys
27 13
28 14 from IPython.core.formatters import _safe_get_formatter_method
29 15 from IPython.config.configurable import Configurable
30 16 from IPython.utils import io
31 17 from IPython.utils.py3compat import builtin_mod
32 from IPython.utils.traitlets import Instance
18 from IPython.utils.traitlets import Instance, Float
33 19 from IPython.utils.warn import warn
34 20
35 #-----------------------------------------------------------------------------
36 # Main displayhook class
37 #-----------------------------------------------------------------------------
38
39 21 # TODO: Move the various attributes (cache_size, [others now moved]). Some
40 22 # of these are also attributes of InteractiveShell. They should be on ONE object
41 23 # only and the other objects should ask that one object for their values.
42 24
43 25 class DisplayHook(Configurable):
44 26 """The custom IPython displayhook to replace sys.displayhook.
45 27
46 28 This class does many things, but the basic idea is that it is a callable
47 29 that gets called anytime user code returns a value.
48 30 """
49 31
50 32 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
33 cull_fraction = Float(0.2)
51 34
52 35 def __init__(self, shell=None, cache_size=1000, **kwargs):
53 36 super(DisplayHook, self).__init__(shell=shell, **kwargs)
54
55 37 cache_size_min = 3
56 38 if cache_size <= 0:
57 39 self.do_full_cache = 0
58 40 cache_size = 0
59 41 elif cache_size < cache_size_min:
60 42 self.do_full_cache = 0
61 43 cache_size = 0
62 44 warn('caching was disabled (min value for cache size is %s).' %
63 45 cache_size_min,level=3)
64 46 else:
65 47 self.do_full_cache = 1
66 48
67 49 self.cache_size = cache_size
68 50
69 51 # we need a reference to the user-level namespace
70 52 self.shell = shell
71 53
72 54 self._,self.__,self.___ = '','',''
73 55
74 56 # these are deliberately global:
75 57 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
76 58 self.shell.user_ns.update(to_user_ns)
77 59
78 60 @property
79 61 def prompt_count(self):
80 62 return self.shell.execution_count
81 63
82 64 #-------------------------------------------------------------------------
83 65 # Methods used in __call__. Override these methods to modify the behavior
84 66 # of the displayhook.
85 67 #-------------------------------------------------------------------------
86 68
87 69 def check_for_underscore(self):
88 70 """Check if the user has set the '_' variable by hand."""
89 71 # If something injected a '_' variable in __builtin__, delete
90 72 # ipython's automatic one so we don't clobber that. gettext() in
91 73 # particular uses _, so we need to stay away from it.
92 74 if '_' in builtin_mod.__dict__:
93 75 try:
94 76 del self.shell.user_ns['_']
95 77 except KeyError:
96 78 pass
97 79
98 80 def quiet(self):
99 81 """Should we silence the display hook because of ';'?"""
100 82 # do not print output if input ends in ';'
101 83 try:
102 84 cell = self.shell.history_manager.input_hist_parsed[self.prompt_count]
103 85 return cell.rstrip().endswith(';')
104 86 except IndexError:
105 87 # some uses of ipshellembed may fail here
106 88 return False
107 89
108 90 def start_displayhook(self):
109 91 """Start the displayhook, initializing resources."""
110 92 pass
111 93
112 94 def write_output_prompt(self):
113 95 """Write the output prompt.
114 96
115 97 The default implementation simply writes the prompt to
116 98 ``io.stdout``.
117 99 """
118 100 # Use write, not print which adds an extra space.
119 101 io.stdout.write(self.shell.separate_out)
120 102 outprompt = self.shell.prompt_manager.render('out')
121 103 if self.do_full_cache:
122 104 io.stdout.write(outprompt)
123 105
124 106 def compute_format_data(self, result):
125 107 """Compute format data of the object to be displayed.
126 108
127 109 The format data is a generalization of the :func:`repr` of an object.
128 110 In the default implementation the format data is a :class:`dict` of
129 111 key value pair where the keys are valid MIME types and the values
130 112 are JSON'able data structure containing the raw data for that MIME
131 113 type. It is up to frontends to determine pick a MIME to to use and
132 114 display that data in an appropriate manner.
133 115
134 116 This method only computes the format data for the object and should
135 117 NOT actually print or write that to a stream.
136 118
137 119 Parameters
138 120 ----------
139 121 result : object
140 122 The Python object passed to the display hook, whose format will be
141 123 computed.
142 124
143 125 Returns
144 126 -------
145 127 (format_dict, md_dict) : dict
146 128 format_dict is a :class:`dict` whose keys are valid MIME types and values are
147 129 JSON'able raw data for that MIME type. It is recommended that
148 130 all return values of this should always include the "text/plain"
149 131 MIME type representation of the object.
150 132 md_dict is a :class:`dict` with the same MIME type keys
151 133 of metadata associated with each output.
152 134
153 135 """
154 136 return self.shell.display_formatter.format(result)
155 137
156 138 def write_format_data(self, format_dict, md_dict=None):
157 139 """Write the format data dict to the frontend.
158 140
159 141 This default version of this method simply writes the plain text
160 142 representation of the object to ``io.stdout``. Subclasses should
161 143 override this method to send the entire `format_dict` to the
162 144 frontends.
163 145
164 146 Parameters
165 147 ----------
166 148 format_dict : dict
167 149 The format dict for the object passed to `sys.displayhook`.
168 150 md_dict : dict (optional)
169 151 The metadata dict to be associated with the display data.
170 152 """
153 if 'text/plain' not in format_dict:
154 # nothing to do
155 return
171 156 # We want to print because we want to always make sure we have a
172 157 # newline, even if all the prompt separators are ''. This is the
173 158 # standard IPython behavior.
174 159 result_repr = format_dict['text/plain']
175 160 if '\n' in result_repr:
176 161 # So that multi-line strings line up with the left column of
177 162 # the screen, instead of having the output prompt mess up
178 163 # their first line.
179 164 # We use the prompt template instead of the expanded prompt
180 165 # because the expansion may add ANSI escapes that will interfere
181 166 # with our ability to determine whether or not we should add
182 167 # a newline.
183 168 prompt_template = self.shell.prompt_manager.out_template
184 169 if prompt_template and not prompt_template.endswith('\n'):
185 170 # But avoid extraneous empty lines.
186 171 result_repr = '\n' + result_repr
187 172
188 173 print(result_repr, file=io.stdout)
189 174
190 175 def update_user_ns(self, result):
191 176 """Update user_ns with various things like _, __, _1, etc."""
192 177
193 178 # Avoid recursive reference when displaying _oh/Out
194 179 if result is not self.shell.user_ns['_oh']:
195 180 if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
196 warn('Output cache limit (currently '+
197 repr(self.cache_size)+' entries) hit.\n'
198 'Flushing cache and resetting history counter...\n'
199 'The only history variables available will be _,__,___ and _1\n'
200 'with the current result.')
201
202 self.flush()
181 self.cull_cache()
203 182 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
204 183 # we cause buggy behavior for things like gettext).
205 184
206 185 if '_' not in builtin_mod.__dict__:
207 186 self.___ = self.__
208 187 self.__ = self._
209 188 self._ = result
210 189 self.shell.push({'_':self._,
211 190 '__':self.__,
212 191 '___':self.___}, interactive=False)
213 192
214 193 # hackish access to top-level namespace to create _1,_2... dynamically
215 194 to_main = {}
216 195 if self.do_full_cache:
217 196 new_result = '_'+repr(self.prompt_count)
218 197 to_main[new_result] = result
219 198 self.shell.push(to_main, interactive=False)
220 199 self.shell.user_ns['_oh'][self.prompt_count] = result
221 200
222 201 def log_output(self, format_dict):
223 202 """Log the output."""
203 if 'text/plain' not in format_dict:
204 # nothing to do
205 return
224 206 if self.shell.logger.log_output:
225 207 self.shell.logger.log_write(format_dict['text/plain'], 'output')
226 208 self.shell.history_manager.output_hist_reprs[self.prompt_count] = \
227 209 format_dict['text/plain']
228 210
229 211 def finish_displayhook(self):
230 212 """Finish up all displayhook activities."""
231 213 io.stdout.write(self.shell.separate_out2)
232 214 io.stdout.flush()
233 215
234 216 def __call__(self, result=None):
235 217 """Printing with history cache management.
236 218
237 219 This is invoked everytime the interpreter needs to print, and is
238 220 activated by setting the variable sys.displayhook to it.
239 221 """
240 222 self.check_for_underscore()
241 223 if result is not None and not self.quiet():
242 224 # If _ipython_display_ is defined, use that to display this object.
243 225 display_method = _safe_get_formatter_method(result, '_ipython_display_')
244 226 if display_method is not None:
245 227 try:
246 228 return display_method()
247 229 except NotImplementedError:
248 230 pass
249 231
250 232 self.start_displayhook()
251 233 self.write_output_prompt()
252 234 format_dict, md_dict = self.compute_format_data(result)
253 235 self.write_format_data(format_dict, md_dict)
254 236 self.update_user_ns(result)
255 237 self.log_output(format_dict)
256 238 self.finish_displayhook()
257 239
240 def cull_cache(self):
241 """Output cache is full, cull the oldest entries"""
242 oh = self.shell.user_ns.get('_oh', {})
243 sz = len(oh)
244 cull_count = max(int(sz * self.cull_fraction), 2)
245 warn('Output cache limit (currently {sz} entries) hit.\n'
246 'Flushing oldest {cull_count} entries.'.format(sz=sz, cull_count=cull_count))
247
248 for i, n in enumerate(sorted(oh)):
249 if i >= cull_count:
250 break
251 self.shell.user_ns.pop('_%i' % n, None)
252 oh.pop(n, None)
253
254
258 255 def flush(self):
259 256 if not self.do_full_cache:
260 257 raise ValueError("You shouldn't have reached the cache flush "
261 258 "if full caching is not enabled!")
262 259 # delete auto-generated vars from global namespace
263 260
264 261 for n in range(1,self.prompt_count + 1):
265 262 key = '_'+repr(n)
266 263 try:
267 264 del self.shell.user_ns[key]
268 265 except: pass
269 266 # In some embedded circumstances, the user_ns doesn't have the
270 267 # '_oh' key set up.
271 268 oh = self.shell.user_ns.get('_oh', None)
272 269 if oh is not None:
273 270 oh.clear()
274 271
275 272 # Release our own references to objects:
276 273 self._, self.__, self.___ = '', '', ''
277 274
278 275 if '_' not in builtin_mod.__dict__:
279 276 self.shell.user_ns.update({'_':None,'__':None, '___':None})
280 277 import gc
281 278 # TODO: Is this really needed?
282 279 # IronPython blocks here forever
283 280 if sys.platform != "cli":
284 281 gc.collect()
285 282
@@ -1,139 +1,131 b''
1 1 """Infrastructure for registering and firing callbacks on application events.
2 2
3 3 Unlike :mod:`IPython.core.hooks`, which lets end users set single functions to
4 4 be called at specific times, or a collection of alternative methods to try,
5 5 callbacks are designed to be used by extension authors. A number of callbacks
6 6 can be registered for the same event without needing to be aware of one another.
7 7
8 8 The functions defined in this module are no-ops indicating the names of available
9 9 events and the arguments which will be passed to them.
10 10
11 11 .. note::
12 12
13 13 This API is experimental in IPython 2.0, and may be revised in future versions.
14 14 """
15 15 from __future__ import print_function
16 16
17 17 class EventManager(object):
18 18 """Manage a collection of events and a sequence of callbacks for each.
19 19
20 20 This is attached to :class:`~IPython.core.interactiveshell.InteractiveShell`
21 21 instances as an ``events`` attribute.
22 22
23 23 .. note::
24 24
25 25 This API is experimental in IPython 2.0, and may be revised in future versions.
26 26 """
27 27 def __init__(self, shell, available_events):
28 28 """Initialise the :class:`CallbackManager`.
29 29
30 30 Parameters
31 31 ----------
32 32 shell
33 33 The :class:`~IPython.core.interactiveshell.InteractiveShell` instance
34 34 available_callbacks
35 35 An iterable of names for callback events.
36 36 """
37 37 self.shell = shell
38 38 self.callbacks = {n:[] for n in available_events}
39 39
40 40 def register(self, event, function):
41 41 """Register a new event callback
42 42
43 43 Parameters
44 44 ----------
45 45 event : str
46 46 The event for which to register this callback.
47 47 function : callable
48 48 A function to be called on the given event. It should take the same
49 49 parameters as the appropriate callback prototype.
50 50
51 51 Raises
52 52 ------
53 53 TypeError
54 54 If ``function`` is not callable.
55 55 KeyError
56 56 If ``event`` is not one of the known events.
57 57 """
58 58 if not callable(function):
59 59 raise TypeError('Need a callable, got %r' % function)
60 60 self.callbacks[event].append(function)
61 61
62 62 def unregister(self, event, function):
63 63 """Remove a callback from the given event."""
64 64 self.callbacks[event].remove(function)
65 65
66 def reset(self, event):
67 """Clear all callbacks for the given event."""
68 self.callbacks[event] = []
69
70 def reset_all(self):
71 """Clear all callbacks for all events."""
72 self.callbacks = {n:[] for n in self.callbacks}
73
74 66 def trigger(self, event, *args, **kwargs):
75 67 """Call callbacks for ``event``.
76 68
77 69 Any additional arguments are passed to all callbacks registered for this
78 70 event. Exceptions raised by callbacks are caught, and a message printed.
79 71 """
80 72 for func in self.callbacks[event]:
81 73 try:
82 74 func(*args, **kwargs)
83 75 except Exception:
84 76 print("Error in callback {} (for {}):".format(func, event))
85 77 self.shell.showtraceback()
86 78
87 79 # event_name -> prototype mapping
88 80 available_events = {}
89 81
90 82 def _define_event(callback_proto):
91 83 available_events[callback_proto.__name__] = callback_proto
92 84 return callback_proto
93 85
94 86 # ------------------------------------------------------------------------------
95 87 # Callback prototypes
96 88 #
97 89 # No-op functions which describe the names of available events and the
98 90 # signatures of callbacks for those events.
99 91 # ------------------------------------------------------------------------------
100 92
101 93 @_define_event
102 94 def pre_execute():
103 95 """Fires before code is executed in response to user/frontend action.
104 96
105 97 This includes comm and widget messages and silent execution, as well as user
106 98 code cells."""
107 99 pass
108 100
109 101 @_define_event
110 102 def pre_run_cell():
111 103 """Fires before user-entered code runs."""
112 104 pass
113 105
114 106 @_define_event
115 107 def post_execute():
116 108 """Fires after code is executed in response to user/frontend action.
117 109
118 110 This includes comm and widget messages and silent execution, as well as user
119 111 code cells."""
120 112 pass
121 113
122 114 @_define_event
123 115 def post_run_cell():
124 116 """Fires after user-entered code runs."""
125 117 pass
126 118
127 119 @_define_event
128 120 def shell_initialized(ip):
129 121 """Fires after initialisation of :class:`~IPython.core.interactiveshell.InteractiveShell`.
130 122
131 123 This is before extensions and startup scripts are loaded, so it can only be
132 124 set by subclassing.
133 125
134 126 Parameters
135 127 ----------
136 128 ip : :class:`~IPython.core.interactiveshell.InteractiveShell`
137 129 The newly initialised shell.
138 130 """
139 131 pass
@@ -1,900 +1,912 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Display formatters.
3 3
4 4 Inheritance diagram:
5 5
6 6 .. inheritance-diagram:: IPython.core.formatters
7 7 :parts: 3
8
9 Authors:
10
11 * Robert Kern
12 * Brian Granger
13 8 """
14 #-----------------------------------------------------------------------------
15 # Copyright (C) 2010-2011, IPython Development Team.
16 #
17 # Distributed under the terms of the Modified BSD License.
18 #
19 # The full license is in the file COPYING.txt, distributed with this software.
20 #-----------------------------------------------------------------------------
21 9
22 #-----------------------------------------------------------------------------
23 # Imports
24 #-----------------------------------------------------------------------------
10 # Copyright (c) IPython Development Team.
11 # Distributed under the terms of the Modified BSD License.
25 12
26 # Stdlib imports
27 13 import abc
28 14 import inspect
29 15 import sys
16 import traceback
30 17 import types
31 18 import warnings
32 19
33 20 from IPython.external.decorator import decorator
34 21
35 # Our own imports
36 22 from IPython.config.configurable import Configurable
23 from IPython.core.getipython import get_ipython
37 24 from IPython.lib import pretty
38 25 from IPython.utils.traitlets import (
39 26 Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
40 27 )
41 28 from IPython.utils.py3compat import (
42 29 unicode_to_str, with_metaclass, PY3, string_types, unicode_type,
43 30 )
44 31
45 32 if PY3:
46 33 from io import StringIO
47 34 else:
48 35 from StringIO import StringIO
49 36
50 37
51 38 #-----------------------------------------------------------------------------
52 39 # The main DisplayFormatter class
53 40 #-----------------------------------------------------------------------------
54 41
55 42
56 43 def _valid_formatter(f):
57 44 """Return whether an object is a valid formatter
58 45
59 46 Cases checked:
60 47
61 48 - bound methods OK
62 49 - unbound methods NO
63 50 - callable with zero args OK
64 51 """
65 52 if f is None:
66 53 return False
67 54 elif isinstance(f, type(str.find)):
68 55 # unbound methods on compiled classes have type method_descriptor
69 56 return False
70 57 elif isinstance(f, types.BuiltinFunctionType):
71 58 # bound methods on compiled classes have type builtin_function
72 59 return True
73 60 elif callable(f):
74 61 # anything that works with zero args should be okay
75 62 try:
76 63 inspect.getcallargs(f)
77 64 except Exception:
78 65 return False
79 66 else:
80 67 return True
81 68 return False
82 69
83 70 def _safe_get_formatter_method(obj, name):
84 71 """Safely get a formatter method"""
85 72 method = pretty._safe_getattr(obj, name, None)
86 73 # formatter methods must be bound
87 74 if _valid_formatter(method):
88 75 return method
89 76
90 77
91 78 class DisplayFormatter(Configurable):
92 79
93 80 # When set to true only the default plain text formatter will be used.
94 81 plain_text_only = Bool(False, config=True)
95 82 def _plain_text_only_changed(self, name, old, new):
96 83 warnings.warn("""DisplayFormatter.plain_text_only is deprecated.
97 84
98 85 Use DisplayFormatter.active_types = ['text/plain']
99 86 for the same effect.
100 87 """, DeprecationWarning)
101 88 if new:
102 89 self.active_types = ['text/plain']
103 90 else:
104 91 self.active_types = self.format_types
105 92
106 93 active_types = List(Unicode, config=True,
107 94 help="""List of currently active mime-types to display.
108 95 You can use this to set a white-list for formats to display.
109 96
110 97 Most users will not need to change this value.
111 98 """)
112 99 def _active_types_default(self):
113 100 return self.format_types
114 101
115 102 def _active_types_changed(self, name, old, new):
116 103 for key, formatter in self.formatters.items():
117 104 if key in new:
118 105 formatter.enabled = True
119 106 else:
120 107 formatter.enabled = False
121 108
122 109 # A dict of formatter whose keys are format types (MIME types) and whose
123 110 # values are subclasses of BaseFormatter.
124 111 formatters = Dict()
125 112 def _formatters_default(self):
126 113 """Activate the default formatters."""
127 114 formatter_classes = [
128 115 PlainTextFormatter,
129 116 HTMLFormatter,
130 117 MarkdownFormatter,
131 118 SVGFormatter,
132 119 PNGFormatter,
133 120 PDFFormatter,
134 121 JPEGFormatter,
135 122 LatexFormatter,
136 123 JSONFormatter,
137 124 JavascriptFormatter
138 125 ]
139 126 d = {}
140 127 for cls in formatter_classes:
141 128 f = cls(parent=self)
142 129 d[f.format_type] = f
143 130 return d
144 131
145 132 def format(self, obj, include=None, exclude=None):
146 133 """Return a format data dict for an object.
147 134
148 135 By default all format types will be computed.
149 136
150 137 The following MIME types are currently implemented:
151 138
152 139 * text/plain
153 140 * text/html
154 141 * text/markdown
155 142 * text/latex
156 143 * application/json
157 144 * application/javascript
158 145 * application/pdf
159 146 * image/png
160 147 * image/jpeg
161 148 * image/svg+xml
162 149
163 150 Parameters
164 151 ----------
165 152 obj : object
166 153 The Python object whose format data will be computed.
167 154 include : list or tuple, optional
168 155 A list of format type strings (MIME types) to include in the
169 156 format data dict. If this is set *only* the format types included
170 157 in this list will be computed.
171 158 exclude : list or tuple, optional
172 159 A list of format type string (MIME types) to exclude in the format
173 160 data dict. If this is set all format types will be computed,
174 161 except for those included in this argument.
175 162
176 163 Returns
177 164 -------
178 165 (format_dict, metadata_dict) : tuple of two dicts
179 166
180 167 format_dict is a dictionary of key/value pairs, one of each format that was
181 168 generated for the object. The keys are the format types, which
182 169 will usually be MIME type strings and the values and JSON'able
183 170 data structure containing the raw data for the representation in
184 171 that format.
185 172
186 173 metadata_dict is a dictionary of metadata about each mime-type output.
187 174 Its keys will be a strict subset of the keys in format_dict.
188 175 """
189 176 format_dict = {}
190 177 md_dict = {}
191 178
192 179 for format_type, formatter in self.formatters.items():
193 180 if include and format_type not in include:
194 181 continue
195 182 if exclude and format_type in exclude:
196 183 continue
197 184
198 185 md = None
199 186 try:
200 187 data = formatter(obj)
201 188 except:
202 189 # FIXME: log the exception
203 190 raise
204 191
205 192 # formatters can return raw data or (data, metadata)
206 193 if isinstance(data, tuple) and len(data) == 2:
207 194 data, md = data
208 195
209 196 if data is not None:
210 197 format_dict[format_type] = data
211 198 if md is not None:
212 199 md_dict[format_type] = md
213 200
214 201 return format_dict, md_dict
215 202
216 203 @property
217 204 def format_types(self):
218 205 """Return the format types (MIME types) of the active formatters."""
219 206 return list(self.formatters.keys())
220 207
221 208
222 209 #-----------------------------------------------------------------------------
223 210 # Formatters for specific format types (text, html, svg, etc.)
224 211 #-----------------------------------------------------------------------------
225 212
213
214 def _safe_repr(obj):
215 """Try to return a repr of an object
216
217 always returns a string, at least.
218 """
219 try:
220 return repr(obj)
221 except Exception as e:
222 return "un-repr-able object (%r)" % e
223
224
226 225 class FormatterWarning(UserWarning):
227 226 """Warning class for errors in formatters"""
228 227
229 228 @decorator
230 229 def warn_format_error(method, self, *args, **kwargs):
231 230 """decorator for warning on failed format call"""
232 231 try:
233 232 r = method(self, *args, **kwargs)
234 except NotImplementedError as e:
233 except NotImplementedError:
235 234 # don't warn on NotImplementedErrors
236 235 return None
237 except Exception as e:
238 warnings.warn("Exception in %s formatter: %s" % (self.format_type, e),
239 FormatterWarning,
240 )
236 except Exception:
237 exc_info = sys.exc_info()
238 ip = get_ipython()
239 if ip is not None:
240 ip.showtraceback(exc_info)
241 else:
242 traceback.print_exception(*exc_info)
241 243 return None
242 244 if r is None or isinstance(r, self._return_type) or \
243 245 (isinstance(r, tuple) and r and isinstance(r[0], self._return_type)):
244 246 return r
245 247 else:
246 248 warnings.warn(
247 249 "%s formatter returned invalid type %s (expected %s) for object: %s" % \
248 (self.format_type, type(r), self._return_type, pretty._safe_repr(args[0])),
250 (self.format_type, type(r), self._return_type, _safe_repr(args[0])),
249 251 FormatterWarning
250 252 )
251 253
252 254
253 255 class FormatterABC(with_metaclass(abc.ABCMeta, object)):
254 256 """ Abstract base class for Formatters.
255 257
256 258 A formatter is a callable class that is responsible for computing the
257 259 raw format data for a particular format type (MIME type). For example,
258 260 an HTML formatter would have a format type of `text/html` and would return
259 261 the HTML representation of the object when called.
260 262 """
261 263
262 264 # The format type of the data returned, usually a MIME type.
263 265 format_type = 'text/plain'
264 266
265 267 # Is the formatter enabled...
266 268 enabled = True
267 269
268 270 @abc.abstractmethod
269 271 @warn_format_error
270 272 def __call__(self, obj):
271 273 """Return a JSON'able representation of the object.
272 274
273 275 If the object cannot be formatted by this formatter,
274 276 warn and return None.
275 277 """
276 278 return repr(obj)
277 279
278 280
279 281 def _mod_name_key(typ):
280 282 """Return a (__module__, __name__) tuple for a type.
281 283
282 284 Used as key in Formatter.deferred_printers.
283 285 """
284 286 module = getattr(typ, '__module__', None)
285 287 name = getattr(typ, '__name__', None)
286 288 return (module, name)
287 289
288 290
289 291 def _get_type(obj):
290 292 """Return the type of an instance (old and new-style)"""
291 293 return getattr(obj, '__class__', None) or type(obj)
292 294
293 295 _raise_key_error = object()
294 296
295 297
296 298 class BaseFormatter(Configurable):
297 299 """A base formatter class that is configurable.
298 300
299 301 This formatter should usually be used as the base class of all formatters.
300 302 It is a traited :class:`Configurable` class and includes an extensible
301 303 API for users to determine how their objects are formatted. The following
302 304 logic is used to find a function to format an given object.
303 305
304 306 1. The object is introspected to see if it has a method with the name
305 307 :attr:`print_method`. If is does, that object is passed to that method
306 308 for formatting.
307 309 2. If no print method is found, three internal dictionaries are consulted
308 310 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
309 311 and :attr:`deferred_printers`.
310 312
311 313 Users should use these dictionaries to register functions that will be
312 314 used to compute the format data for their objects (if those objects don't
313 315 have the special print methods). The easiest way of using these
314 316 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
315 317 methods.
316 318
317 319 If no function/callable is found to compute the format data, ``None`` is
318 320 returned and this format type is not used.
319 321 """
320 322
321 323 format_type = Unicode('text/plain')
322 324 _return_type = string_types
323 325
324 326 enabled = Bool(True, config=True)
325 327
326 328 print_method = ObjectName('__repr__')
327 329
328 330 # The singleton printers.
329 331 # Maps the IDs of the builtin singleton objects to the format functions.
330 332 singleton_printers = Dict(config=True)
331 333
332 334 # The type-specific printers.
333 335 # Map type objects to the format functions.
334 336 type_printers = Dict(config=True)
335 337
336 338 # The deferred-import type-specific printers.
337 339 # Map (modulename, classname) pairs to the format functions.
338 340 deferred_printers = Dict(config=True)
339 341
340 342 @warn_format_error
341 343 def __call__(self, obj):
342 344 """Compute the format for an object."""
343 345 if self.enabled:
344 346 # lookup registered printer
345 347 try:
346 348 printer = self.lookup(obj)
347 349 except KeyError:
348 350 pass
349 351 else:
350 352 return printer(obj)
351 353 # Finally look for special method names
352 354 method = _safe_get_formatter_method(obj, self.print_method)
353 355 if method is not None:
354 356 return method()
355 357 return None
356 358 else:
357 359 return None
358 360
359 361 def __contains__(self, typ):
360 362 """map in to lookup_by_type"""
361 363 try:
362 364 self.lookup_by_type(typ)
363 365 except KeyError:
364 366 return False
365 367 else:
366 368 return True
367 369
368 370 def lookup(self, obj):
369 371 """Look up the formatter for a given instance.
370 372
371 373 Parameters
372 374 ----------
373 375 obj : object instance
374 376
375 377 Returns
376 378 -------
377 379 f : callable
378 380 The registered formatting callable for the type.
379 381
380 382 Raises
381 383 ------
382 384 KeyError if the type has not been registered.
383 385 """
384 386 # look for singleton first
385 387 obj_id = id(obj)
386 388 if obj_id in self.singleton_printers:
387 389 return self.singleton_printers[obj_id]
388 390 # then lookup by type
389 391 return self.lookup_by_type(_get_type(obj))
390 392
391 393 def lookup_by_type(self, typ):
392 394 """Look up the registered formatter for a type.
393 395
394 396 Parameters
395 397 ----------
396 398 typ : type or '__module__.__name__' string for a type
397 399
398 400 Returns
399 401 -------
400 402 f : callable
401 403 The registered formatting callable for the type.
402 404
403 405 Raises
404 406 ------
405 407 KeyError if the type has not been registered.
406 408 """
407 409 if isinstance(typ, string_types):
408 410 typ_key = tuple(typ.rsplit('.',1))
409 411 if typ_key not in self.deferred_printers:
410 412 # We may have it cached in the type map. We will have to
411 413 # iterate over all of the types to check.
412 414 for cls in self.type_printers:
413 415 if _mod_name_key(cls) == typ_key:
414 416 return self.type_printers[cls]
415 417 else:
416 418 return self.deferred_printers[typ_key]
417 419 else:
418 420 for cls in pretty._get_mro(typ):
419 421 if cls in self.type_printers or self._in_deferred_types(cls):
420 422 return self.type_printers[cls]
421 423
422 424 # If we have reached here, the lookup failed.
423 425 raise KeyError("No registered printer for {0!r}".format(typ))
424 426
425 427 def for_type(self, typ, func=None):
426 428 """Add a format function for a given type.
427 429
428 430 Parameters
429 431 -----------
430 432 typ : type or '__module__.__name__' string for a type
431 433 The class of the object that will be formatted using `func`.
432 434 func : callable
433 435 A callable for computing the format data.
434 436 `func` will be called with the object to be formatted,
435 437 and will return the raw data in this formatter's format.
436 438 Subclasses may use a different call signature for the
437 439 `func` argument.
438 440
439 441 If `func` is None or not specified, there will be no change,
440 442 only returning the current value.
441 443
442 444 Returns
443 445 -------
444 446 oldfunc : callable
445 447 The currently registered callable.
446 448 If you are registering a new formatter,
447 449 this will be the previous value (to enable restoring later).
448 450 """
449 451 # if string given, interpret as 'pkg.module.class_name'
450 452 if isinstance(typ, string_types):
451 453 type_module, type_name = typ.rsplit('.', 1)
452 454 return self.for_type_by_name(type_module, type_name, func)
453 455
454 456 try:
455 457 oldfunc = self.lookup_by_type(typ)
456 458 except KeyError:
457 459 oldfunc = None
458 460
459 461 if func is not None:
460 462 self.type_printers[typ] = func
461 463
462 464 return oldfunc
463 465
464 466 def for_type_by_name(self, type_module, type_name, func=None):
465 467 """Add a format function for a type specified by the full dotted
466 468 module and name of the type, rather than the type of the object.
467 469
468 470 Parameters
469 471 ----------
470 472 type_module : str
471 473 The full dotted name of the module the type is defined in, like
472 474 ``numpy``.
473 475 type_name : str
474 476 The name of the type (the class name), like ``dtype``
475 477 func : callable
476 478 A callable for computing the format data.
477 479 `func` will be called with the object to be formatted,
478 480 and will return the raw data in this formatter's format.
479 481 Subclasses may use a different call signature for the
480 482 `func` argument.
481 483
482 484 If `func` is None or unspecified, there will be no change,
483 485 only returning the current value.
484 486
485 487 Returns
486 488 -------
487 489 oldfunc : callable
488 490 The currently registered callable.
489 491 If you are registering a new formatter,
490 492 this will be the previous value (to enable restoring later).
491 493 """
492 494 key = (type_module, type_name)
493 495
494 496 try:
495 497 oldfunc = self.lookup_by_type("%s.%s" % key)
496 498 except KeyError:
497 499 oldfunc = None
498 500
499 501 if func is not None:
500 502 self.deferred_printers[key] = func
501 503 return oldfunc
502 504
503 505 def pop(self, typ, default=_raise_key_error):
504 506 """Pop a formatter for the given type.
505 507
506 508 Parameters
507 509 ----------
508 510 typ : type or '__module__.__name__' string for a type
509 511 default : object
510 512 value to be returned if no formatter is registered for typ.
511 513
512 514 Returns
513 515 -------
514 516 obj : object
515 517 The last registered object for the type.
516 518
517 519 Raises
518 520 ------
519 521 KeyError if the type is not registered and default is not specified.
520 522 """
521 523
522 524 if isinstance(typ, string_types):
523 525 typ_key = tuple(typ.rsplit('.',1))
524 526 if typ_key not in self.deferred_printers:
525 527 # We may have it cached in the type map. We will have to
526 528 # iterate over all of the types to check.
527 529 for cls in self.type_printers:
528 530 if _mod_name_key(cls) == typ_key:
529 531 old = self.type_printers.pop(cls)
530 532 break
531 533 else:
532 534 old = default
533 535 else:
534 536 old = self.deferred_printers.pop(typ_key)
535 537 else:
536 538 if typ in self.type_printers:
537 539 old = self.type_printers.pop(typ)
538 540 else:
539 541 old = self.deferred_printers.pop(_mod_name_key(typ), default)
540 542 if old is _raise_key_error:
541 543 raise KeyError("No registered value for {0!r}".format(typ))
542 544 return old
543 545
544 546 def _in_deferred_types(self, cls):
545 547 """
546 548 Check if the given class is specified in the deferred type registry.
547 549
548 550 Successful matches will be moved to the regular type registry for future use.
549 551 """
550 552 mod = getattr(cls, '__module__', None)
551 553 name = getattr(cls, '__name__', None)
552 554 key = (mod, name)
553 555 if key in self.deferred_printers:
554 556 # Move the printer over to the regular registry.
555 557 printer = self.deferred_printers.pop(key)
556 558 self.type_printers[cls] = printer
557 559 return True
558 560 return False
559 561
560 562
561 563 class PlainTextFormatter(BaseFormatter):
562 564 """The default pretty-printer.
563 565
564 566 This uses :mod:`IPython.lib.pretty` to compute the format data of
565 567 the object. If the object cannot be pretty printed, :func:`repr` is used.
566 568 See the documentation of :mod:`IPython.lib.pretty` for details on
567 569 how to write pretty printers. Here is a simple example::
568 570
569 571 def dtype_pprinter(obj, p, cycle):
570 572 if cycle:
571 573 return p.text('dtype(...)')
572 574 if hasattr(obj, 'fields'):
573 575 if obj.fields is None:
574 576 p.text(repr(obj))
575 577 else:
576 578 p.begin_group(7, 'dtype([')
577 579 for i, field in enumerate(obj.descr):
578 580 if i > 0:
579 581 p.text(',')
580 582 p.breakable()
581 583 p.pretty(field)
582 584 p.end_group(7, '])')
583 585 """
584 586
585 587 # The format type of data returned.
586 588 format_type = Unicode('text/plain')
587 589
588 590 # This subclass ignores this attribute as it always need to return
589 591 # something.
590 592 enabled = Bool(True, config=False)
591
593
594 max_seq_length = Integer(pretty.MAX_SEQ_LENGTH, config=True,
595 help="""Truncate large collections (lists, dicts, tuples, sets) to this size.
596
597 Set to 0 to disable truncation.
598 """
599 )
600
592 601 # Look for a _repr_pretty_ methods to use for pretty printing.
593 602 print_method = ObjectName('_repr_pretty_')
594 603
595 604 # Whether to pretty-print or not.
596 605 pprint = Bool(True, config=True)
597 606
598 607 # Whether to be verbose or not.
599 608 verbose = Bool(False, config=True)
600 609
601 610 # The maximum width.
602 611 max_width = Integer(79, config=True)
603 612
604 613 # The newline character.
605 614 newline = Unicode('\n', config=True)
606 615
607 616 # format-string for pprinting floats
608 617 float_format = Unicode('%r')
609 618 # setter for float precision, either int or direct format-string
610 619 float_precision = CUnicode('', config=True)
611 620
612 621 def _float_precision_changed(self, name, old, new):
613 622 """float_precision changed, set float_format accordingly.
614 623
615 624 float_precision can be set by int or str.
616 625 This will set float_format, after interpreting input.
617 626 If numpy has been imported, numpy print precision will also be set.
618 627
619 628 integer `n` sets format to '%.nf', otherwise, format set directly.
620 629
621 630 An empty string returns to defaults (repr for float, 8 for numpy).
622 631
623 632 This parameter can be set via the '%precision' magic.
624 633 """
625 634
626 635 if '%' in new:
627 636 # got explicit format string
628 637 fmt = new
629 638 try:
630 639 fmt%3.14159
631 640 except Exception:
632 641 raise ValueError("Precision must be int or format string, not %r"%new)
633 642 elif new:
634 643 # otherwise, should be an int
635 644 try:
636 645 i = int(new)
637 646 assert i >= 0
638 647 except ValueError:
639 648 raise ValueError("Precision must be int or format string, not %r"%new)
640 649 except AssertionError:
641 650 raise ValueError("int precision must be non-negative, not %r"%i)
642 651
643 652 fmt = '%%.%if'%i
644 653 if 'numpy' in sys.modules:
645 654 # set numpy precision if it has been imported
646 655 import numpy
647 656 numpy.set_printoptions(precision=i)
648 657 else:
649 658 # default back to repr
650 659 fmt = '%r'
651 660 if 'numpy' in sys.modules:
652 661 import numpy
653 662 # numpy default is 8
654 663 numpy.set_printoptions(precision=8)
655 664 self.float_format = fmt
656 665
657 666 # Use the default pretty printers from IPython.lib.pretty.
658 667 def _singleton_printers_default(self):
659 668 return pretty._singleton_pprinters.copy()
660 669
661 670 def _type_printers_default(self):
662 671 d = pretty._type_pprinters.copy()
663 672 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
664 673 return d
665 674
666 675 def _deferred_printers_default(self):
667 676 return pretty._deferred_type_pprinters.copy()
668 677
669 678 #### FormatterABC interface ####
670 679
671 680 @warn_format_error
672 681 def __call__(self, obj):
673 682 """Compute the pretty representation of the object."""
674 683 if not self.pprint:
675 return pretty._safe_repr(obj)
684 return repr(obj)
676 685 else:
677 686 # This uses use StringIO, as cStringIO doesn't handle unicode.
678 687 stream = StringIO()
679 688 # self.newline.encode() is a quick fix for issue gh-597. We need to
680 689 # ensure that stream does not get a mix of unicode and bytestrings,
681 690 # or it will cause trouble.
682 691 printer = pretty.RepresentationPrinter(stream, self.verbose,
683 692 self.max_width, unicode_to_str(self.newline),
693 max_seq_length=self.max_seq_length,
684 694 singleton_pprinters=self.singleton_printers,
685 695 type_pprinters=self.type_printers,
686 696 deferred_pprinters=self.deferred_printers)
687 697 printer.pretty(obj)
688 698 printer.flush()
689 699 return stream.getvalue()
690 700
691 701
692 702 class HTMLFormatter(BaseFormatter):
693 703 """An HTML formatter.
694 704
695 705 To define the callables that compute the HTML representation of your
696 706 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
697 707 or :meth:`for_type_by_name` methods to register functions that handle
698 708 this.
699 709
700 710 The return value of this formatter should be a valid HTML snippet that
701 711 could be injected into an existing DOM. It should *not* include the
702 712 ```<html>`` or ```<body>`` tags.
703 713 """
704 714 format_type = Unicode('text/html')
705 715
706 716 print_method = ObjectName('_repr_html_')
707 717
708 718
709 719 class MarkdownFormatter(BaseFormatter):
710 720 """A Markdown formatter.
711 721
712 722 To define the callables that compute the Markdown representation of your
713 723 objects, define a :meth:`_repr_markdown_` method or use the :meth:`for_type`
714 724 or :meth:`for_type_by_name` methods to register functions that handle
715 725 this.
716 726
717 727 The return value of this formatter should be a valid Markdown.
718 728 """
719 729 format_type = Unicode('text/markdown')
720 730
721 731 print_method = ObjectName('_repr_markdown_')
722 732
723 733 class SVGFormatter(BaseFormatter):
724 734 """An SVG formatter.
725 735
726 736 To define the callables that compute the SVG representation of your
727 737 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
728 738 or :meth:`for_type_by_name` methods to register functions that handle
729 739 this.
730 740
731 741 The return value of this formatter should be valid SVG enclosed in
732 742 ```<svg>``` tags, that could be injected into an existing DOM. It should
733 743 *not* include the ```<html>`` or ```<body>`` tags.
734 744 """
735 745 format_type = Unicode('image/svg+xml')
736 746
737 747 print_method = ObjectName('_repr_svg_')
738 748
739 749
740 750 class PNGFormatter(BaseFormatter):
741 751 """A PNG formatter.
742 752
743 753 To define the callables that compute the PNG representation of your
744 754 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
745 755 or :meth:`for_type_by_name` methods to register functions that handle
746 756 this.
747 757
748 758 The return value of this formatter should be raw PNG data, *not*
749 759 base64 encoded.
750 760 """
751 761 format_type = Unicode('image/png')
752 762
753 763 print_method = ObjectName('_repr_png_')
754 764
755 765 _return_type = (bytes, unicode_type)
756 766
757 767
758 768 class JPEGFormatter(BaseFormatter):
759 769 """A JPEG formatter.
760 770
761 771 To define the callables that compute the JPEG representation of your
762 772 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
763 773 or :meth:`for_type_by_name` methods to register functions that handle
764 774 this.
765 775
766 776 The return value of this formatter should be raw JPEG data, *not*
767 777 base64 encoded.
768 778 """
769 779 format_type = Unicode('image/jpeg')
770 780
771 781 print_method = ObjectName('_repr_jpeg_')
772 782
773 783 _return_type = (bytes, unicode_type)
774 784
775 785
776 786 class LatexFormatter(BaseFormatter):
777 787 """A LaTeX formatter.
778 788
779 789 To define the callables that compute the LaTeX representation of your
780 790 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
781 791 or :meth:`for_type_by_name` methods to register functions that handle
782 792 this.
783 793
784 794 The return value of this formatter should be a valid LaTeX equation,
785 795 enclosed in either ```$```, ```$$``` or another LaTeX equation
786 796 environment.
787 797 """
788 798 format_type = Unicode('text/latex')
789 799
790 800 print_method = ObjectName('_repr_latex_')
791 801
792 802
793 803 class JSONFormatter(BaseFormatter):
794 804 """A JSON string formatter.
795 805
796 806 To define the callables that compute the JSON string representation of
797 807 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
798 808 or :meth:`for_type_by_name` methods to register functions that handle
799 809 this.
800 810
801 811 The return value of this formatter should be a valid JSON string.
802 812 """
803 813 format_type = Unicode('application/json')
804 814
805 815 print_method = ObjectName('_repr_json_')
806 816
807 817
808 818 class JavascriptFormatter(BaseFormatter):
809 819 """A Javascript formatter.
810 820
811 821 To define the callables that compute the Javascript representation of
812 822 your objects, define a :meth:`_repr_javascript_` method or use the
813 823 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
814 824 that handle this.
815 825
816 826 The return value of this formatter should be valid Javascript code and
817 827 should *not* be enclosed in ```<script>``` tags.
818 828 """
819 829 format_type = Unicode('application/javascript')
820 830
821 831 print_method = ObjectName('_repr_javascript_')
822 832
823 833
824 834 class PDFFormatter(BaseFormatter):
825 835 """A PDF formatter.
826 836
827 837 To define the callables that compute the PDF representation of your
828 838 objects, define a :meth:`_repr_pdf_` method or use the :meth:`for_type`
829 839 or :meth:`for_type_by_name` methods to register functions that handle
830 840 this.
831 841
832 842 The return value of this formatter should be raw PDF data, *not*
833 843 base64 encoded.
834 844 """
835 845 format_type = Unicode('application/pdf')
836 846
837 847 print_method = ObjectName('_repr_pdf_')
838 848
849 _return_type = (bytes, unicode_type)
850
839 851
840 852 FormatterABC.register(BaseFormatter)
841 853 FormatterABC.register(PlainTextFormatter)
842 854 FormatterABC.register(HTMLFormatter)
843 855 FormatterABC.register(MarkdownFormatter)
844 856 FormatterABC.register(SVGFormatter)
845 857 FormatterABC.register(PNGFormatter)
846 858 FormatterABC.register(PDFFormatter)
847 859 FormatterABC.register(JPEGFormatter)
848 860 FormatterABC.register(LatexFormatter)
849 861 FormatterABC.register(JSONFormatter)
850 862 FormatterABC.register(JavascriptFormatter)
851 863
852 864
853 865 def format_display_data(obj, include=None, exclude=None):
854 866 """Return a format data dict for an object.
855 867
856 868 By default all format types will be computed.
857 869
858 870 The following MIME types are currently implemented:
859 871
860 872 * text/plain
861 873 * text/html
862 874 * text/markdown
863 875 * text/latex
864 876 * application/json
865 877 * application/javascript
866 878 * application/pdf
867 879 * image/png
868 880 * image/jpeg
869 881 * image/svg+xml
870 882
871 883 Parameters
872 884 ----------
873 885 obj : object
874 886 The Python object whose format data will be computed.
875 887
876 888 Returns
877 889 -------
878 890 format_dict : dict
879 891 A dictionary of key/value pairs, one or each format that was
880 892 generated for the object. The keys are the format types, which
881 893 will usually be MIME type strings and the values and JSON'able
882 894 data structure containing the raw data for the representation in
883 895 that format.
884 896 include : list or tuple, optional
885 897 A list of format type strings (MIME types) to include in the
886 898 format data dict. If this is set *only* the format types included
887 899 in this list will be computed.
888 900 exclude : list or tuple, optional
889 901 A list of format type string (MIME types) to exclue in the format
890 902 data dict. If this is set all format types will be computed,
891 903 except for those included in this argument.
892 904 """
893 905 from IPython.core.interactiveshell import InteractiveShell
894 906
895 907 InteractiveShell.instance().display_formatter.format(
896 908 obj,
897 909 include,
898 910 exclude
899 911 )
900 912
@@ -1,855 +1,870 b''
1 1 """ History related magics and functionality """
2 2 #-----------------------------------------------------------------------------
3 3 # Copyright (C) 2010-2011 The IPython Development Team.
4 4 #
5 5 # Distributed under the terms of the BSD License.
6 6 #
7 7 # The full license is in the file COPYING.txt, distributed with this software.
8 8 #-----------------------------------------------------------------------------
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Imports
12 12 #-----------------------------------------------------------------------------
13 13 from __future__ import print_function
14 14
15 15 # Stdlib imports
16 16 import atexit
17 17 import datetime
18 18 import os
19 19 import re
20 20 try:
21 21 import sqlite3
22 22 except ImportError:
23 23 try:
24 24 from pysqlite2 import dbapi2 as sqlite3
25 25 except ImportError:
26 26 sqlite3 = None
27 27 import threading
28 28
29 29 # Our own packages
30 30 from IPython.config.configurable import Configurable
31 31 from IPython.external.decorator import decorator
32 32 from IPython.utils.decorators import undoc
33 33 from IPython.utils.path import locate_profile
34 34 from IPython.utils import py3compat
35 35 from IPython.utils.traitlets import (
36 36 Any, Bool, Dict, Instance, Integer, List, Unicode, TraitError,
37 37 )
38 38 from IPython.utils.warn import warn
39 39
40 40 #-----------------------------------------------------------------------------
41 41 # Classes and functions
42 42 #-----------------------------------------------------------------------------
43 43
44 44 @undoc
45 45 class DummyDB(object):
46 46 """Dummy DB that will act as a black hole for history.
47 47
48 48 Only used in the absence of sqlite"""
49 49 def execute(*args, **kwargs):
50 50 return []
51 51
52 52 def commit(self, *args, **kwargs):
53 53 pass
54 54
55 55 def __enter__(self, *args, **kwargs):
56 56 pass
57 57
58 58 def __exit__(self, *args, **kwargs):
59 59 pass
60 60
61 61
62 62 @decorator
63 63 def needs_sqlite(f, self, *a, **kw):
64 64 """Decorator: return an empty list in the absence of sqlite."""
65 65 if sqlite3 is None or not self.enabled:
66 66 return []
67 67 else:
68 68 return f(self, *a, **kw)
69 69
70 70
71 71 if sqlite3 is not None:
72 72 DatabaseError = sqlite3.DatabaseError
73 73 else:
74 74 @undoc
75 75 class DatabaseError(Exception):
76 76 "Dummy exception when sqlite could not be imported. Should never occur."
77 77
78 78 @decorator
79 79 def catch_corrupt_db(f, self, *a, **kw):
80 80 """A decorator which wraps HistoryAccessor method calls to catch errors from
81 81 a corrupt SQLite database, move the old database out of the way, and create
82 82 a new one.
83 83 """
84 84 try:
85 85 return f(self, *a, **kw)
86 86 except DatabaseError:
87 87 if os.path.isfile(self.hist_file):
88 88 # Try to move the file out of the way
89 89 base,ext = os.path.splitext(self.hist_file)
90 90 newpath = base + '-corrupt' + ext
91 91 os.rename(self.hist_file, newpath)
92 92 self.init_db()
93 93 print("ERROR! History file wasn't a valid SQLite database.",
94 94 "It was moved to %s" % newpath, "and a new file created.")
95 95 return []
96 96
97 97 else:
98 98 # The hist_file is probably :memory: or something else.
99 99 raise
100 100
101 class HistoryAccessorBase(Configurable):
102 """An abstract class for History Accessors """
101 103
104 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
105 raise NotImplementedError
106
107 def search(self, pattern="*", raw=True, search_raw=True,
108 output=False, n=None, unique=False):
109 raise NotImplementedError
110
111 def get_range(self, session, start=1, stop=None, raw=True,output=False):
112 raise NotImplementedError
102 113
103 class HistoryAccessor(Configurable):
114 def get_range_by_str(self, rangestr, raw=True, output=False):
115 raise NotImplementedError
116
117
118 class HistoryAccessor(HistoryAccessorBase):
104 119 """Access the history database without adding to it.
105 120
106 121 This is intended for use by standalone history tools. IPython shells use
107 122 HistoryManager, below, which is a subclass of this."""
108 123
109 124 # String holding the path to the history file
110 125 hist_file = Unicode(config=True,
111 126 help="""Path to file to use for SQLite history database.
112 127
113 128 By default, IPython will put the history database in the IPython
114 129 profile directory. If you would rather share one history among
115 130 profiles, you can set this value in each, so that they are consistent.
116 131
117 132 Due to an issue with fcntl, SQLite is known to misbehave on some NFS
118 133 mounts. If you see IPython hanging, try setting this to something on a
119 134 local disk, e.g::
120 135
121 136 ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite
122 137
123 138 """)
124 139
125 140 enabled = Bool(True, config=True,
126 141 help="""enable the SQLite history
127 142
128 143 set enabled=False to disable the SQLite history,
129 144 in which case there will be no stored history, no SQLite connection,
130 145 and no background saving thread. This may be necessary in some
131 146 threaded environments where IPython is embedded.
132 147 """
133 148 )
134 149
135 150 connection_options = Dict(config=True,
136 151 help="""Options for configuring the SQLite connection
137 152
138 153 These options are passed as keyword args to sqlite3.connect
139 154 when establishing database conenctions.
140 155 """
141 156 )
142 157
143 158 # The SQLite database
144 159 db = Any()
145 160 def _db_changed(self, name, old, new):
146 161 """validate the db, since it can be an Instance of two different types"""
147 162 connection_types = (DummyDB,)
148 163 if sqlite3 is not None:
149 164 connection_types = (DummyDB, sqlite3.Connection)
150 165 if not isinstance(new, connection_types):
151 166 msg = "%s.db must be sqlite3 Connection or DummyDB, not %r" % \
152 167 (self.__class__.__name__, new)
153 168 raise TraitError(msg)
154 169
155 170 def __init__(self, profile='default', hist_file=u'', **traits):
156 171 """Create a new history accessor.
157 172
158 173 Parameters
159 174 ----------
160 175 profile : str
161 176 The name of the profile from which to open history.
162 177 hist_file : str
163 178 Path to an SQLite history database stored by IPython. If specified,
164 179 hist_file overrides profile.
165 180 config : :class:`~IPython.config.loader.Config`
166 181 Config object. hist_file can also be set through this.
167 182 """
168 183 # We need a pointer back to the shell for various tasks.
169 184 super(HistoryAccessor, self).__init__(**traits)
170 185 # defer setting hist_file from kwarg until after init,
171 186 # otherwise the default kwarg value would clobber any value
172 187 # set by config
173 188 if hist_file:
174 189 self.hist_file = hist_file
175 190
176 191 if self.hist_file == u'':
177 192 # No one has set the hist_file, yet.
178 193 self.hist_file = self._get_hist_file_name(profile)
179 194
180 195 if sqlite3 is None and self.enabled:
181 196 warn("IPython History requires SQLite, your history will not be saved")
182 197 self.enabled = False
183 198
184 199 self.init_db()
185 200
186 201 def _get_hist_file_name(self, profile='default'):
187 202 """Find the history file for the given profile name.
188 203
189 204 This is overridden by the HistoryManager subclass, to use the shell's
190 205 active profile.
191 206
192 207 Parameters
193 208 ----------
194 209 profile : str
195 210 The name of a profile which has a history file.
196 211 """
197 212 return os.path.join(locate_profile(profile), 'history.sqlite')
198 213
199 214 @catch_corrupt_db
200 215 def init_db(self):
201 216 """Connect to the database, and create tables if necessary."""
202 217 if not self.enabled:
203 218 self.db = DummyDB()
204 219 return
205 220
206 221 # use detect_types so that timestamps return datetime objects
207 222 kwargs = dict(detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
208 223 kwargs.update(self.connection_options)
209 224 self.db = sqlite3.connect(self.hist_file, **kwargs)
210 225 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
211 226 primary key autoincrement, start timestamp,
212 227 end timestamp, num_cmds integer, remark text)""")
213 228 self.db.execute("""CREATE TABLE IF NOT EXISTS history
214 229 (session integer, line integer, source text, source_raw text,
215 230 PRIMARY KEY (session, line))""")
216 231 # Output history is optional, but ensure the table's there so it can be
217 232 # enabled later.
218 233 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
219 234 (session integer, line integer, output text,
220 235 PRIMARY KEY (session, line))""")
221 236 self.db.commit()
222 237
223 238 def writeout_cache(self):
224 239 """Overridden by HistoryManager to dump the cache before certain
225 240 database lookups."""
226 241 pass
227 242
228 243 ## -------------------------------
229 244 ## Methods for retrieving history:
230 245 ## -------------------------------
231 246 def _run_sql(self, sql, params, raw=True, output=False):
232 247 """Prepares and runs an SQL query for the history database.
233 248
234 249 Parameters
235 250 ----------
236 251 sql : str
237 252 Any filtering expressions to go after SELECT ... FROM ...
238 253 params : tuple
239 254 Parameters passed to the SQL query (to replace "?")
240 255 raw, output : bool
241 256 See :meth:`get_range`
242 257
243 258 Returns
244 259 -------
245 260 Tuples as :meth:`get_range`
246 261 """
247 262 toget = 'source_raw' if raw else 'source'
248 263 sqlfrom = "history"
249 264 if output:
250 265 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
251 266 toget = "history.%s, output_history.output" % toget
252 267 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
253 268 (toget, sqlfrom) + sql, params)
254 269 if output: # Regroup into 3-tuples, and parse JSON
255 270 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
256 271 return cur
257 272
258 273 @needs_sqlite
259 274 @catch_corrupt_db
260 275 def get_session_info(self, session):
261 276 """Get info about a session.
262 277
263 278 Parameters
264 279 ----------
265 280
266 281 session : int
267 282 Session number to retrieve.
268 283
269 284 Returns
270 285 -------
271 286
272 287 session_id : int
273 288 Session ID number
274 289 start : datetime
275 290 Timestamp for the start of the session.
276 291 end : datetime
277 292 Timestamp for the end of the session, or None if IPython crashed.
278 293 num_cmds : int
279 294 Number of commands run, or None if IPython crashed.
280 295 remark : unicode
281 296 A manually set description.
282 297 """
283 298 query = "SELECT * from sessions where session == ?"
284 299 return self.db.execute(query, (session,)).fetchone()
285 300
286 301 @catch_corrupt_db
287 302 def get_last_session_id(self):
288 303 """Get the last session ID currently in the database.
289 304
290 305 Within IPython, this should be the same as the value stored in
291 306 :attr:`HistoryManager.session_number`.
292 307 """
293 308 for record in self.get_tail(n=1, include_latest=True):
294 309 return record[0]
295 310
296 311 @catch_corrupt_db
297 312 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
298 313 """Get the last n lines from the history database.
299 314
300 315 Parameters
301 316 ----------
302 317 n : int
303 318 The number of lines to get
304 319 raw, output : bool
305 320 See :meth:`get_range`
306 321 include_latest : bool
307 322 If False (default), n+1 lines are fetched, and the latest one
308 323 is discarded. This is intended to be used where the function
309 324 is called by a user command, which it should not return.
310 325
311 326 Returns
312 327 -------
313 328 Tuples as :meth:`get_range`
314 329 """
315 330 self.writeout_cache()
316 331 if not include_latest:
317 332 n += 1
318 333 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
319 334 (n,), raw=raw, output=output)
320 335 if not include_latest:
321 336 return reversed(list(cur)[1:])
322 337 return reversed(list(cur))
323 338
324 339 @catch_corrupt_db
325 340 def search(self, pattern="*", raw=True, search_raw=True,
326 341 output=False, n=None, unique=False):
327 342 """Search the database using unix glob-style matching (wildcards
328 343 * and ?).
329 344
330 345 Parameters
331 346 ----------
332 347 pattern : str
333 348 The wildcarded pattern to match when searching
334 349 search_raw : bool
335 350 If True, search the raw input, otherwise, the parsed input
336 351 raw, output : bool
337 352 See :meth:`get_range`
338 353 n : None or int
339 354 If an integer is given, it defines the limit of
340 355 returned entries.
341 356 unique : bool
342 357 When it is true, return only unique entries.
343 358
344 359 Returns
345 360 -------
346 361 Tuples as :meth:`get_range`
347 362 """
348 363 tosearch = "source_raw" if search_raw else "source"
349 364 if output:
350 365 tosearch = "history." + tosearch
351 366 self.writeout_cache()
352 367 sqlform = "WHERE %s GLOB ?" % tosearch
353 368 params = (pattern,)
354 369 if unique:
355 370 sqlform += ' GROUP BY {0}'.format(tosearch)
356 371 if n is not None:
357 372 sqlform += " ORDER BY session DESC, line DESC LIMIT ?"
358 373 params += (n,)
359 374 elif unique:
360 375 sqlform += " ORDER BY session, line"
361 376 cur = self._run_sql(sqlform, params, raw=raw, output=output)
362 377 if n is not None:
363 378 return reversed(list(cur))
364 379 return cur
365 380
366 381 @catch_corrupt_db
367 382 def get_range(self, session, start=1, stop=None, raw=True,output=False):
368 383 """Retrieve input by session.
369 384
370 385 Parameters
371 386 ----------
372 387 session : int
373 388 Session number to retrieve.
374 389 start : int
375 390 First line to retrieve.
376 391 stop : int
377 392 End of line range (excluded from output itself). If None, retrieve
378 393 to the end of the session.
379 394 raw : bool
380 395 If True, return untranslated input
381 396 output : bool
382 397 If True, attempt to include output. This will be 'real' Python
383 398 objects for the current session, or text reprs from previous
384 399 sessions if db_log_output was enabled at the time. Where no output
385 400 is found, None is used.
386 401
387 402 Returns
388 403 -------
389 404 entries
390 405 An iterator over the desired lines. Each line is a 3-tuple, either
391 406 (session, line, input) if output is False, or
392 407 (session, line, (input, output)) if output is True.
393 408 """
394 409 if stop:
395 410 lineclause = "line >= ? AND line < ?"
396 411 params = (session, start, stop)
397 412 else:
398 413 lineclause = "line>=?"
399 414 params = (session, start)
400 415
401 416 return self._run_sql("WHERE session==? AND %s" % lineclause,
402 417 params, raw=raw, output=output)
403 418
404 419 def get_range_by_str(self, rangestr, raw=True, output=False):
405 420 """Get lines of history from a string of ranges, as used by magic
406 421 commands %hist, %save, %macro, etc.
407 422
408 423 Parameters
409 424 ----------
410 425 rangestr : str
411 426 A string specifying ranges, e.g. "5 ~2/1-4". See
412 427 :func:`magic_history` for full details.
413 428 raw, output : bool
414 429 As :meth:`get_range`
415 430
416 431 Returns
417 432 -------
418 433 Tuples as :meth:`get_range`
419 434 """
420 435 for sess, s, e in extract_hist_ranges(rangestr):
421 436 for line in self.get_range(sess, s, e, raw=raw, output=output):
422 437 yield line
423 438
424 439
425 440 class HistoryManager(HistoryAccessor):
426 441 """A class to organize all history-related functionality in one place.
427 442 """
428 443 # Public interface
429 444
430 445 # An instance of the IPython shell we are attached to
431 446 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
432 447 # Lists to hold processed and raw history. These start with a blank entry
433 448 # so that we can index them starting from 1
434 449 input_hist_parsed = List([""])
435 450 input_hist_raw = List([""])
436 451 # A list of directories visited during session
437 452 dir_hist = List()
438 453 def _dir_hist_default(self):
439 454 try:
440 455 return [py3compat.getcwd()]
441 456 except OSError:
442 457 return []
443 458
444 459 # A dict of output history, keyed with ints from the shell's
445 460 # execution count.
446 461 output_hist = Dict()
447 462 # The text/plain repr of outputs.
448 463 output_hist_reprs = Dict()
449 464
450 465 # The number of the current session in the history database
451 466 session_number = Integer()
452 467
453 468 db_log_output = Bool(False, config=True,
454 469 help="Should the history database include output? (default: no)"
455 470 )
456 471 db_cache_size = Integer(0, config=True,
457 472 help="Write to database every x commands (higher values save disk access & power).\n"
458 473 "Values of 1 or less effectively disable caching."
459 474 )
460 475 # The input and output caches
461 476 db_input_cache = List()
462 477 db_output_cache = List()
463 478
464 479 # History saving in separate thread
465 480 save_thread = Instance('IPython.core.history.HistorySavingThread')
466 481 try: # Event is a function returning an instance of _Event...
467 482 save_flag = Instance(threading._Event)
468 483 except AttributeError: # ...until Python 3.3, when it's a class.
469 484 save_flag = Instance(threading.Event)
470 485
471 486 # Private interface
472 487 # Variables used to store the three last inputs from the user. On each new
473 488 # history update, we populate the user's namespace with these, shifted as
474 489 # necessary.
475 490 _i00 = Unicode(u'')
476 491 _i = Unicode(u'')
477 492 _ii = Unicode(u'')
478 493 _iii = Unicode(u'')
479 494
480 495 # A regex matching all forms of the exit command, so that we don't store
481 496 # them in the history (it's annoying to rewind the first entry and land on
482 497 # an exit call).
483 498 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
484 499
485 500 def __init__(self, shell=None, config=None, **traits):
486 501 """Create a new history manager associated with a shell instance.
487 502 """
488 503 # We need a pointer back to the shell for various tasks.
489 504 super(HistoryManager, self).__init__(shell=shell, config=config,
490 505 **traits)
491 506 self.save_flag = threading.Event()
492 507 self.db_input_cache_lock = threading.Lock()
493 508 self.db_output_cache_lock = threading.Lock()
494 509 if self.enabled and self.hist_file != ':memory:':
495 510 self.save_thread = HistorySavingThread(self)
496 511 self.save_thread.start()
497 512
498 513 self.new_session()
499 514
500 515 def _get_hist_file_name(self, profile=None):
501 516 """Get default history file name based on the Shell's profile.
502 517
503 518 The profile parameter is ignored, but must exist for compatibility with
504 519 the parent class."""
505 520 profile_dir = self.shell.profile_dir.location
506 521 return os.path.join(profile_dir, 'history.sqlite')
507 522
508 523 @needs_sqlite
509 524 def new_session(self, conn=None):
510 525 """Get a new session number."""
511 526 if conn is None:
512 527 conn = self.db
513 528
514 529 with conn:
515 530 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
516 531 NULL, "") """, (datetime.datetime.now(),))
517 532 self.session_number = cur.lastrowid
518 533
519 534 def end_session(self):
520 535 """Close the database session, filling in the end time and line count."""
521 536 self.writeout_cache()
522 537 with self.db:
523 538 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
524 539 session==?""", (datetime.datetime.now(),
525 540 len(self.input_hist_parsed)-1, self.session_number))
526 541 self.session_number = 0
527 542
528 543 def name_session(self, name):
529 544 """Give the current session a name in the history database."""
530 545 with self.db:
531 546 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
532 547 (name, self.session_number))
533 548
534 549 def reset(self, new_session=True):
535 550 """Clear the session history, releasing all object references, and
536 551 optionally open a new session."""
537 552 self.output_hist.clear()
538 553 # The directory history can't be completely empty
539 554 self.dir_hist[:] = [py3compat.getcwd()]
540 555
541 556 if new_session:
542 557 if self.session_number:
543 558 self.end_session()
544 559 self.input_hist_parsed[:] = [""]
545 560 self.input_hist_raw[:] = [""]
546 561 self.new_session()
547
562
548 563 # ------------------------------
549 564 # Methods for retrieving history
550 565 # ------------------------------
551 566 def get_session_info(self, session=0):
552 567 """Get info about a session.
553 568
554 569 Parameters
555 570 ----------
556 571
557 572 session : int
558 573 Session number to retrieve. The current session is 0, and negative
559 574 numbers count back from current session, so -1 is the previous session.
560 575
561 576 Returns
562 577 -------
563 578
564 579 session_id : int
565 580 Session ID number
566 581 start : datetime
567 582 Timestamp for the start of the session.
568 583 end : datetime
569 584 Timestamp for the end of the session, or None if IPython crashed.
570 585 num_cmds : int
571 586 Number of commands run, or None if IPython crashed.
572 587 remark : unicode
573 588 A manually set description.
574 589 """
575 590 if session <= 0:
576 591 session += self.session_number
577 592
578 593 return super(HistoryManager, self).get_session_info(session=session)
579 594
580 595 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
581 596 """Get input and output history from the current session. Called by
582 597 get_range, and takes similar parameters."""
583 598 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
584 599
585 600 n = len(input_hist)
586 601 if start < 0:
587 602 start += n
588 603 if not stop or (stop > n):
589 604 stop = n
590 605 elif stop < 0:
591 606 stop += n
592 607
593 608 for i in range(start, stop):
594 609 if output:
595 610 line = (input_hist[i], self.output_hist_reprs.get(i))
596 611 else:
597 612 line = input_hist[i]
598 613 yield (0, i, line)
599 614
600 615 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
601 616 """Retrieve input by session.
602 617
603 618 Parameters
604 619 ----------
605 620 session : int
606 621 Session number to retrieve. The current session is 0, and negative
607 622 numbers count back from current session, so -1 is previous session.
608 623 start : int
609 624 First line to retrieve.
610 625 stop : int
611 626 End of line range (excluded from output itself). If None, retrieve
612 627 to the end of the session.
613 628 raw : bool
614 629 If True, return untranslated input
615 630 output : bool
616 631 If True, attempt to include output. This will be 'real' Python
617 632 objects for the current session, or text reprs from previous
618 633 sessions if db_log_output was enabled at the time. Where no output
619 634 is found, None is used.
620 635
621 636 Returns
622 637 -------
623 638 entries
624 639 An iterator over the desired lines. Each line is a 3-tuple, either
625 640 (session, line, input) if output is False, or
626 641 (session, line, (input, output)) if output is True.
627 642 """
628 643 if session <= 0:
629 644 session += self.session_number
630 645 if session==self.session_number: # Current session
631 646 return self._get_range_session(start, stop, raw, output)
632 647 return super(HistoryManager, self).get_range(session, start, stop, raw,
633 648 output)
634 649
635 650 ## ----------------------------
636 651 ## Methods for storing history:
637 652 ## ----------------------------
638 653 def store_inputs(self, line_num, source, source_raw=None):
639 654 """Store source and raw input in history and create input cache
640 655 variables ``_i*``.
641 656
642 657 Parameters
643 658 ----------
644 659 line_num : int
645 660 The prompt number of this input.
646 661
647 662 source : str
648 663 Python input.
649 664
650 665 source_raw : str, optional
651 666 If given, this is the raw input without any IPython transformations
652 667 applied to it. If not given, ``source`` is used.
653 668 """
654 669 if source_raw is None:
655 670 source_raw = source
656 671 source = source.rstrip('\n')
657 672 source_raw = source_raw.rstrip('\n')
658 673
659 674 # do not store exit/quit commands
660 675 if self._exit_re.match(source_raw.strip()):
661 676 return
662 677
663 678 self.input_hist_parsed.append(source)
664 679 self.input_hist_raw.append(source_raw)
665 680
666 681 with self.db_input_cache_lock:
667 682 self.db_input_cache.append((line_num, source, source_raw))
668 683 # Trigger to flush cache and write to DB.
669 684 if len(self.db_input_cache) >= self.db_cache_size:
670 685 self.save_flag.set()
671 686
672 687 # update the auto _i variables
673 688 self._iii = self._ii
674 689 self._ii = self._i
675 690 self._i = self._i00
676 691 self._i00 = source_raw
677 692
678 693 # hackish access to user namespace to create _i1,_i2... dynamically
679 694 new_i = '_i%s' % line_num
680 695 to_main = {'_i': self._i,
681 696 '_ii': self._ii,
682 697 '_iii': self._iii,
683 698 new_i : self._i00 }
684 699
685 700 if self.shell is not None:
686 701 self.shell.push(to_main, interactive=False)
687 702
688 703 def store_output(self, line_num):
689 704 """If database output logging is enabled, this saves all the
690 705 outputs from the indicated prompt number to the database. It's
691 706 called by run_cell after code has been executed.
692 707
693 708 Parameters
694 709 ----------
695 710 line_num : int
696 711 The line number from which to save outputs
697 712 """
698 713 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
699 714 return
700 715 output = self.output_hist_reprs[line_num]
701 716
702 717 with self.db_output_cache_lock:
703 718 self.db_output_cache.append((line_num, output))
704 719 if self.db_cache_size <= 1:
705 720 self.save_flag.set()
706 721
707 722 def _writeout_input_cache(self, conn):
708 723 with conn:
709 724 for line in self.db_input_cache:
710 725 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
711 726 (self.session_number,)+line)
712 727
713 728 def _writeout_output_cache(self, conn):
714 729 with conn:
715 730 for line in self.db_output_cache:
716 731 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
717 732 (self.session_number,)+line)
718 733
719 734 @needs_sqlite
720 735 def writeout_cache(self, conn=None):
721 736 """Write any entries in the cache to the database."""
722 737 if conn is None:
723 738 conn = self.db
724 739
725 740 with self.db_input_cache_lock:
726 741 try:
727 742 self._writeout_input_cache(conn)
728 743 except sqlite3.IntegrityError:
729 744 self.new_session(conn)
730 745 print("ERROR! Session/line number was not unique in",
731 746 "database. History logging moved to new session",
732 747 self.session_number)
733 748 try:
734 749 # Try writing to the new session. If this fails, don't
735 750 # recurse
736 751 self._writeout_input_cache(conn)
737 752 except sqlite3.IntegrityError:
738 753 pass
739 754 finally:
740 755 self.db_input_cache = []
741 756
742 757 with self.db_output_cache_lock:
743 758 try:
744 759 self._writeout_output_cache(conn)
745 760 except sqlite3.IntegrityError:
746 761 print("!! Session/line number for output was not unique",
747 762 "in database. Output will not be stored.")
748 763 finally:
749 764 self.db_output_cache = []
750 765
751 766
752 767 class HistorySavingThread(threading.Thread):
753 768 """This thread takes care of writing history to the database, so that
754 769 the UI isn't held up while that happens.
755 770
756 771 It waits for the HistoryManager's save_flag to be set, then writes out
757 772 the history cache. The main thread is responsible for setting the flag when
758 773 the cache size reaches a defined threshold."""
759 774 daemon = True
760 775 stop_now = False
761 776 enabled = True
762 777 def __init__(self, history_manager):
763 778 super(HistorySavingThread, self).__init__(name="IPythonHistorySavingThread")
764 779 self.history_manager = history_manager
765 780 self.enabled = history_manager.enabled
766 781 atexit.register(self.stop)
767 782
768 783 @needs_sqlite
769 784 def run(self):
770 785 # We need a separate db connection per thread:
771 786 try:
772 787 self.db = sqlite3.connect(self.history_manager.hist_file,
773 788 **self.history_manager.connection_options
774 789 )
775 790 while True:
776 791 self.history_manager.save_flag.wait()
777 792 if self.stop_now:
778 793 self.db.close()
779 794 return
780 795 self.history_manager.save_flag.clear()
781 796 self.history_manager.writeout_cache(self.db)
782 797 except Exception as e:
783 798 print(("The history saving thread hit an unexpected error (%s)."
784 799 "History will not be written to the database.") % repr(e))
785 800
786 801 def stop(self):
787 802 """This can be called from the main thread to safely stop this thread.
788 803
789 804 Note that it does not attempt to write out remaining history before
790 805 exiting. That should be done by calling the HistoryManager's
791 806 end_session method."""
792 807 self.stop_now = True
793 808 self.history_manager.save_flag.set()
794 809 self.join()
795 810
796 811
797 812 # To match, e.g. ~5/8-~2/3
798 813 range_re = re.compile(r"""
799 814 ((?P<startsess>~?\d+)/)?
800 815 (?P<start>\d+)?
801 816 ((?P<sep>[\-:])
802 817 ((?P<endsess>~?\d+)/)?
803 818 (?P<end>\d+))?
804 819 $""", re.VERBOSE)
805 820
806 821
807 822 def extract_hist_ranges(ranges_str):
808 823 """Turn a string of history ranges into 3-tuples of (session, start, stop).
809 824
810 825 Examples
811 826 --------
812 827 >>> list(extract_hist_ranges("~8/5-~7/4 2"))
813 828 [(-8, 5, None), (-7, 1, 5), (0, 2, 3)]
814 829 """
815 830 for range_str in ranges_str.split():
816 831 rmatch = range_re.match(range_str)
817 832 if not rmatch:
818 833 continue
819 834 start = rmatch.group("start")
820 835 if start:
821 836 start = int(start)
822 837 end = rmatch.group("end")
823 838 # If no end specified, get (a, a + 1)
824 839 end = int(end) if end else start + 1
825 840 else: # start not specified
826 841 if not rmatch.group('startsess'): # no startsess
827 842 continue
828 843 start = 1
829 844 end = None # provide the entire session hist
830 845
831 846 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
832 847 end += 1
833 848 startsess = rmatch.group("startsess") or "0"
834 849 endsess = rmatch.group("endsess") or startsess
835 850 startsess = int(startsess.replace("~","-"))
836 851 endsess = int(endsess.replace("~","-"))
837 852 assert endsess >= startsess, "start session must be earlier than end session"
838 853
839 854 if endsess == startsess:
840 855 yield (startsess, start, end)
841 856 continue
842 857 # Multiple sessions in one range:
843 858 yield (startsess, start, None)
844 859 for sess in range(startsess+1, endsess):
845 860 yield (sess, 1, None)
846 861 yield (endsess, 1, end)
847 862
848 863
849 864 def _format_lineno(session, line):
850 865 """Helper function to format line numbers properly."""
851 866 if session == 0:
852 867 return str(line)
853 868 return "%s#%s" % (session, line)
854 869
855 870
@@ -1,638 +1,682 b''
1 1 """Input handling and transformation machinery.
2 2
3 3 The first class in this module, :class:`InputSplitter`, is designed to tell when
4 4 input from a line-oriented frontend is complete and should be executed, and when
5 5 the user should be prompted for another line of code instead. The name 'input
6 6 splitter' is largely for historical reasons.
7 7
8 8 A companion, :class:`IPythonInputSplitter`, provides the same functionality but
9 9 with full support for the extended IPython syntax (magics, system calls, etc).
10 10 The code to actually do these transformations is in :mod:`IPython.core.inputtransformer`.
11 11 :class:`IPythonInputSplitter` feeds the raw code to the transformers in order
12 12 and stores the results.
13 13
14 14 For more details, see the class docstrings below.
15 15 """
16 16
17 17 # Copyright (c) IPython Development Team.
18 18 # Distributed under the terms of the Modified BSD License.
19 19 import ast
20 20 import codeop
21 21 import re
22 22 import sys
23 import warnings
23 24
24 25 from IPython.utils.py3compat import cast_unicode
25 26 from IPython.core.inputtransformer import (leading_indent,
26 27 classic_prompt,
27 28 ipy_prompt,
28 29 strip_encoding_cookie,
29 30 cellmagic,
30 31 assemble_logical_lines,
31 32 help_end,
32 33 escaped_commands,
33 34 assign_from_magic,
34 35 assign_from_system,
35 36 assemble_python_lines,
36 37 )
37 38
38 39 # These are available in this module for backwards compatibility.
39 40 from IPython.core.inputtransformer import (ESC_SHELL, ESC_SH_CAP, ESC_HELP,
40 41 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,
41 42 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN, ESC_SEQUENCES)
42 43
43 44 #-----------------------------------------------------------------------------
44 45 # Utilities
45 46 #-----------------------------------------------------------------------------
46 47
47 48 # FIXME: These are general-purpose utilities that later can be moved to the
48 49 # general ward. Kept here for now because we're being very strict about test
49 50 # coverage with this code, and this lets us ensure that we keep 100% coverage
50 51 # while developing.
51 52
52 53 # compiled regexps for autoindent management
53 54 dedent_re = re.compile('|'.join([
54 55 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
55 56 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
56 57 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
57 58 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
58 59 r'^\s+pass\s*$', # pass (optionally followed by trailing spaces)
59 60 r'^\s+break\s*$', # break (optionally followed by trailing spaces)
60 61 r'^\s+continue\s*$', # continue (optionally followed by trailing spaces)
61 62 ]))
62 63 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
63 64
64 65 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
65 66 # before pure comments
66 67 comment_line_re = re.compile('^\s*\#')
67 68
68 69
69 70 def num_ini_spaces(s):
70 71 """Return the number of initial spaces in a string.
71 72
72 73 Note that tabs are counted as a single space. For now, we do *not* support
73 74 mixing of tabs and spaces in the user's input.
74 75
75 76 Parameters
76 77 ----------
77 78 s : string
78 79
79 80 Returns
80 81 -------
81 82 n : int
82 83 """
83 84
84 85 ini_spaces = ini_spaces_re.match(s)
85 86 if ini_spaces:
86 87 return ini_spaces.end()
87 88 else:
88 89 return 0
89 90
90 91 def last_blank(src):
91 92 """Determine if the input source ends in a blank.
92 93
93 94 A blank is either a newline or a line consisting of whitespace.
94 95
95 96 Parameters
96 97 ----------
97 98 src : string
98 99 A single or multiline string.
99 100 """
100 101 if not src: return False
101 102 ll = src.splitlines()[-1]
102 103 return (ll == '') or ll.isspace()
103 104
104 105
105 106 last_two_blanks_re = re.compile(r'\n\s*\n\s*$', re.MULTILINE)
106 107 last_two_blanks_re2 = re.compile(r'.+\n\s*\n\s+$', re.MULTILINE)
107 108
108 109 def last_two_blanks(src):
109 110 """Determine if the input source ends in two blanks.
110 111
111 112 A blank is either a newline or a line consisting of whitespace.
112 113
113 114 Parameters
114 115 ----------
115 116 src : string
116 117 A single or multiline string.
117 118 """
118 119 if not src: return False
119 120 # The logic here is tricky: I couldn't get a regexp to work and pass all
120 121 # the tests, so I took a different approach: split the source by lines,
121 122 # grab the last two and prepend '###\n' as a stand-in for whatever was in
122 123 # the body before the last two lines. Then, with that structure, it's
123 124 # possible to analyze with two regexps. Not the most elegant solution, but
124 125 # it works. If anyone tries to change this logic, make sure to validate
125 126 # the whole test suite first!
126 127 new_src = '\n'.join(['###\n'] + src.splitlines()[-2:])
127 128 return (bool(last_two_blanks_re.match(new_src)) or
128 129 bool(last_two_blanks_re2.match(new_src)) )
129 130
130 131
131 132 def remove_comments(src):
132 133 """Remove all comments from input source.
133 134
134 135 Note: comments are NOT recognized inside of strings!
135 136
136 137 Parameters
137 138 ----------
138 139 src : string
139 140 A single or multiline input string.
140 141
141 142 Returns
142 143 -------
143 144 String with all Python comments removed.
144 145 """
145 146
146 147 return re.sub('#.*', '', src)
147 148
148 149
149 150 def get_input_encoding():
150 151 """Return the default standard input encoding.
151 152
152 153 If sys.stdin has no encoding, 'ascii' is returned."""
153 154 # There are strange environments for which sys.stdin.encoding is None. We
154 155 # ensure that a valid encoding is returned.
155 156 encoding = getattr(sys.stdin, 'encoding', None)
156 157 if encoding is None:
157 158 encoding = 'ascii'
158 159 return encoding
159 160
160 161 #-----------------------------------------------------------------------------
161 162 # Classes and functions for normal Python syntax handling
162 163 #-----------------------------------------------------------------------------
163 164
164 165 class InputSplitter(object):
165 166 r"""An object that can accumulate lines of Python source before execution.
166 167
167 168 This object is designed to be fed python source line-by-line, using
168 169 :meth:`push`. It will return on each push whether the currently pushed
169 170 code could be executed already. In addition, it provides a method called
170 171 :meth:`push_accepts_more` that can be used to query whether more input
171 172 can be pushed into a single interactive block.
172 173
173 174 This is a simple example of how an interactive terminal-based client can use
174 175 this tool::
175 176
176 177 isp = InputSplitter()
177 178 while isp.push_accepts_more():
178 179 indent = ' '*isp.indent_spaces
179 180 prompt = '>>> ' + indent
180 181 line = indent + raw_input(prompt)
181 182 isp.push(line)
182 183 print 'Input source was:\n', isp.source_reset(),
183 184 """
184 185 # Number of spaces of indentation computed from input that has been pushed
185 186 # so far. This is the attributes callers should query to get the current
186 187 # indentation level, in order to provide auto-indent facilities.
187 188 indent_spaces = 0
188 189 # String, indicating the default input encoding. It is computed by default
189 190 # at initialization time via get_input_encoding(), but it can be reset by a
190 191 # client with specific knowledge of the encoding.
191 192 encoding = ''
192 193 # String where the current full source input is stored, properly encoded.
193 194 # Reading this attribute is the normal way of querying the currently pushed
194 195 # source code, that has been properly encoded.
195 196 source = ''
196 197 # Code object corresponding to the current source. It is automatically
197 198 # synced to the source, so it can be queried at any time to obtain the code
198 199 # object; it will be None if the source doesn't compile to valid Python.
199 200 code = None
200 201
201 202 # Private attributes
202 203
203 204 # List with lines of input accumulated so far
204 205 _buffer = None
205 206 # Command compiler
206 207 _compile = None
207 208 # Mark when input has changed indentation all the way back to flush-left
208 209 _full_dedent = False
209 210 # Boolean indicating whether the current block is complete
210 211 _is_complete = None
212 # Boolean indicating whether the current block has an unrecoverable syntax error
213 _is_invalid = False
211 214
212 215 def __init__(self):
213 216 """Create a new InputSplitter instance.
214 217 """
215 218 self._buffer = []
216 219 self._compile = codeop.CommandCompiler()
217 220 self.encoding = get_input_encoding()
218 221
219 222 def reset(self):
220 223 """Reset the input buffer and associated state."""
221 224 self.indent_spaces = 0
222 225 self._buffer[:] = []
223 226 self.source = ''
224 227 self.code = None
225 228 self._is_complete = False
229 self._is_invalid = False
226 230 self._full_dedent = False
227 231
228 232 def source_reset(self):
229 233 """Return the input source and perform a full reset.
230 234 """
231 235 out = self.source
232 236 self.reset()
233 237 return out
234 238
239 def check_complete(self, source):
240 """Return whether a block of code is ready to execute, or should be continued
241
242 This is a non-stateful API, and will reset the state of this InputSplitter.
243
244 Parameters
245 ----------
246 source : string
247 Python input code, which can be multiline.
248
249 Returns
250 -------
251 status : str
252 One of 'complete', 'incomplete', or 'invalid' if source is not a
253 prefix of valid code.
254 indent_spaces : int or None
255 The number of spaces by which to indent the next line of code. If
256 status is not 'incomplete', this is None.
257 """
258 self.reset()
259 try:
260 self.push(source)
261 except SyntaxError:
262 # Transformers in IPythonInputSplitter can raise SyntaxError,
263 # which push() will not catch.
264 return 'invalid', None
265 else:
266 if self._is_invalid:
267 return 'invalid', None
268 elif self.push_accepts_more():
269 return 'incomplete', self.indent_spaces
270 else:
271 return 'complete', None
272 finally:
273 self.reset()
274
235 275 def push(self, lines):
236 276 """Push one or more lines of input.
237 277
238 278 This stores the given lines and returns a status code indicating
239 279 whether the code forms a complete Python block or not.
240 280
241 281 Any exceptions generated in compilation are swallowed, but if an
242 282 exception was produced, the method returns True.
243 283
244 284 Parameters
245 285 ----------
246 286 lines : string
247 287 One or more lines of Python input.
248 288
249 289 Returns
250 290 -------
251 291 is_complete : boolean
252 292 True if the current input source (the result of the current input
253 293 plus prior inputs) forms a complete Python execution block. Note that
254 294 this value is also stored as a private attribute (``_is_complete``), so it
255 295 can be queried at any time.
256 296 """
257 297 self._store(lines)
258 298 source = self.source
259 299
260 300 # Before calling _compile(), reset the code object to None so that if an
261 301 # exception is raised in compilation, we don't mislead by having
262 302 # inconsistent code/source attributes.
263 303 self.code, self._is_complete = None, None
304 self._is_invalid = False
264 305
265 306 # Honor termination lines properly
266 307 if source.endswith('\\\n'):
267 308 return False
268 309
269 310 self._update_indent(lines)
270 311 try:
271 self.code = self._compile(source, symbol="exec")
312 with warnings.catch_warnings():
313 warnings.simplefilter('error', SyntaxWarning)
314 self.code = self._compile(source, symbol="exec")
272 315 # Invalid syntax can produce any of a number of different errors from
273 316 # inside the compiler, so we have to catch them all. Syntax errors
274 317 # immediately produce a 'ready' block, so the invalid Python can be
275 318 # sent to the kernel for evaluation with possible ipython
276 319 # special-syntax conversion.
277 320 except (SyntaxError, OverflowError, ValueError, TypeError,
278 MemoryError):
321 MemoryError, SyntaxWarning):
279 322 self._is_complete = True
323 self._is_invalid = True
280 324 else:
281 325 # Compilation didn't produce any exceptions (though it may not have
282 326 # given a complete code object)
283 327 self._is_complete = self.code is not None
284 328
285 329 return self._is_complete
286 330
287 331 def push_accepts_more(self):
288 332 """Return whether a block of interactive input can accept more input.
289 333
290 334 This method is meant to be used by line-oriented frontends, who need to
291 335 guess whether a block is complete or not based solely on prior and
292 336 current input lines. The InputSplitter considers it has a complete
293 337 interactive block and will not accept more input when either:
294 338
295 339 * A SyntaxError is raised
296 340
297 341 * The code is complete and consists of a single line or a single
298 342 non-compound statement
299 343
300 344 * The code is complete and has a blank line at the end
301 345
302 346 If the current input produces a syntax error, this method immediately
303 347 returns False but does *not* raise the syntax error exception, as
304 348 typically clients will want to send invalid syntax to an execution
305 349 backend which might convert the invalid syntax into valid Python via
306 350 one of the dynamic IPython mechanisms.
307 351 """
308 352
309 353 # With incomplete input, unconditionally accept more
310 354 # A syntax error also sets _is_complete to True - see push()
311 355 if not self._is_complete:
312 356 #print("Not complete") # debug
313 357 return True
314 358
315 359 # The user can make any (complete) input execute by leaving a blank line
316 360 last_line = self.source.splitlines()[-1]
317 361 if (not last_line) or last_line.isspace():
318 362 #print("Blank line") # debug
319 363 return False
320 364
321 365 # If there's just a single line or AST node, and we're flush left, as is
322 366 # the case after a simple statement such as 'a=1', we want to execute it
323 367 # straight away.
324 368 if self.indent_spaces==0:
325 369 if len(self.source.splitlines()) <= 1:
326 370 return False
327 371
328 372 try:
329 373 code_ast = ast.parse(u''.join(self._buffer))
330 374 except Exception:
331 375 #print("Can't parse AST") # debug
332 376 return False
333 377 else:
334 378 if len(code_ast.body) == 1 and \
335 379 not hasattr(code_ast.body[0], 'body'):
336 380 #print("Simple statement") # debug
337 381 return False
338 382
339 383 # General fallback - accept more code
340 384 return True
341 385
342 386 #------------------------------------------------------------------------
343 387 # Private interface
344 388 #------------------------------------------------------------------------
345 389
346 390 def _find_indent(self, line):
347 391 """Compute the new indentation level for a single line.
348 392
349 393 Parameters
350 394 ----------
351 395 line : str
352 396 A single new line of non-whitespace, non-comment Python input.
353 397
354 398 Returns
355 399 -------
356 400 indent_spaces : int
357 401 New value for the indent level (it may be equal to self.indent_spaces
358 402 if indentation doesn't change.
359 403
360 404 full_dedent : boolean
361 405 Whether the new line causes a full flush-left dedent.
362 406 """
363 407 indent_spaces = self.indent_spaces
364 408 full_dedent = self._full_dedent
365 409
366 410 inisp = num_ini_spaces(line)
367 411 if inisp < indent_spaces:
368 412 indent_spaces = inisp
369 413 if indent_spaces <= 0:
370 414 #print 'Full dedent in text',self.source # dbg
371 415 full_dedent = True
372 416
373 417 if line.rstrip()[-1] == ':':
374 418 indent_spaces += 4
375 419 elif dedent_re.match(line):
376 420 indent_spaces -= 4
377 421 if indent_spaces <= 0:
378 422 full_dedent = True
379 423
380 424 # Safety
381 425 if indent_spaces < 0:
382 426 indent_spaces = 0
383 427 #print 'safety' # dbg
384 428
385 429 return indent_spaces, full_dedent
386 430
387 431 def _update_indent(self, lines):
388 432 for line in remove_comments(lines).splitlines():
389 433 if line and not line.isspace():
390 434 self.indent_spaces, self._full_dedent = self._find_indent(line)
391 435
392 436 def _store(self, lines, buffer=None, store='source'):
393 437 """Store one or more lines of input.
394 438
395 439 If input lines are not newline-terminated, a newline is automatically
396 440 appended."""
397 441
398 442 if buffer is None:
399 443 buffer = self._buffer
400 444
401 445 if lines.endswith('\n'):
402 446 buffer.append(lines)
403 447 else:
404 448 buffer.append(lines+'\n')
405 449 setattr(self, store, self._set_source(buffer))
406 450
407 451 def _set_source(self, buffer):
408 452 return u''.join(buffer)
409 453
410 454
411 455 class IPythonInputSplitter(InputSplitter):
412 456 """An input splitter that recognizes all of IPython's special syntax."""
413 457
414 458 # String with raw, untransformed input.
415 459 source_raw = ''
416 460
417 461 # Flag to track when a transformer has stored input that it hasn't given
418 462 # back yet.
419 463 transformer_accumulating = False
420 464
421 465 # Flag to track when assemble_python_lines has stored input that it hasn't
422 466 # given back yet.
423 467 within_python_line = False
424 468
425 469 # Private attributes
426 470
427 471 # List with lines of raw input accumulated so far.
428 472 _buffer_raw = None
429 473
430 474 def __init__(self, line_input_checker=True, physical_line_transforms=None,
431 475 logical_line_transforms=None, python_line_transforms=None):
432 476 super(IPythonInputSplitter, self).__init__()
433 477 self._buffer_raw = []
434 478 self._validate = True
435 479
436 480 if physical_line_transforms is not None:
437 481 self.physical_line_transforms = physical_line_transforms
438 482 else:
439 483 self.physical_line_transforms = [
440 484 leading_indent(),
441 485 classic_prompt(),
442 486 ipy_prompt(),
443 487 strip_encoding_cookie(),
444 488 cellmagic(end_on_blank_line=line_input_checker),
445 489 ]
446 490
447 491 self.assemble_logical_lines = assemble_logical_lines()
448 492 if logical_line_transforms is not None:
449 493 self.logical_line_transforms = logical_line_transforms
450 494 else:
451 495 self.logical_line_transforms = [
452 496 help_end(),
453 497 escaped_commands(),
454 498 assign_from_magic(),
455 499 assign_from_system(),
456 500 ]
457 501
458 502 self.assemble_python_lines = assemble_python_lines()
459 503 if python_line_transforms is not None:
460 504 self.python_line_transforms = python_line_transforms
461 505 else:
462 506 # We don't use any of these at present
463 507 self.python_line_transforms = []
464 508
465 509 @property
466 510 def transforms(self):
467 511 "Quick access to all transformers."
468 512 return self.physical_line_transforms + \
469 513 [self.assemble_logical_lines] + self.logical_line_transforms + \
470 514 [self.assemble_python_lines] + self.python_line_transforms
471 515
472 516 @property
473 517 def transforms_in_use(self):
474 518 """Transformers, excluding logical line transformers if we're in a
475 519 Python line."""
476 520 t = self.physical_line_transforms[:]
477 521 if not self.within_python_line:
478 522 t += [self.assemble_logical_lines] + self.logical_line_transforms
479 523 return t + [self.assemble_python_lines] + self.python_line_transforms
480 524
481 525 def reset(self):
482 526 """Reset the input buffer and associated state."""
483 527 super(IPythonInputSplitter, self).reset()
484 528 self._buffer_raw[:] = []
485 529 self.source_raw = ''
486 530 self.transformer_accumulating = False
487 531 self.within_python_line = False
488 532
489 533 for t in self.transforms:
490 534 try:
491 535 t.reset()
492 536 except SyntaxError:
493 537 # Nothing that calls reset() expects to handle transformer
494 538 # errors
495 539 pass
496 540
497 541 def flush_transformers(self):
498 542 def _flush(transform, outs):
499 543 """yield transformed lines
500 544
501 545 always strings, never None
502 546
503 547 transform: the current transform
504 548 outs: an iterable of previously transformed inputs.
505 549 Each may be multiline, which will be passed
506 550 one line at a time to transform.
507 551 """
508 552 for out in outs:
509 553 for line in out.splitlines():
510 554 # push one line at a time
511 555 tmp = transform.push(line)
512 556 if tmp is not None:
513 557 yield tmp
514 558
515 559 # reset the transform
516 560 tmp = transform.reset()
517 561 if tmp is not None:
518 562 yield tmp
519 563
520 564 out = []
521 565 for t in self.transforms_in_use:
522 566 out = _flush(t, out)
523 567
524 568 out = list(out)
525 569 if out:
526 570 self._store('\n'.join(out))
527 571
528 572 def raw_reset(self):
529 573 """Return raw input only and perform a full reset.
530 574 """
531 575 out = self.source_raw
532 576 self.reset()
533 577 return out
534 578
535 579 def source_reset(self):
536 580 try:
537 581 self.flush_transformers()
538 582 return self.source
539 583 finally:
540 584 self.reset()
541 585
542 586 def push_accepts_more(self):
543 587 if self.transformer_accumulating:
544 588 return True
545 589 else:
546 590 return super(IPythonInputSplitter, self).push_accepts_more()
547 591
548 592 def transform_cell(self, cell):
549 593 """Process and translate a cell of input.
550 594 """
551 595 self.reset()
552 596 try:
553 597 self.push(cell)
554 598 self.flush_transformers()
555 599 return self.source
556 600 finally:
557 601 self.reset()
558 602
559 603 def push(self, lines):
560 604 """Push one or more lines of IPython input.
561 605
562 606 This stores the given lines and returns a status code indicating
563 607 whether the code forms a complete Python block or not, after processing
564 608 all input lines for special IPython syntax.
565 609
566 610 Any exceptions generated in compilation are swallowed, but if an
567 611 exception was produced, the method returns True.
568 612
569 613 Parameters
570 614 ----------
571 615 lines : string
572 616 One or more lines of Python input.
573 617
574 618 Returns
575 619 -------
576 620 is_complete : boolean
577 621 True if the current input source (the result of the current input
578 622 plus prior inputs) forms a complete Python execution block. Note that
579 623 this value is also stored as a private attribute (_is_complete), so it
580 624 can be queried at any time.
581 625 """
582 626
583 627 # We must ensure all input is pure unicode
584 628 lines = cast_unicode(lines, self.encoding)
585 629
586 630 # ''.splitlines() --> [], but we need to push the empty line to transformers
587 631 lines_list = lines.splitlines()
588 632 if not lines_list:
589 633 lines_list = ['']
590 634
591 635 # Store raw source before applying any transformations to it. Note
592 636 # that this must be done *after* the reset() call that would otherwise
593 637 # flush the buffer.
594 638 self._store(lines, self._buffer_raw, 'source_raw')
595 639
596 640 for line in lines_list:
597 641 out = self.push_line(line)
598 642
599 643 return out
600 644
601 645 def push_line(self, line):
602 646 buf = self._buffer
603 647
604 648 def _accumulating(dbg):
605 649 #print(dbg)
606 650 self.transformer_accumulating = True
607 651 return False
608 652
609 653 for transformer in self.physical_line_transforms:
610 654 line = transformer.push(line)
611 655 if line is None:
612 656 return _accumulating(transformer)
613 657
614 658 if not self.within_python_line:
615 659 line = self.assemble_logical_lines.push(line)
616 660 if line is None:
617 661 return _accumulating('acc logical line')
618 662
619 663 for transformer in self.logical_line_transforms:
620 664 line = transformer.push(line)
621 665 if line is None:
622 666 return _accumulating(transformer)
623 667
624 668 line = self.assemble_python_lines.push(line)
625 669 if line is None:
626 670 self.within_python_line = True
627 671 return _accumulating('acc python line')
628 672 else:
629 673 self.within_python_line = False
630 674
631 675 for transformer in self.python_line_transforms:
632 676 line = transformer.push(line)
633 677 if line is None:
634 678 return _accumulating(transformer)
635 679
636 680 #print("transformers clear") #debug
637 681 self.transformer_accumulating = False
638 682 return super(IPythonInputSplitter, self).push(line)
@@ -1,549 +1,549 b''
1 1 """Input transformer classes to support IPython special syntax.
2 2
3 3 This includes the machinery to recognise and transform ``%magic`` commands,
4 4 ``!system`` commands, ``help?`` querying, prompt stripping, and so forth.
5 5 """
6 6 import abc
7 7 import functools
8 8 import re
9 9
10 10 from IPython.core.splitinput import LineInfo
11 11 from IPython.utils import tokenize2
12 12 from IPython.utils.openpy import cookie_comment_re
13 13 from IPython.utils.py3compat import with_metaclass, PY3
14 14 from IPython.utils.tokenize2 import generate_tokens, untokenize, TokenError
15 15
16 16 if PY3:
17 17 from io import StringIO
18 18 else:
19 19 from StringIO import StringIO
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Globals
23 23 #-----------------------------------------------------------------------------
24 24
25 25 # The escape sequences that define the syntax transformations IPython will
26 26 # apply to user input. These can NOT be just changed here: many regular
27 27 # expressions and other parts of the code may use their hardcoded values, and
28 28 # for all intents and purposes they constitute the 'IPython syntax', so they
29 29 # should be considered fixed.
30 30
31 31 ESC_SHELL = '!' # Send line to underlying system shell
32 32 ESC_SH_CAP = '!!' # Send line to system shell and capture output
33 33 ESC_HELP = '?' # Find information about object
34 34 ESC_HELP2 = '??' # Find extra-detailed information about object
35 35 ESC_MAGIC = '%' # Call magic function
36 36 ESC_MAGIC2 = '%%' # Call cell-magic function
37 37 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
38 38 ESC_QUOTE2 = ';' # Quote all args as a single string, call
39 39 ESC_PAREN = '/' # Call first argument with rest of line as arguments
40 40
41 41 ESC_SEQUENCES = [ESC_SHELL, ESC_SH_CAP, ESC_HELP ,\
42 42 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,\
43 43 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN ]
44 44
45 45
46 46 class InputTransformer(with_metaclass(abc.ABCMeta, object)):
47 47 """Abstract base class for line-based input transformers."""
48 48
49 49 @abc.abstractmethod
50 50 def push(self, line):
51 51 """Send a line of input to the transformer, returning the transformed
52 52 input or None if the transformer is waiting for more input.
53 53
54 54 Must be overridden by subclasses.
55 55
56 56 Implementations may raise ``SyntaxError`` if the input is invalid. No
57 57 other exceptions may be raised.
58 58 """
59 59 pass
60 60
61 61 @abc.abstractmethod
62 62 def reset(self):
63 63 """Return, transformed any lines that the transformer has accumulated,
64 64 and reset its internal state.
65 65
66 66 Must be overridden by subclasses.
67 67 """
68 68 pass
69 69
70 70 @classmethod
71 71 def wrap(cls, func):
72 72 """Can be used by subclasses as a decorator, to return a factory that
73 73 will allow instantiation with the decorated object.
74 74 """
75 75 @functools.wraps(func)
76 76 def transformer_factory(**kwargs):
77 77 return cls(func, **kwargs)
78 78
79 79 return transformer_factory
80 80
81 81 class StatelessInputTransformer(InputTransformer):
82 82 """Wrapper for a stateless input transformer implemented as a function."""
83 83 def __init__(self, func):
84 84 self.func = func
85 85
86 86 def __repr__(self):
87 87 return "StatelessInputTransformer(func={0!r})".format(self.func)
88 88
89 89 def push(self, line):
90 90 """Send a line of input to the transformer, returning the
91 91 transformed input."""
92 92 return self.func(line)
93 93
94 94 def reset(self):
95 95 """No-op - exists for compatibility."""
96 96 pass
97 97
98 98 class CoroutineInputTransformer(InputTransformer):
99 99 """Wrapper for an input transformer implemented as a coroutine."""
100 100 def __init__(self, coro, **kwargs):
101 101 # Prime it
102 102 self.coro = coro(**kwargs)
103 103 next(self.coro)
104 104
105 105 def __repr__(self):
106 106 return "CoroutineInputTransformer(coro={0!r})".format(self.coro)
107 107
108 108 def push(self, line):
109 109 """Send a line of input to the transformer, returning the
110 110 transformed input or None if the transformer is waiting for more
111 111 input.
112 112 """
113 113 return self.coro.send(line)
114 114
115 115 def reset(self):
116 116 """Return, transformed any lines that the transformer has
117 117 accumulated, and reset its internal state.
118 118 """
119 119 return self.coro.send(None)
120 120
121 121 class TokenInputTransformer(InputTransformer):
122 122 """Wrapper for a token-based input transformer.
123 123
124 124 func should accept a list of tokens (5-tuples, see tokenize docs), and
125 125 return an iterable which can be passed to tokenize.untokenize().
126 126 """
127 127 def __init__(self, func):
128 128 self.func = func
129 129 self.current_line = ""
130 130 self.line_used = False
131 131 self.reset_tokenizer()
132 132
133 133 def reset_tokenizer(self):
134 134 self.tokenizer = generate_tokens(self.get_line)
135 135
136 136 def get_line(self):
137 137 if self.line_used:
138 138 raise TokenError
139 139 self.line_used = True
140 140 return self.current_line
141 141
142 142 def push(self, line):
143 143 self.current_line += line + "\n"
144 144 if self.current_line.isspace():
145 145 return self.reset()
146 146
147 147 self.line_used = False
148 148 tokens = []
149 149 stop_at_NL = False
150 150 try:
151 151 for intok in self.tokenizer:
152 152 tokens.append(intok)
153 153 t = intok[0]
154 154 if t == tokenize2.NEWLINE or (stop_at_NL and t == tokenize2.NL):
155 155 # Stop before we try to pull a line we don't have yet
156 156 break
157 157 elif t == tokenize2.ERRORTOKEN:
158 158 stop_at_NL = True
159 159 except TokenError:
160 160 # Multi-line statement - stop and try again with the next line
161 161 self.reset_tokenizer()
162 162 return None
163 163
164 164 return self.output(tokens)
165 165
166 166 def output(self, tokens):
167 167 self.current_line = ""
168 168 self.reset_tokenizer()
169 169 return untokenize(self.func(tokens)).rstrip('\n')
170 170
171 171 def reset(self):
172 172 l = self.current_line
173 173 self.current_line = ""
174 174 self.reset_tokenizer()
175 175 if l:
176 176 return l.rstrip('\n')
177 177
178 178 class assemble_python_lines(TokenInputTransformer):
179 179 def __init__(self):
180 180 super(assemble_python_lines, self).__init__(None)
181 181
182 182 def output(self, tokens):
183 183 return self.reset()
184 184
185 185 @CoroutineInputTransformer.wrap
186 186 def assemble_logical_lines():
187 187 """Join lines following explicit line continuations (\)"""
188 188 line = ''
189 189 while True:
190 190 line = (yield line)
191 191 if not line or line.isspace():
192 192 continue
193 193
194 194 parts = []
195 195 while line is not None:
196 196 if line.endswith('\\') and (not has_comment(line)):
197 197 parts.append(line[:-1])
198 198 line = (yield None) # Get another line
199 199 else:
200 200 parts.append(line)
201 201 break
202 202
203 203 # Output
204 204 line = ''.join(parts)
205 205
206 206 # Utilities
207 207 def _make_help_call(target, esc, lspace, next_input=None):
208 208 """Prepares a pinfo(2)/psearch call from a target name and the escape
209 209 (i.e. ? or ??)"""
210 210 method = 'pinfo2' if esc == '??' \
211 211 else 'psearch' if '*' in target \
212 212 else 'pinfo'
213 213 arg = " ".join([method, target])
214 214 if next_input is None:
215 215 return '%sget_ipython().magic(%r)' % (lspace, arg)
216 216 else:
217 217 return '%sget_ipython().set_next_input(%r);get_ipython().magic(%r)' % \
218 218 (lspace, next_input, arg)
219 219
220 220 # These define the transformations for the different escape characters.
221 221 def _tr_system(line_info):
222 222 "Translate lines escaped with: !"
223 223 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
224 224 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
225 225
226 226 def _tr_system2(line_info):
227 227 "Translate lines escaped with: !!"
228 228 cmd = line_info.line.lstrip()[2:]
229 229 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
230 230
231 231 def _tr_help(line_info):
232 232 "Translate lines escaped with: ?/??"
233 233 # A naked help line should just fire the intro help screen
234 234 if not line_info.line[1:]:
235 235 return 'get_ipython().show_usage()'
236 236
237 237 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
238 238
239 239 def _tr_magic(line_info):
240 240 "Translate lines escaped with: %"
241 241 tpl = '%sget_ipython().magic(%r)'
242 242 if line_info.line.startswith(ESC_MAGIC2):
243 243 return line_info.line
244 244 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
245 245 return tpl % (line_info.pre, cmd)
246 246
247 247 def _tr_quote(line_info):
248 248 "Translate lines escaped with: ,"
249 249 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
250 250 '", "'.join(line_info.the_rest.split()) )
251 251
252 252 def _tr_quote2(line_info):
253 253 "Translate lines escaped with: ;"
254 254 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
255 255 line_info.the_rest)
256 256
257 257 def _tr_paren(line_info):
258 258 "Translate lines escaped with: /"
259 259 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
260 260 ", ".join(line_info.the_rest.split()))
261 261
262 262 tr = { ESC_SHELL : _tr_system,
263 263 ESC_SH_CAP : _tr_system2,
264 264 ESC_HELP : _tr_help,
265 265 ESC_HELP2 : _tr_help,
266 266 ESC_MAGIC : _tr_magic,
267 267 ESC_QUOTE : _tr_quote,
268 268 ESC_QUOTE2 : _tr_quote2,
269 269 ESC_PAREN : _tr_paren }
270 270
271 271 @StatelessInputTransformer.wrap
272 272 def escaped_commands(line):
273 273 """Transform escaped commands - %magic, !system, ?help + various autocalls.
274 274 """
275 275 if not line or line.isspace():
276 276 return line
277 277 lineinf = LineInfo(line)
278 278 if lineinf.esc not in tr:
279 279 return line
280 280
281 281 return tr[lineinf.esc](lineinf)
282 282
283 283 _initial_space_re = re.compile(r'\s*')
284 284
285 285 _help_end_re = re.compile(r"""(%{0,2}
286 286 [a-zA-Z_*][\w*]* # Variable name
287 287 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
288 288 )
289 289 (\?\??)$ # ? or ??
290 290 """,
291 291 re.VERBOSE)
292 292
293 293 # Extra pseudotokens for multiline strings and data structures
294 294 _MULTILINE_STRING = object()
295 295 _MULTILINE_STRUCTURE = object()
296 296
297 297 def _line_tokens(line):
298 298 """Helper for has_comment and ends_in_comment_or_string."""
299 299 readline = StringIO(line).readline
300 300 toktypes = set()
301 301 try:
302 302 for t in generate_tokens(readline):
303 303 toktypes.add(t[0])
304 304 except TokenError as e:
305 305 # There are only two cases where a TokenError is raised.
306 306 if 'multi-line string' in e.args[0]:
307 307 toktypes.add(_MULTILINE_STRING)
308 308 else:
309 309 toktypes.add(_MULTILINE_STRUCTURE)
310 310 return toktypes
311 311
312 312 def has_comment(src):
313 313 """Indicate whether an input line has (i.e. ends in, or is) a comment.
314 314
315 315 This uses tokenize, so it can distinguish comments from # inside strings.
316 316
317 317 Parameters
318 318 ----------
319 319 src : string
320 320 A single line input string.
321 321
322 322 Returns
323 323 -------
324 324 comment : bool
325 325 True if source has a comment.
326 326 """
327 327 return (tokenize2.COMMENT in _line_tokens(src))
328 328
329 329 def ends_in_comment_or_string(src):
330 330 """Indicates whether or not an input line ends in a comment or within
331 331 a multiline string.
332 332
333 333 Parameters
334 334 ----------
335 335 src : string
336 336 A single line input string.
337 337
338 338 Returns
339 339 -------
340 340 comment : bool
341 341 True if source ends in a comment or multiline string.
342 342 """
343 343 toktypes = _line_tokens(src)
344 344 return (tokenize2.COMMENT in toktypes) or (_MULTILINE_STRING in toktypes)
345 345
346 346
347 347 @StatelessInputTransformer.wrap
348 348 def help_end(line):
349 349 """Translate lines with ?/?? at the end"""
350 350 m = _help_end_re.search(line)
351 351 if m is None or ends_in_comment_or_string(line):
352 352 return line
353 353 target = m.group(1)
354 354 esc = m.group(3)
355 355 lspace = _initial_space_re.match(line).group(0)
356 356
357 357 # If we're mid-command, put it back on the next prompt for the user.
358 358 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
359 359
360 360 return _make_help_call(target, esc, lspace, next_input)
361 361
362 362
363 363 @CoroutineInputTransformer.wrap
364 364 def cellmagic(end_on_blank_line=False):
365 365 """Captures & transforms cell magics.
366 366
367 367 After a cell magic is started, this stores up any lines it gets until it is
368 368 reset (sent None).
369 369 """
370 370 tpl = 'get_ipython().run_cell_magic(%r, %r, %r)'
371 371 cellmagic_help_re = re.compile('%%\w+\?')
372 372 line = ''
373 373 while True:
374 374 line = (yield line)
375 375 # consume leading empty lines
376 376 while not line:
377 377 line = (yield line)
378 378
379 379 if not line.startswith(ESC_MAGIC2):
380 380 # This isn't a cell magic, idle waiting for reset then start over
381 381 while line is not None:
382 382 line = (yield line)
383 383 continue
384 384
385 385 if cellmagic_help_re.match(line):
386 386 # This case will be handled by help_end
387 387 continue
388 388
389 389 first = line
390 390 body = []
391 391 line = (yield None)
392 392 while (line is not None) and \
393 393 ((line.strip() != '') or not end_on_blank_line):
394 394 body.append(line)
395 395 line = (yield None)
396 396
397 397 # Output
398 398 magic_name, _, first = first.partition(' ')
399 399 magic_name = magic_name.lstrip(ESC_MAGIC2)
400 400 line = tpl % (magic_name, first, u'\n'.join(body))
401 401
402 402
403 403 def _strip_prompts(prompt_re, initial_re=None):
404 404 """Remove matching input prompts from a block of input.
405 405
406 406 Parameters
407 407 ----------
408 408 prompt_re : regular expression
409 409 A regular expression matching any input prompt (including continuation)
410 410 initial_re : regular expression, optional
411 411 A regular expression matching only the initial prompt, but not continuation.
412 412 If no initial expression is given, prompt_re will be used everywhere.
413 413 Used mainly for plain Python prompts, where the continuation prompt
414 414 ``...`` is a valid Python expression in Python 3, so shouldn't be stripped.
415 415
416 416 If initial_re and prompt_re differ,
417 417 only initial_re will be tested against the first line.
418 418 If any prompt is found on the first two lines,
419 419 prompts will be stripped from the rest of the block.
420 420 """
421 421 if initial_re is None:
422 422 initial_re = prompt_re
423 423 line = ''
424 424 while True:
425 425 line = (yield line)
426 426
427 427 # First line of cell
428 428 if line is None:
429 429 continue
430 430 out, n1 = initial_re.subn('', line, count=1)
431 431 line = (yield out)
432 432
433 433 if line is None:
434 434 continue
435 435 # check for any prompt on the second line of the cell,
436 436 # because people often copy from just after the first prompt,
437 437 # so we might not see it in the first line.
438 438 out, n2 = prompt_re.subn('', line, count=1)
439 439 line = (yield out)
440 440
441 441 if n1 or n2:
442 442 # Found a prompt in the first two lines - check for it in
443 443 # the rest of the cell as well.
444 444 while line is not None:
445 445 line = (yield prompt_re.sub('', line, count=1))
446 446
447 447 else:
448 448 # Prompts not in input - wait for reset
449 449 while line is not None:
450 450 line = (yield line)
451 451
452 452 @CoroutineInputTransformer.wrap
453 453 def classic_prompt():
454 454 """Strip the >>>/... prompts of the Python interactive shell."""
455 455 # FIXME: non-capturing version (?:...) usable?
456 456 prompt_re = re.compile(r'^(>>>|\.\.\.)( |$)')
457 457 initial_re = re.compile(r'^>>>( |$)')
458 458 return _strip_prompts(prompt_re, initial_re)
459 459
460 460 @CoroutineInputTransformer.wrap
461 461 def ipy_prompt():
462 462 """Strip IPython's In [1]:/...: prompts."""
463 463 # FIXME: non-capturing version (?:...) usable?
464 prompt_re = re.compile(r'^(In \[\d+\]: |\ {3,}\.{3,}: )')
464 prompt_re = re.compile(r'^(In \[\d+\]: |\s*\.{3,}: ?)')
465 465 return _strip_prompts(prompt_re)
466 466
467 467
468 468 @CoroutineInputTransformer.wrap
469 469 def leading_indent():
470 470 """Remove leading indentation.
471 471
472 472 If the first line starts with a spaces or tabs, the same whitespace will be
473 473 removed from each following line until it is reset.
474 474 """
475 475 space_re = re.compile(r'^[ \t]+')
476 476 line = ''
477 477 while True:
478 478 line = (yield line)
479 479
480 480 if line is None:
481 481 continue
482 482
483 483 m = space_re.match(line)
484 484 if m:
485 485 space = m.group(0)
486 486 while line is not None:
487 487 if line.startswith(space):
488 488 line = line[len(space):]
489 489 line = (yield line)
490 490 else:
491 491 # No leading spaces - wait for reset
492 492 while line is not None:
493 493 line = (yield line)
494 494
495 495
496 496 @CoroutineInputTransformer.wrap
497 497 def strip_encoding_cookie():
498 498 """Remove encoding comment if found in first two lines
499 499
500 500 If the first or second line has the `# coding: utf-8` comment,
501 501 it will be removed.
502 502 """
503 503 line = ''
504 504 while True:
505 505 line = (yield line)
506 506 # check comment on first two lines
507 507 for i in range(2):
508 508 if line is None:
509 509 break
510 510 if cookie_comment_re.match(line):
511 511 line = (yield "")
512 512 else:
513 513 line = (yield line)
514 514
515 515 # no-op on the rest of the cell
516 516 while line is not None:
517 517 line = (yield line)
518 518
519 519 _assign_pat = \
520 520 r'''(?P<lhs>(\s*)
521 521 ([\w\.]+) # Initial identifier
522 522 (\s*,\s*
523 523 \*?[\w\.]+)* # Further identifiers for unpacking
524 524 \s*?,? # Trailing comma
525 525 )
526 526 \s*=\s*
527 527 '''
528 528
529 529 assign_system_re = re.compile(r'{}!\s*(?P<cmd>.*)'.format(_assign_pat), re.VERBOSE)
530 530 assign_system_template = '%s = get_ipython().getoutput(%r)'
531 531 @StatelessInputTransformer.wrap
532 532 def assign_from_system(line):
533 533 """Transform assignment from system commands (e.g. files = !ls)"""
534 534 m = assign_system_re.match(line)
535 535 if m is None:
536 536 return line
537 537
538 538 return assign_system_template % m.group('lhs', 'cmd')
539 539
540 540 assign_magic_re = re.compile(r'{}%\s*(?P<cmd>.*)'.format(_assign_pat), re.VERBOSE)
541 541 assign_magic_template = '%s = get_ipython().magic(%r)'
542 542 @StatelessInputTransformer.wrap
543 543 def assign_from_magic(line):
544 544 """Transform assignment from magic commands (e.g. a = %who_ls)"""
545 545 m = assign_magic_re.match(line)
546 546 if m is None:
547 547 return line
548 548
549 549 return assign_magic_template % m.group('lhs', 'cmd')
@@ -1,3288 +1,3336 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Main IPython class."""
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 from __future__ import absolute_import, print_function
14 14
15 15 import __future__
16 16 import abc
17 17 import ast
18 18 import atexit
19 19 import functools
20 20 import os
21 21 import re
22 22 import runpy
23 23 import sys
24 24 import tempfile
25 import traceback
25 26 import types
26 27 import subprocess
27 28 from io import open as io_open
28 29
29 30 from IPython.config.configurable import SingletonConfigurable
30 31 from IPython.core import debugger, oinspect
31 32 from IPython.core import magic
32 33 from IPython.core import page
33 34 from IPython.core import prefilter
34 35 from IPython.core import shadowns
35 36 from IPython.core import ultratb
36 37 from IPython.core.alias import AliasManager, AliasError
37 38 from IPython.core.autocall import ExitAutocall
38 39 from IPython.core.builtin_trap import BuiltinTrap
39 40 from IPython.core.events import EventManager, available_events
40 41 from IPython.core.compilerop import CachingCompiler, check_linecache_ipython
41 42 from IPython.core.display_trap import DisplayTrap
42 43 from IPython.core.displayhook import DisplayHook
43 44 from IPython.core.displaypub import DisplayPublisher
44 45 from IPython.core.error import InputRejected, UsageError
45 46 from IPython.core.extensions import ExtensionManager
46 47 from IPython.core.formatters import DisplayFormatter
47 48 from IPython.core.history import HistoryManager
48 49 from IPython.core.inputsplitter import IPythonInputSplitter, ESC_MAGIC, ESC_MAGIC2
49 50 from IPython.core.logger import Logger
50 51 from IPython.core.macro import Macro
51 52 from IPython.core.payload import PayloadManager
52 53 from IPython.core.prefilter import PrefilterManager
53 54 from IPython.core.profiledir import ProfileDir
54 55 from IPython.core.prompts import PromptManager
55 56 from IPython.core.usage import default_banner
56 57 from IPython.lib.latextools import LaTeXTool
57 58 from IPython.testing.skipdoctest import skip_doctest
58 59 from IPython.utils import PyColorize
59 60 from IPython.utils import io
60 61 from IPython.utils import py3compat
61 62 from IPython.utils import openpy
62 63 from IPython.utils.decorators import undoc
63 64 from IPython.utils.io import ask_yes_no
64 65 from IPython.utils.ipstruct import Struct
65 66 from IPython.utils.path import get_home_dir, get_ipython_dir, get_py_filename, unquote_filename, ensure_dir_exists
66 67 from IPython.utils.pickleshare import PickleShareDB
67 68 from IPython.utils.process import system, getoutput
68 69 from IPython.utils.py3compat import (builtin_mod, unicode_type, string_types,
69 70 with_metaclass, iteritems)
70 71 from IPython.utils.strdispatch import StrDispatch
71 72 from IPython.utils.syspathcontext import prepended_to_syspath
72 73 from IPython.utils.text import (format_screen, LSString, SList,
73 74 DollarFormatter)
74 75 from IPython.utils.traitlets import (Integer, CBool, CaselessStrEnum, Enum,
75 76 List, Unicode, Instance, Type)
76 77 from IPython.utils.warn import warn, error
77 78 import IPython.core.hooks
78 79
79 80 #-----------------------------------------------------------------------------
80 81 # Globals
81 82 #-----------------------------------------------------------------------------
82 83
83 84 # compiled regexps for autoindent management
84 85 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
85 86
86 87 #-----------------------------------------------------------------------------
87 88 # Utilities
88 89 #-----------------------------------------------------------------------------
89 90
90 91 @undoc
91 92 def softspace(file, newvalue):
92 93 """Copied from code.py, to remove the dependency"""
93 94
94 95 oldvalue = 0
95 96 try:
96 97 oldvalue = file.softspace
97 98 except AttributeError:
98 99 pass
99 100 try:
100 101 file.softspace = newvalue
101 102 except (AttributeError, TypeError):
102 103 # "attribute-less object" or "read-only attributes"
103 104 pass
104 105 return oldvalue
105 106
106 107 @undoc
107 108 def no_op(*a, **kw): pass
108 109
109 110 @undoc
110 111 class NoOpContext(object):
111 112 def __enter__(self): pass
112 113 def __exit__(self, type, value, traceback): pass
113 114 no_op_context = NoOpContext()
114 115
115 116 class SpaceInInput(Exception): pass
116 117
117 118 @undoc
118 119 class Bunch: pass
119 120
120 121
121 122 def get_default_colors():
122 123 if sys.platform=='darwin':
123 124 return "LightBG"
124 125 elif os.name=='nt':
125 126 return 'Linux'
126 127 else:
127 128 return 'Linux'
128 129
129 130
130 131 class SeparateUnicode(Unicode):
131 132 r"""A Unicode subclass to validate separate_in, separate_out, etc.
132 133
133 134 This is a Unicode based trait that converts '0'->'' and ``'\\n'->'\n'``.
134 135 """
135 136
136 137 def validate(self, obj, value):
137 138 if value == '0': value = ''
138 139 value = value.replace('\\n','\n')
139 140 return super(SeparateUnicode, self).validate(obj, value)
140 141
141 142
142 143 class ReadlineNoRecord(object):
143 144 """Context manager to execute some code, then reload readline history
144 145 so that interactive input to the code doesn't appear when pressing up."""
145 146 def __init__(self, shell):
146 147 self.shell = shell
147 148 self._nested_level = 0
148 149
149 150 def __enter__(self):
150 151 if self._nested_level == 0:
151 152 try:
152 153 self.orig_length = self.current_length()
153 154 self.readline_tail = self.get_readline_tail()
154 155 except (AttributeError, IndexError): # Can fail with pyreadline
155 156 self.orig_length, self.readline_tail = 999999, []
156 157 self._nested_level += 1
157 158
158 159 def __exit__(self, type, value, traceback):
159 160 self._nested_level -= 1
160 161 if self._nested_level == 0:
161 162 # Try clipping the end if it's got longer
162 163 try:
163 164 e = self.current_length() - self.orig_length
164 165 if e > 0:
165 166 for _ in range(e):
166 167 self.shell.readline.remove_history_item(self.orig_length)
167 168
168 169 # If it still doesn't match, just reload readline history.
169 170 if self.current_length() != self.orig_length \
170 171 or self.get_readline_tail() != self.readline_tail:
171 172 self.shell.refill_readline_hist()
172 173 except (AttributeError, IndexError):
173 174 pass
174 175 # Returning False will cause exceptions to propagate
175 176 return False
176 177
177 178 def current_length(self):
178 179 return self.shell.readline.get_current_history_length()
179 180
180 181 def get_readline_tail(self, n=10):
181 182 """Get the last n items in readline history."""
182 183 end = self.shell.readline.get_current_history_length() + 1
183 184 start = max(end-n, 1)
184 185 ghi = self.shell.readline.get_history_item
185 186 return [ghi(x) for x in range(start, end)]
186 187
187 188
188 189 @undoc
189 190 class DummyMod(object):
190 191 """A dummy module used for IPython's interactive module when
191 192 a namespace must be assigned to the module's __dict__."""
192 193 pass
193 194
194 195 #-----------------------------------------------------------------------------
195 196 # Main IPython class
196 197 #-----------------------------------------------------------------------------
197 198
198 199 class InteractiveShell(SingletonConfigurable):
199 200 """An enhanced, interactive shell for Python."""
200 201
201 202 _instance = None
202 203
203 204 ast_transformers = List([], config=True, help=
204 205 """
205 206 A list of ast.NodeTransformer subclass instances, which will be applied
206 207 to user input before code is run.
207 208 """
208 209 )
209 210
210 211 autocall = Enum((0,1,2), default_value=0, config=True, help=
211 212 """
212 213 Make IPython automatically call any callable object even if you didn't
213 214 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
214 215 automatically. The value can be '0' to disable the feature, '1' for
215 216 'smart' autocall, where it is not applied if there are no more
216 217 arguments on the line, and '2' for 'full' autocall, where all callable
217 218 objects are automatically called (even if no arguments are present).
218 219 """
219 220 )
220 221 # TODO: remove all autoindent logic and put into frontends.
221 222 # We can't do this yet because even runlines uses the autoindent.
222 223 autoindent = CBool(True, config=True, help=
223 224 """
224 225 Autoindent IPython code entered interactively.
225 226 """
226 227 )
227 228 automagic = CBool(True, config=True, help=
228 229 """
229 230 Enable magic commands to be called without the leading %.
230 231 """
231 232 )
232 233
233 234 banner = Unicode('')
234 235
235 236 banner1 = Unicode(default_banner, config=True,
236 237 help="""The part of the banner to be printed before the profile"""
237 238 )
238 239 banner2 = Unicode('', config=True,
239 240 help="""The part of the banner to be printed after the profile"""
240 241 )
241 242
242 243 cache_size = Integer(1000, config=True, help=
243 244 """
244 245 Set the size of the output cache. The default is 1000, you can
245 246 change it permanently in your config file. Setting it to 0 completely
246 247 disables the caching system, and the minimum value accepted is 20 (if
247 248 you provide a value less than 20, it is reset to 0 and a warning is
248 249 issued). This limit is defined because otherwise you'll spend more
249 250 time re-flushing a too small cache than working
250 251 """
251 252 )
252 253 color_info = CBool(True, config=True, help=
253 254 """
254 255 Use colors for displaying information about objects. Because this
255 256 information is passed through a pager (like 'less'), and some pagers
256 257 get confused with color codes, this capability can be turned off.
257 258 """
258 259 )
259 260 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
260 261 default_value=get_default_colors(), config=True,
261 262 help="Set the color scheme (NoColor, Linux, or LightBG)."
262 263 )
263 264 colors_force = CBool(False, help=
264 265 """
265 266 Force use of ANSI color codes, regardless of OS and readline
266 267 availability.
267 268 """
268 269 # FIXME: This is essentially a hack to allow ZMQShell to show colors
269 270 # without readline on Win32. When the ZMQ formatting system is
270 271 # refactored, this should be removed.
271 272 )
272 273 debug = CBool(False, config=True)
273 274 deep_reload = CBool(False, config=True, help=
274 275 """
275 276 Enable deep (recursive) reloading by default. IPython can use the
276 277 deep_reload module which reloads changes in modules recursively (it
277 278 replaces the reload() function, so you don't need to change anything to
278 279 use it). deep_reload() forces a full reload of modules whose code may
279 280 have changed, which the default reload() function does not. When
280 281 deep_reload is off, IPython will use the normal reload(), but
281 282 deep_reload will still be available as dreload().
282 283 """
283 284 )
284 285 disable_failing_post_execute = CBool(False, config=True,
285 286 help="Don't call post-execute functions that have failed in the past."
286 287 )
287 288 display_formatter = Instance(DisplayFormatter)
288 289 displayhook_class = Type(DisplayHook)
289 290 display_pub_class = Type(DisplayPublisher)
290 291 data_pub_class = None
291 292
292 293 exit_now = CBool(False)
293 294 exiter = Instance(ExitAutocall)
294 295 def _exiter_default(self):
295 296 return ExitAutocall(self)
296 297 # Monotonically increasing execution counter
297 298 execution_count = Integer(1)
298 299 filename = Unicode("<ipython console>")
299 300 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
300 301
301 302 # Input splitter, to transform input line by line and detect when a block
302 303 # is ready to be executed.
303 304 input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
304 305 (), {'line_input_checker': True})
305 306
306 307 # This InputSplitter instance is used to transform completed cells before
307 308 # running them. It allows cell magics to contain blank lines.
308 309 input_transformer_manager = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
309 310 (), {'line_input_checker': False})
310 311
311 312 logstart = CBool(False, config=True, help=
312 313 """
313 314 Start logging to the default log file.
314 315 """
315 316 )
316 317 logfile = Unicode('', config=True, help=
317 318 """
318 319 The name of the logfile to use.
319 320 """
320 321 )
321 322 logappend = Unicode('', config=True, help=
322 323 """
323 324 Start logging to the given file in append mode.
324 325 """
325 326 )
326 327 object_info_string_level = Enum((0,1,2), default_value=0,
327 328 config=True)
328 329 pdb = CBool(False, config=True, help=
329 330 """
330 331 Automatically call the pdb debugger after every exception.
331 332 """
332 333 )
333 334 multiline_history = CBool(sys.platform != 'win32', config=True,
334 335 help="Save multi-line entries as one entry in readline history"
335 336 )
336 337
337 338 # deprecated prompt traits:
338 339
339 340 prompt_in1 = Unicode('In [\\#]: ', config=True,
340 341 help="Deprecated, use PromptManager.in_template")
341 342 prompt_in2 = Unicode(' .\\D.: ', config=True,
342 343 help="Deprecated, use PromptManager.in2_template")
343 344 prompt_out = Unicode('Out[\\#]: ', config=True,
344 345 help="Deprecated, use PromptManager.out_template")
345 346 prompts_pad_left = CBool(True, config=True,
346 347 help="Deprecated, use PromptManager.justify")
347 348
348 349 def _prompt_trait_changed(self, name, old, new):
349 350 table = {
350 351 'prompt_in1' : 'in_template',
351 352 'prompt_in2' : 'in2_template',
352 353 'prompt_out' : 'out_template',
353 354 'prompts_pad_left' : 'justify',
354 355 }
355 356 warn("InteractiveShell.{name} is deprecated, use PromptManager.{newname}".format(
356 357 name=name, newname=table[name])
357 358 )
358 359 # protect against weird cases where self.config may not exist:
359 360 if self.config is not None:
360 361 # propagate to corresponding PromptManager trait
361 362 setattr(self.config.PromptManager, table[name], new)
362 363
363 364 _prompt_in1_changed = _prompt_trait_changed
364 365 _prompt_in2_changed = _prompt_trait_changed
365 366 _prompt_out_changed = _prompt_trait_changed
366 367 _prompt_pad_left_changed = _prompt_trait_changed
367 368
368 369 show_rewritten_input = CBool(True, config=True,
369 370 help="Show rewritten input, e.g. for autocall."
370 371 )
371 372
372 373 quiet = CBool(False, config=True)
373 374
374 375 history_length = Integer(10000, config=True)
375 376
376 377 # The readline stuff will eventually be moved to the terminal subclass
377 378 # but for now, we can't do that as readline is welded in everywhere.
378 379 readline_use = CBool(True, config=True)
379 380 readline_remove_delims = Unicode('-/~', config=True)
380 381 readline_delims = Unicode() # set by init_readline()
381 382 # don't use \M- bindings by default, because they
382 383 # conflict with 8-bit encodings. See gh-58,gh-88
383 384 readline_parse_and_bind = List([
384 385 'tab: complete',
385 386 '"\C-l": clear-screen',
386 387 'set show-all-if-ambiguous on',
387 388 '"\C-o": tab-insert',
388 389 '"\C-r": reverse-search-history',
389 390 '"\C-s": forward-search-history',
390 391 '"\C-p": history-search-backward',
391 392 '"\C-n": history-search-forward',
392 393 '"\e[A": history-search-backward',
393 394 '"\e[B": history-search-forward',
394 395 '"\C-k": kill-line',
395 396 '"\C-u": unix-line-discard',
396 397 ], config=True)
397 398
398 399 _custom_readline_config = False
399 400
400 401 def _readline_parse_and_bind_changed(self, name, old, new):
401 402 # notice that readline config is customized
402 403 # indicates that it should have higher priority than inputrc
403 404 self._custom_readline_config = True
404 405
405 406 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none'],
406 407 default_value='last_expr', config=True,
407 408 help="""
408 409 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
409 410 run interactively (displaying output from expressions).""")
410 411
411 412 # TODO: this part of prompt management should be moved to the frontends.
412 413 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
413 414 separate_in = SeparateUnicode('\n', config=True)
414 415 separate_out = SeparateUnicode('', config=True)
415 416 separate_out2 = SeparateUnicode('', config=True)
416 417 wildcards_case_sensitive = CBool(True, config=True)
417 418 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
418 419 default_value='Context', config=True)
419 420
420 421 # Subcomponents of InteractiveShell
421 422 alias_manager = Instance('IPython.core.alias.AliasManager')
422 423 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
423 424 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap')
424 425 display_trap = Instance('IPython.core.display_trap.DisplayTrap')
425 426 extension_manager = Instance('IPython.core.extensions.ExtensionManager')
426 427 payload_manager = Instance('IPython.core.payload.PayloadManager')
427 history_manager = Instance('IPython.core.history.HistoryManager')
428 history_manager = Instance('IPython.core.history.HistoryAccessorBase')
428 429 magics_manager = Instance('IPython.core.magic.MagicsManager')
429 430
430 431 profile_dir = Instance('IPython.core.application.ProfileDir')
431 432 @property
432 433 def profile(self):
433 434 if self.profile_dir is not None:
434 435 name = os.path.basename(self.profile_dir.location)
435 436 return name.replace('profile_','')
436 437
437 438
438 439 # Private interface
439 440 _post_execute = Instance(dict)
440 441
441 442 # Tracks any GUI loop loaded for pylab
442 443 pylab_gui_select = None
443 444
444 445 def __init__(self, ipython_dir=None, profile_dir=None,
445 446 user_module=None, user_ns=None,
446 447 custom_exceptions=((), None), **kwargs):
447 448
448 449 # This is where traits with a config_key argument are updated
449 450 # from the values on config.
450 451 super(InteractiveShell, self).__init__(**kwargs)
451 452 self.configurables = [self]
452 453
453 454 # These are relatively independent and stateless
454 455 self.init_ipython_dir(ipython_dir)
455 456 self.init_profile_dir(profile_dir)
456 457 self.init_instance_attrs()
457 458 self.init_environment()
458 459
459 460 # Check if we're in a virtualenv, and set up sys.path.
460 461 self.init_virtualenv()
461 462
462 463 # Create namespaces (user_ns, user_global_ns, etc.)
463 464 self.init_create_namespaces(user_module, user_ns)
464 465 # This has to be done after init_create_namespaces because it uses
465 466 # something in self.user_ns, but before init_sys_modules, which
466 467 # is the first thing to modify sys.
467 468 # TODO: When we override sys.stdout and sys.stderr before this class
468 469 # is created, we are saving the overridden ones here. Not sure if this
469 470 # is what we want to do.
470 471 self.save_sys_module_state()
471 472 self.init_sys_modules()
472 473
473 474 # While we're trying to have each part of the code directly access what
474 475 # it needs without keeping redundant references to objects, we have too
475 476 # much legacy code that expects ip.db to exist.
476 477 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
477 478
478 479 self.init_history()
479 480 self.init_encoding()
480 481 self.init_prefilter()
481 482
482 483 self.init_syntax_highlighting()
483 484 self.init_hooks()
484 485 self.init_events()
485 486 self.init_pushd_popd_magic()
486 487 # self.init_traceback_handlers use to be here, but we moved it below
487 488 # because it and init_io have to come after init_readline.
488 489 self.init_user_ns()
489 490 self.init_logger()
490 491 self.init_builtins()
491 492
492 493 # The following was in post_config_initialization
493 494 self.init_inspector()
494 495 # init_readline() must come before init_io(), because init_io uses
495 496 # readline related things.
496 497 self.init_readline()
497 498 # We save this here in case user code replaces raw_input, but it needs
498 499 # to be after init_readline(), because PyPy's readline works by replacing
499 500 # raw_input.
500 501 if py3compat.PY3:
501 502 self.raw_input_original = input
502 503 else:
503 504 self.raw_input_original = raw_input
504 505 # init_completer must come after init_readline, because it needs to
505 506 # know whether readline is present or not system-wide to configure the
506 507 # completers, since the completion machinery can now operate
507 508 # independently of readline (e.g. over the network)
508 509 self.init_completer()
509 510 # TODO: init_io() needs to happen before init_traceback handlers
510 511 # because the traceback handlers hardcode the stdout/stderr streams.
511 512 # This logic in in debugger.Pdb and should eventually be changed.
512 513 self.init_io()
513 514 self.init_traceback_handlers(custom_exceptions)
514 515 self.init_prompts()
515 516 self.init_display_formatter()
516 517 self.init_display_pub()
517 518 self.init_data_pub()
518 519 self.init_displayhook()
519 520 self.init_latextool()
520 521 self.init_magics()
521 522 self.init_alias()
522 523 self.init_logstart()
523 524 self.init_pdb()
524 525 self.init_extension_manager()
525 526 self.init_payload()
526 self.init_comms()
527 527 self.hooks.late_startup_hook()
528 528 self.events.trigger('shell_initialized', self)
529 529 atexit.register(self.atexit_operations)
530 530
531 531 def get_ipython(self):
532 532 """Return the currently running IPython instance."""
533 533 return self
534 534
535 535 #-------------------------------------------------------------------------
536 536 # Trait changed handlers
537 537 #-------------------------------------------------------------------------
538 538
539 539 def _ipython_dir_changed(self, name, new):
540 540 ensure_dir_exists(new)
541 541
542 542 def set_autoindent(self,value=None):
543 543 """Set the autoindent flag, checking for readline support.
544 544
545 545 If called with no arguments, it acts as a toggle."""
546 546
547 547 if value != 0 and not self.has_readline:
548 548 if os.name == 'posix':
549 549 warn("The auto-indent feature requires the readline library")
550 550 self.autoindent = 0
551 551 return
552 552 if value is None:
553 553 self.autoindent = not self.autoindent
554 554 else:
555 555 self.autoindent = value
556 556
557 557 #-------------------------------------------------------------------------
558 558 # init_* methods called by __init__
559 559 #-------------------------------------------------------------------------
560 560
561 561 def init_ipython_dir(self, ipython_dir):
562 562 if ipython_dir is not None:
563 563 self.ipython_dir = ipython_dir
564 564 return
565 565
566 566 self.ipython_dir = get_ipython_dir()
567 567
568 568 def init_profile_dir(self, profile_dir):
569 569 if profile_dir is not None:
570 570 self.profile_dir = profile_dir
571 571 return
572 572 self.profile_dir =\
573 573 ProfileDir.create_profile_dir_by_name(self.ipython_dir, 'default')
574 574
575 575 def init_instance_attrs(self):
576 576 self.more = False
577 577
578 578 # command compiler
579 579 self.compile = CachingCompiler()
580 580
581 581 # Make an empty namespace, which extension writers can rely on both
582 582 # existing and NEVER being used by ipython itself. This gives them a
583 583 # convenient location for storing additional information and state
584 584 # their extensions may require, without fear of collisions with other
585 585 # ipython names that may develop later.
586 586 self.meta = Struct()
587 587
588 588 # Temporary files used for various purposes. Deleted at exit.
589 589 self.tempfiles = []
590 590 self.tempdirs = []
591 591
592 592 # Keep track of readline usage (later set by init_readline)
593 593 self.has_readline = False
594 594
595 595 # keep track of where we started running (mainly for crash post-mortem)
596 596 # This is not being used anywhere currently.
597 597 self.starting_dir = py3compat.getcwd()
598 598
599 599 # Indentation management
600 600 self.indent_current_nsp = 0
601 601
602 602 # Dict to track post-execution functions that have been registered
603 603 self._post_execute = {}
604 604
605 605 def init_environment(self):
606 606 """Any changes we need to make to the user's environment."""
607 607 pass
608 608
609 609 def init_encoding(self):
610 610 # Get system encoding at startup time. Certain terminals (like Emacs
611 611 # under Win32 have it set to None, and we need to have a known valid
612 612 # encoding to use in the raw_input() method
613 613 try:
614 614 self.stdin_encoding = sys.stdin.encoding or 'ascii'
615 615 except AttributeError:
616 616 self.stdin_encoding = 'ascii'
617 617
618 618 def init_syntax_highlighting(self):
619 619 # Python source parser/formatter for syntax highlighting
620 620 pyformat = PyColorize.Parser().format
621 621 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
622 622
623 623 def init_pushd_popd_magic(self):
624 624 # for pushd/popd management
625 625 self.home_dir = get_home_dir()
626 626
627 627 self.dir_stack = []
628 628
629 629 def init_logger(self):
630 630 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
631 631 logmode='rotate')
632 632
633 633 def init_logstart(self):
634 634 """Initialize logging in case it was requested at the command line.
635 635 """
636 636 if self.logappend:
637 637 self.magic('logstart %s append' % self.logappend)
638 638 elif self.logfile:
639 639 self.magic('logstart %s' % self.logfile)
640 640 elif self.logstart:
641 641 self.magic('logstart')
642 642
643 643 def init_builtins(self):
644 644 # A single, static flag that we set to True. Its presence indicates
645 645 # that an IPython shell has been created, and we make no attempts at
646 646 # removing on exit or representing the existence of more than one
647 647 # IPython at a time.
648 648 builtin_mod.__dict__['__IPYTHON__'] = True
649 649
650 650 # In 0.11 we introduced '__IPYTHON__active' as an integer we'd try to
651 651 # manage on enter/exit, but with all our shells it's virtually
652 652 # impossible to get all the cases right. We're leaving the name in for
653 653 # those who adapted their codes to check for this flag, but will
654 654 # eventually remove it after a few more releases.
655 655 builtin_mod.__dict__['__IPYTHON__active'] = \
656 656 'Deprecated, check for __IPYTHON__'
657 657
658 658 self.builtin_trap = BuiltinTrap(shell=self)
659 659
660 660 def init_inspector(self):
661 661 # Object inspector
662 662 self.inspector = oinspect.Inspector(oinspect.InspectColors,
663 663 PyColorize.ANSICodeColors,
664 664 'NoColor',
665 665 self.object_info_string_level)
666 666
667 667 def init_io(self):
668 668 # This will just use sys.stdout and sys.stderr. If you want to
669 669 # override sys.stdout and sys.stderr themselves, you need to do that
670 670 # *before* instantiating this class, because io holds onto
671 671 # references to the underlying streams.
672 672 if (sys.platform == 'win32' or sys.platform == 'cli') and self.has_readline:
673 673 io.stdout = io.stderr = io.IOStream(self.readline._outputfile)
674 674 else:
675 675 io.stdout = io.IOStream(sys.stdout)
676 676 io.stderr = io.IOStream(sys.stderr)
677 677
678 678 def init_prompts(self):
679 679 self.prompt_manager = PromptManager(shell=self, parent=self)
680 680 self.configurables.append(self.prompt_manager)
681 681 # Set system prompts, so that scripts can decide if they are running
682 682 # interactively.
683 683 sys.ps1 = 'In : '
684 684 sys.ps2 = '...: '
685 685 sys.ps3 = 'Out: '
686 686
687 687 def init_display_formatter(self):
688 688 self.display_formatter = DisplayFormatter(parent=self)
689 689 self.configurables.append(self.display_formatter)
690 690
691 691 def init_display_pub(self):
692 692 self.display_pub = self.display_pub_class(parent=self)
693 693 self.configurables.append(self.display_pub)
694 694
695 695 def init_data_pub(self):
696 696 if not self.data_pub_class:
697 697 self.data_pub = None
698 698 return
699 699 self.data_pub = self.data_pub_class(parent=self)
700 700 self.configurables.append(self.data_pub)
701 701
702 702 def init_displayhook(self):
703 703 # Initialize displayhook, set in/out prompts and printing system
704 704 self.displayhook = self.displayhook_class(
705 705 parent=self,
706 706 shell=self,
707 707 cache_size=self.cache_size,
708 708 )
709 709 self.configurables.append(self.displayhook)
710 710 # This is a context manager that installs/revmoes the displayhook at
711 711 # the appropriate time.
712 712 self.display_trap = DisplayTrap(hook=self.displayhook)
713 713
714 714 def init_latextool(self):
715 715 """Configure LaTeXTool."""
716 716 cfg = LaTeXTool.instance(parent=self)
717 717 if cfg not in self.configurables:
718 718 self.configurables.append(cfg)
719 719
720 720 def init_virtualenv(self):
721 721 """Add a virtualenv to sys.path so the user can import modules from it.
722 722 This isn't perfect: it doesn't use the Python interpreter with which the
723 723 virtualenv was built, and it ignores the --no-site-packages option. A
724 724 warning will appear suggesting the user installs IPython in the
725 725 virtualenv, but for many cases, it probably works well enough.
726 726
727 727 Adapted from code snippets online.
728 728
729 729 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
730 730 """
731 731 if 'VIRTUAL_ENV' not in os.environ:
732 732 # Not in a virtualenv
733 733 return
734 734
735 735 # venv detection:
736 736 # stdlib venv may symlink sys.executable, so we can't use realpath.
737 737 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
738 738 # So we just check every item in the symlink tree (generally <= 3)
739 739 p = os.path.normcase(sys.executable)
740 740 paths = [p]
741 741 while os.path.islink(p):
742 742 p = os.path.normcase(os.path.join(os.path.dirname(p), os.readlink(p)))
743 743 paths.append(p)
744 744 p_venv = os.path.normcase(os.environ['VIRTUAL_ENV'])
745 745 if any(p.startswith(p_venv) for p in paths):
746 746 # Running properly in the virtualenv, don't need to do anything
747 747 return
748 748
749 749 warn("Attempting to work in a virtualenv. If you encounter problems, please "
750 750 "install IPython inside the virtualenv.")
751 751 if sys.platform == "win32":
752 752 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'Lib', 'site-packages')
753 753 else:
754 754 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'lib',
755 755 'python%d.%d' % sys.version_info[:2], 'site-packages')
756 756
757 757 import site
758 758 sys.path.insert(0, virtual_env)
759 759 site.addsitedir(virtual_env)
760 760
761 761 #-------------------------------------------------------------------------
762 762 # Things related to injections into the sys module
763 763 #-------------------------------------------------------------------------
764 764
765 765 def save_sys_module_state(self):
766 766 """Save the state of hooks in the sys module.
767 767
768 768 This has to be called after self.user_module is created.
769 769 """
770 770 self._orig_sys_module_state = {}
771 771 self._orig_sys_module_state['stdin'] = sys.stdin
772 772 self._orig_sys_module_state['stdout'] = sys.stdout
773 773 self._orig_sys_module_state['stderr'] = sys.stderr
774 774 self._orig_sys_module_state['excepthook'] = sys.excepthook
775 775 self._orig_sys_modules_main_name = self.user_module.__name__
776 776 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
777 777
778 778 def restore_sys_module_state(self):
779 779 """Restore the state of the sys module."""
780 780 try:
781 781 for k, v in iteritems(self._orig_sys_module_state):
782 782 setattr(sys, k, v)
783 783 except AttributeError:
784 784 pass
785 785 # Reset what what done in self.init_sys_modules
786 786 if self._orig_sys_modules_main_mod is not None:
787 787 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
788 788
789 789 #-------------------------------------------------------------------------
790 790 # Things related to the banner
791 791 #-------------------------------------------------------------------------
792 792
793 793 @property
794 794 def banner(self):
795 795 banner = self.banner1
796 796 if self.profile and self.profile != 'default':
797 797 banner += '\nIPython profile: %s\n' % self.profile
798 798 if self.banner2:
799 799 banner += '\n' + self.banner2
800 800 return banner
801 801
802 802 def show_banner(self, banner=None):
803 803 if banner is None:
804 804 banner = self.banner
805 805 self.write(banner)
806 806
807 807 #-------------------------------------------------------------------------
808 808 # Things related to hooks
809 809 #-------------------------------------------------------------------------
810 810
811 811 def init_hooks(self):
812 812 # hooks holds pointers used for user-side customizations
813 813 self.hooks = Struct()
814 814
815 815 self.strdispatchers = {}
816 816
817 817 # Set all default hooks, defined in the IPython.hooks module.
818 818 hooks = IPython.core.hooks
819 819 for hook_name in hooks.__all__:
820 820 # default hooks have priority 100, i.e. low; user hooks should have
821 821 # 0-100 priority
822 822 self.set_hook(hook_name,getattr(hooks,hook_name), 100, _warn_deprecated=False)
823 823
824 824 def set_hook(self,name,hook, priority=50, str_key=None, re_key=None,
825 825 _warn_deprecated=True):
826 826 """set_hook(name,hook) -> sets an internal IPython hook.
827 827
828 828 IPython exposes some of its internal API as user-modifiable hooks. By
829 829 adding your function to one of these hooks, you can modify IPython's
830 830 behavior to call at runtime your own routines."""
831 831
832 832 # At some point in the future, this should validate the hook before it
833 833 # accepts it. Probably at least check that the hook takes the number
834 834 # of args it's supposed to.
835 835
836 836 f = types.MethodType(hook,self)
837 837
838 838 # check if the hook is for strdispatcher first
839 839 if str_key is not None:
840 840 sdp = self.strdispatchers.get(name, StrDispatch())
841 841 sdp.add_s(str_key, f, priority )
842 842 self.strdispatchers[name] = sdp
843 843 return
844 844 if re_key is not None:
845 845 sdp = self.strdispatchers.get(name, StrDispatch())
846 846 sdp.add_re(re.compile(re_key), f, priority )
847 847 self.strdispatchers[name] = sdp
848 848 return
849 849
850 850 dp = getattr(self.hooks, name, None)
851 851 if name not in IPython.core.hooks.__all__:
852 852 print("Warning! Hook '%s' is not one of %s" % \
853 853 (name, IPython.core.hooks.__all__ ))
854 854
855 855 if _warn_deprecated and (name in IPython.core.hooks.deprecated):
856 856 alternative = IPython.core.hooks.deprecated[name]
857 857 warn("Hook {} is deprecated. Use {} instead.".format(name, alternative))
858 858
859 859 if not dp:
860 860 dp = IPython.core.hooks.CommandChainDispatcher()
861 861
862 862 try:
863 863 dp.add(f,priority)
864 864 except AttributeError:
865 865 # it was not commandchain, plain old func - replace
866 866 dp = f
867 867
868 868 setattr(self.hooks,name, dp)
869 869
870 870 #-------------------------------------------------------------------------
871 871 # Things related to events
872 872 #-------------------------------------------------------------------------
873 873
874 874 def init_events(self):
875 875 self.events = EventManager(self, available_events)
876 876
877 self.events.register("pre_execute", self._clear_warning_registry)
878
877 879 def register_post_execute(self, func):
878 880 """DEPRECATED: Use ip.events.register('post_run_cell', func)
879 881
880 882 Register a function for calling after code execution.
881 883 """
882 884 warn("ip.register_post_execute is deprecated, use "
883 885 "ip.events.register('post_run_cell', func) instead.")
884 886 self.events.register('post_run_cell', func)
885 887
888 def _clear_warning_registry(self):
889 # clear the warning registry, so that different code blocks with
890 # overlapping line number ranges don't cause spurious suppression of
891 # warnings (see gh-6611 for details)
892 if "__warningregistry__" in self.user_global_ns:
893 del self.user_global_ns["__warningregistry__"]
894
886 895 #-------------------------------------------------------------------------
887 896 # Things related to the "main" module
888 897 #-------------------------------------------------------------------------
889 898
890 899 def new_main_mod(self, filename, modname):
891 900 """Return a new 'main' module object for user code execution.
892 901
893 902 ``filename`` should be the path of the script which will be run in the
894 903 module. Requests with the same filename will get the same module, with
895 904 its namespace cleared.
896 905
897 906 ``modname`` should be the module name - normally either '__main__' or
898 907 the basename of the file without the extension.
899 908
900 909 When scripts are executed via %run, we must keep a reference to their
901 910 __main__ module around so that Python doesn't
902 911 clear it, rendering references to module globals useless.
903 912
904 913 This method keeps said reference in a private dict, keyed by the
905 914 absolute path of the script. This way, for multiple executions of the
906 915 same script we only keep one copy of the namespace (the last one),
907 916 thus preventing memory leaks from old references while allowing the
908 917 objects from the last execution to be accessible.
909 918 """
910 919 filename = os.path.abspath(filename)
911 920 try:
912 921 main_mod = self._main_mod_cache[filename]
913 922 except KeyError:
914 923 main_mod = self._main_mod_cache[filename] = types.ModuleType(
915 924 py3compat.cast_bytes_py2(modname),
916 925 doc="Module created for script run in IPython")
917 926 else:
918 927 main_mod.__dict__.clear()
919 928 main_mod.__name__ = modname
920 929
921 930 main_mod.__file__ = filename
922 931 # It seems pydoc (and perhaps others) needs any module instance to
923 932 # implement a __nonzero__ method
924 933 main_mod.__nonzero__ = lambda : True
925 934
926 935 return main_mod
927 936
928 937 def clear_main_mod_cache(self):
929 938 """Clear the cache of main modules.
930 939
931 940 Mainly for use by utilities like %reset.
932 941
933 942 Examples
934 943 --------
935 944
936 945 In [15]: import IPython
937 946
938 947 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
939 948
940 949 In [17]: len(_ip._main_mod_cache) > 0
941 950 Out[17]: True
942 951
943 952 In [18]: _ip.clear_main_mod_cache()
944 953
945 954 In [19]: len(_ip._main_mod_cache) == 0
946 955 Out[19]: True
947 956 """
948 957 self._main_mod_cache.clear()
949 958
950 959 #-------------------------------------------------------------------------
951 960 # Things related to debugging
952 961 #-------------------------------------------------------------------------
953 962
954 963 def init_pdb(self):
955 964 # Set calling of pdb on exceptions
956 965 # self.call_pdb is a property
957 966 self.call_pdb = self.pdb
958 967
959 968 def _get_call_pdb(self):
960 969 return self._call_pdb
961 970
962 971 def _set_call_pdb(self,val):
963 972
964 973 if val not in (0,1,False,True):
965 974 raise ValueError('new call_pdb value must be boolean')
966 975
967 976 # store value in instance
968 977 self._call_pdb = val
969 978
970 979 # notify the actual exception handlers
971 980 self.InteractiveTB.call_pdb = val
972 981
973 982 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
974 983 'Control auto-activation of pdb at exceptions')
975 984
976 985 def debugger(self,force=False):
977 986 """Call the pydb/pdb debugger.
978 987
979 988 Keywords:
980 989
981 990 - force(False): by default, this routine checks the instance call_pdb
982 991 flag and does not actually invoke the debugger if the flag is false.
983 992 The 'force' option forces the debugger to activate even if the flag
984 993 is false.
985 994 """
986 995
987 996 if not (force or self.call_pdb):
988 997 return
989 998
990 999 if not hasattr(sys,'last_traceback'):
991 1000 error('No traceback has been produced, nothing to debug.')
992 1001 return
993 1002
994 1003 # use pydb if available
995 1004 if debugger.has_pydb:
996 1005 from pydb import pm
997 1006 else:
998 1007 # fallback to our internal debugger
999 1008 pm = lambda : self.InteractiveTB.debugger(force=True)
1000 1009
1001 1010 with self.readline_no_record:
1002 1011 pm()
1003 1012
1004 1013 #-------------------------------------------------------------------------
1005 1014 # Things related to IPython's various namespaces
1006 1015 #-------------------------------------------------------------------------
1007 1016 default_user_namespaces = True
1008 1017
1009 1018 def init_create_namespaces(self, user_module=None, user_ns=None):
1010 1019 # Create the namespace where the user will operate. user_ns is
1011 1020 # normally the only one used, and it is passed to the exec calls as
1012 1021 # the locals argument. But we do carry a user_global_ns namespace
1013 1022 # given as the exec 'globals' argument, This is useful in embedding
1014 1023 # situations where the ipython shell opens in a context where the
1015 1024 # distinction between locals and globals is meaningful. For
1016 1025 # non-embedded contexts, it is just the same object as the user_ns dict.
1017 1026
1018 1027 # FIXME. For some strange reason, __builtins__ is showing up at user
1019 1028 # level as a dict instead of a module. This is a manual fix, but I
1020 1029 # should really track down where the problem is coming from. Alex
1021 1030 # Schmolck reported this problem first.
1022 1031
1023 1032 # A useful post by Alex Martelli on this topic:
1024 1033 # Re: inconsistent value from __builtins__
1025 1034 # Von: Alex Martelli <aleaxit@yahoo.com>
1026 1035 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
1027 1036 # Gruppen: comp.lang.python
1028 1037
1029 1038 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
1030 1039 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
1031 1040 # > <type 'dict'>
1032 1041 # > >>> print type(__builtins__)
1033 1042 # > <type 'module'>
1034 1043 # > Is this difference in return value intentional?
1035 1044
1036 1045 # Well, it's documented that '__builtins__' can be either a dictionary
1037 1046 # or a module, and it's been that way for a long time. Whether it's
1038 1047 # intentional (or sensible), I don't know. In any case, the idea is
1039 1048 # that if you need to access the built-in namespace directly, you
1040 1049 # should start with "import __builtin__" (note, no 's') which will
1041 1050 # definitely give you a module. Yeah, it's somewhat confusing:-(.
1042 1051
1043 1052 # These routines return a properly built module and dict as needed by
1044 1053 # the rest of the code, and can also be used by extension writers to
1045 1054 # generate properly initialized namespaces.
1046 1055 if (user_ns is not None) or (user_module is not None):
1047 1056 self.default_user_namespaces = False
1048 1057 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
1049 1058
1050 1059 # A record of hidden variables we have added to the user namespace, so
1051 1060 # we can list later only variables defined in actual interactive use.
1052 1061 self.user_ns_hidden = {}
1053 1062
1054 1063 # Now that FakeModule produces a real module, we've run into a nasty
1055 1064 # problem: after script execution (via %run), the module where the user
1056 1065 # code ran is deleted. Now that this object is a true module (needed
1057 1066 # so docetst and other tools work correctly), the Python module
1058 1067 # teardown mechanism runs over it, and sets to None every variable
1059 1068 # present in that module. Top-level references to objects from the
1060 1069 # script survive, because the user_ns is updated with them. However,
1061 1070 # calling functions defined in the script that use other things from
1062 1071 # the script will fail, because the function's closure had references
1063 1072 # to the original objects, which are now all None. So we must protect
1064 1073 # these modules from deletion by keeping a cache.
1065 1074 #
1066 1075 # To avoid keeping stale modules around (we only need the one from the
1067 1076 # last run), we use a dict keyed with the full path to the script, so
1068 1077 # only the last version of the module is held in the cache. Note,
1069 1078 # however, that we must cache the module *namespace contents* (their
1070 1079 # __dict__). Because if we try to cache the actual modules, old ones
1071 1080 # (uncached) could be destroyed while still holding references (such as
1072 1081 # those held by GUI objects that tend to be long-lived)>
1073 1082 #
1074 1083 # The %reset command will flush this cache. See the cache_main_mod()
1075 1084 # and clear_main_mod_cache() methods for details on use.
1076 1085
1077 1086 # This is the cache used for 'main' namespaces
1078 1087 self._main_mod_cache = {}
1079 1088
1080 1089 # A table holding all the namespaces IPython deals with, so that
1081 1090 # introspection facilities can search easily.
1082 1091 self.ns_table = {'user_global':self.user_module.__dict__,
1083 1092 'user_local':self.user_ns,
1084 1093 'builtin':builtin_mod.__dict__
1085 1094 }
1086 1095
1087 1096 @property
1088 1097 def user_global_ns(self):
1089 1098 return self.user_module.__dict__
1090 1099
1091 1100 def prepare_user_module(self, user_module=None, user_ns=None):
1092 1101 """Prepare the module and namespace in which user code will be run.
1093 1102
1094 1103 When IPython is started normally, both parameters are None: a new module
1095 1104 is created automatically, and its __dict__ used as the namespace.
1096 1105
1097 1106 If only user_module is provided, its __dict__ is used as the namespace.
1098 1107 If only user_ns is provided, a dummy module is created, and user_ns
1099 1108 becomes the global namespace. If both are provided (as they may be
1100 1109 when embedding), user_ns is the local namespace, and user_module
1101 1110 provides the global namespace.
1102 1111
1103 1112 Parameters
1104 1113 ----------
1105 1114 user_module : module, optional
1106 1115 The current user module in which IPython is being run. If None,
1107 1116 a clean module will be created.
1108 1117 user_ns : dict, optional
1109 1118 A namespace in which to run interactive commands.
1110 1119
1111 1120 Returns
1112 1121 -------
1113 1122 A tuple of user_module and user_ns, each properly initialised.
1114 1123 """
1115 1124 if user_module is None and user_ns is not None:
1116 1125 user_ns.setdefault("__name__", "__main__")
1117 1126 user_module = DummyMod()
1118 1127 user_module.__dict__ = user_ns
1119 1128
1120 1129 if user_module is None:
1121 1130 user_module = types.ModuleType("__main__",
1122 1131 doc="Automatically created module for IPython interactive environment")
1123 1132
1124 1133 # We must ensure that __builtin__ (without the final 's') is always
1125 1134 # available and pointing to the __builtin__ *module*. For more details:
1126 1135 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1127 1136 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1128 1137 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1129 1138
1130 1139 if user_ns is None:
1131 1140 user_ns = user_module.__dict__
1132 1141
1133 1142 return user_module, user_ns
1134 1143
1135 1144 def init_sys_modules(self):
1136 1145 # We need to insert into sys.modules something that looks like a
1137 1146 # module but which accesses the IPython namespace, for shelve and
1138 1147 # pickle to work interactively. Normally they rely on getting
1139 1148 # everything out of __main__, but for embedding purposes each IPython
1140 1149 # instance has its own private namespace, so we can't go shoving
1141 1150 # everything into __main__.
1142 1151
1143 1152 # note, however, that we should only do this for non-embedded
1144 1153 # ipythons, which really mimic the __main__.__dict__ with their own
1145 1154 # namespace. Embedded instances, on the other hand, should not do
1146 1155 # this because they need to manage the user local/global namespaces
1147 1156 # only, but they live within a 'normal' __main__ (meaning, they
1148 1157 # shouldn't overtake the execution environment of the script they're
1149 1158 # embedded in).
1150 1159
1151 1160 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1152 1161 main_name = self.user_module.__name__
1153 1162 sys.modules[main_name] = self.user_module
1154 1163
1155 1164 def init_user_ns(self):
1156 1165 """Initialize all user-visible namespaces to their minimum defaults.
1157 1166
1158 1167 Certain history lists are also initialized here, as they effectively
1159 1168 act as user namespaces.
1160 1169
1161 1170 Notes
1162 1171 -----
1163 1172 All data structures here are only filled in, they are NOT reset by this
1164 1173 method. If they were not empty before, data will simply be added to
1165 1174 therm.
1166 1175 """
1167 1176 # This function works in two parts: first we put a few things in
1168 1177 # user_ns, and we sync that contents into user_ns_hidden so that these
1169 1178 # initial variables aren't shown by %who. After the sync, we add the
1170 1179 # rest of what we *do* want the user to see with %who even on a new
1171 1180 # session (probably nothing, so theye really only see their own stuff)
1172 1181
1173 1182 # The user dict must *always* have a __builtin__ reference to the
1174 1183 # Python standard __builtin__ namespace, which must be imported.
1175 1184 # This is so that certain operations in prompt evaluation can be
1176 1185 # reliably executed with builtins. Note that we can NOT use
1177 1186 # __builtins__ (note the 's'), because that can either be a dict or a
1178 1187 # module, and can even mutate at runtime, depending on the context
1179 1188 # (Python makes no guarantees on it). In contrast, __builtin__ is
1180 1189 # always a module object, though it must be explicitly imported.
1181 1190
1182 1191 # For more details:
1183 1192 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1184 1193 ns = dict()
1185 1194
1186 1195 # make global variables for user access to the histories
1187 1196 ns['_ih'] = self.history_manager.input_hist_parsed
1188 1197 ns['_oh'] = self.history_manager.output_hist
1189 1198 ns['_dh'] = self.history_manager.dir_hist
1190 1199
1191 1200 ns['_sh'] = shadowns
1192 1201
1193 1202 # user aliases to input and output histories. These shouldn't show up
1194 1203 # in %who, as they can have very large reprs.
1195 1204 ns['In'] = self.history_manager.input_hist_parsed
1196 1205 ns['Out'] = self.history_manager.output_hist
1197 1206
1198 1207 # Store myself as the public api!!!
1199 1208 ns['get_ipython'] = self.get_ipython
1200 1209
1201 1210 ns['exit'] = self.exiter
1202 1211 ns['quit'] = self.exiter
1203 1212
1204 1213 # Sync what we've added so far to user_ns_hidden so these aren't seen
1205 1214 # by %who
1206 1215 self.user_ns_hidden.update(ns)
1207 1216
1208 1217 # Anything put into ns now would show up in %who. Think twice before
1209 1218 # putting anything here, as we really want %who to show the user their
1210 1219 # stuff, not our variables.
1211 1220
1212 1221 # Finally, update the real user's namespace
1213 1222 self.user_ns.update(ns)
1214 1223
1215 1224 @property
1216 1225 def all_ns_refs(self):
1217 1226 """Get a list of references to all the namespace dictionaries in which
1218 1227 IPython might store a user-created object.
1219 1228
1220 1229 Note that this does not include the displayhook, which also caches
1221 1230 objects from the output."""
1222 1231 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1223 1232 [m.__dict__ for m in self._main_mod_cache.values()]
1224 1233
1225 1234 def reset(self, new_session=True):
1226 1235 """Clear all internal namespaces, and attempt to release references to
1227 1236 user objects.
1228 1237
1229 1238 If new_session is True, a new history session will be opened.
1230 1239 """
1231 1240 # Clear histories
1232 1241 self.history_manager.reset(new_session)
1233 1242 # Reset counter used to index all histories
1234 1243 if new_session:
1235 1244 self.execution_count = 1
1236 1245
1237 1246 # Flush cached output items
1238 1247 if self.displayhook.do_full_cache:
1239 1248 self.displayhook.flush()
1240 1249
1241 1250 # The main execution namespaces must be cleared very carefully,
1242 1251 # skipping the deletion of the builtin-related keys, because doing so
1243 1252 # would cause errors in many object's __del__ methods.
1244 1253 if self.user_ns is not self.user_global_ns:
1245 1254 self.user_ns.clear()
1246 1255 ns = self.user_global_ns
1247 1256 drop_keys = set(ns.keys())
1248 1257 drop_keys.discard('__builtin__')
1249 1258 drop_keys.discard('__builtins__')
1250 1259 drop_keys.discard('__name__')
1251 1260 for k in drop_keys:
1252 1261 del ns[k]
1253 1262
1254 1263 self.user_ns_hidden.clear()
1255 1264
1256 1265 # Restore the user namespaces to minimal usability
1257 1266 self.init_user_ns()
1258 1267
1259 1268 # Restore the default and user aliases
1260 1269 self.alias_manager.clear_aliases()
1261 1270 self.alias_manager.init_aliases()
1262 1271
1263 1272 # Flush the private list of module references kept for script
1264 1273 # execution protection
1265 1274 self.clear_main_mod_cache()
1266 1275
1267 1276 def del_var(self, varname, by_name=False):
1268 1277 """Delete a variable from the various namespaces, so that, as
1269 1278 far as possible, we're not keeping any hidden references to it.
1270 1279
1271 1280 Parameters
1272 1281 ----------
1273 1282 varname : str
1274 1283 The name of the variable to delete.
1275 1284 by_name : bool
1276 1285 If True, delete variables with the given name in each
1277 1286 namespace. If False (default), find the variable in the user
1278 1287 namespace, and delete references to it.
1279 1288 """
1280 1289 if varname in ('__builtin__', '__builtins__'):
1281 1290 raise ValueError("Refusing to delete %s" % varname)
1282 1291
1283 1292 ns_refs = self.all_ns_refs
1284 1293
1285 1294 if by_name: # Delete by name
1286 1295 for ns in ns_refs:
1287 1296 try:
1288 1297 del ns[varname]
1289 1298 except KeyError:
1290 1299 pass
1291 1300 else: # Delete by object
1292 1301 try:
1293 1302 obj = self.user_ns[varname]
1294 1303 except KeyError:
1295 1304 raise NameError("name '%s' is not defined" % varname)
1296 1305 # Also check in output history
1297 1306 ns_refs.append(self.history_manager.output_hist)
1298 1307 for ns in ns_refs:
1299 1308 to_delete = [n for n, o in iteritems(ns) if o is obj]
1300 1309 for name in to_delete:
1301 1310 del ns[name]
1302 1311
1303 1312 # displayhook keeps extra references, but not in a dictionary
1304 1313 for name in ('_', '__', '___'):
1305 1314 if getattr(self.displayhook, name) is obj:
1306 1315 setattr(self.displayhook, name, None)
1307 1316
1308 1317 def reset_selective(self, regex=None):
1309 1318 """Clear selective variables from internal namespaces based on a
1310 1319 specified regular expression.
1311 1320
1312 1321 Parameters
1313 1322 ----------
1314 1323 regex : string or compiled pattern, optional
1315 1324 A regular expression pattern that will be used in searching
1316 1325 variable names in the users namespaces.
1317 1326 """
1318 1327 if regex is not None:
1319 1328 try:
1320 1329 m = re.compile(regex)
1321 1330 except TypeError:
1322 1331 raise TypeError('regex must be a string or compiled pattern')
1323 1332 # Search for keys in each namespace that match the given regex
1324 1333 # If a match is found, delete the key/value pair.
1325 1334 for ns in self.all_ns_refs:
1326 1335 for var in ns:
1327 1336 if m.search(var):
1328 1337 del ns[var]
1329 1338
1330 1339 def push(self, variables, interactive=True):
1331 1340 """Inject a group of variables into the IPython user namespace.
1332 1341
1333 1342 Parameters
1334 1343 ----------
1335 1344 variables : dict, str or list/tuple of str
1336 1345 The variables to inject into the user's namespace. If a dict, a
1337 1346 simple update is done. If a str, the string is assumed to have
1338 1347 variable names separated by spaces. A list/tuple of str can also
1339 1348 be used to give the variable names. If just the variable names are
1340 1349 give (list/tuple/str) then the variable values looked up in the
1341 1350 callers frame.
1342 1351 interactive : bool
1343 1352 If True (default), the variables will be listed with the ``who``
1344 1353 magic.
1345 1354 """
1346 1355 vdict = None
1347 1356
1348 1357 # We need a dict of name/value pairs to do namespace updates.
1349 1358 if isinstance(variables, dict):
1350 1359 vdict = variables
1351 1360 elif isinstance(variables, string_types+(list, tuple)):
1352 1361 if isinstance(variables, string_types):
1353 1362 vlist = variables.split()
1354 1363 else:
1355 1364 vlist = variables
1356 1365 vdict = {}
1357 1366 cf = sys._getframe(1)
1358 1367 for name in vlist:
1359 1368 try:
1360 1369 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1361 1370 except:
1362 1371 print('Could not get variable %s from %s' %
1363 1372 (name,cf.f_code.co_name))
1364 1373 else:
1365 1374 raise ValueError('variables must be a dict/str/list/tuple')
1366 1375
1367 1376 # Propagate variables to user namespace
1368 1377 self.user_ns.update(vdict)
1369 1378
1370 1379 # And configure interactive visibility
1371 1380 user_ns_hidden = self.user_ns_hidden
1372 1381 if interactive:
1373 1382 for name in vdict:
1374 1383 user_ns_hidden.pop(name, None)
1375 1384 else:
1376 1385 user_ns_hidden.update(vdict)
1377 1386
1378 1387 def drop_by_id(self, variables):
1379 1388 """Remove a dict of variables from the user namespace, if they are the
1380 1389 same as the values in the dictionary.
1381 1390
1382 1391 This is intended for use by extensions: variables that they've added can
1383 1392 be taken back out if they are unloaded, without removing any that the
1384 1393 user has overwritten.
1385 1394
1386 1395 Parameters
1387 1396 ----------
1388 1397 variables : dict
1389 1398 A dictionary mapping object names (as strings) to the objects.
1390 1399 """
1391 1400 for name, obj in iteritems(variables):
1392 1401 if name in self.user_ns and self.user_ns[name] is obj:
1393 1402 del self.user_ns[name]
1394 1403 self.user_ns_hidden.pop(name, None)
1395 1404
1396 1405 #-------------------------------------------------------------------------
1397 1406 # Things related to object introspection
1398 1407 #-------------------------------------------------------------------------
1399 1408
1400 1409 def _ofind(self, oname, namespaces=None):
1401 1410 """Find an object in the available namespaces.
1402 1411
1403 1412 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1404 1413
1405 1414 Has special code to detect magic functions.
1406 1415 """
1407 1416 oname = oname.strip()
1408 1417 #print '1- oname: <%r>' % oname # dbg
1409 1418 if not oname.startswith(ESC_MAGIC) and \
1410 1419 not oname.startswith(ESC_MAGIC2) and \
1411 1420 not py3compat.isidentifier(oname, dotted=True):
1412 1421 return dict(found=False)
1413 1422
1414 1423 alias_ns = None
1415 1424 if namespaces is None:
1416 1425 # Namespaces to search in:
1417 1426 # Put them in a list. The order is important so that we
1418 1427 # find things in the same order that Python finds them.
1419 1428 namespaces = [ ('Interactive', self.user_ns),
1420 1429 ('Interactive (global)', self.user_global_ns),
1421 1430 ('Python builtin', builtin_mod.__dict__),
1422 1431 ]
1423 1432
1424 1433 # initialize results to 'null'
1425 1434 found = False; obj = None; ospace = None; ds = None;
1426 1435 ismagic = False; isalias = False; parent = None
1427 1436
1428 1437 # We need to special-case 'print', which as of python2.6 registers as a
1429 1438 # function but should only be treated as one if print_function was
1430 1439 # loaded with a future import. In this case, just bail.
1431 1440 if (oname == 'print' and not py3compat.PY3 and not \
1432 1441 (self.compile.compiler_flags & __future__.CO_FUTURE_PRINT_FUNCTION)):
1433 1442 return {'found':found, 'obj':obj, 'namespace':ospace,
1434 1443 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1435 1444
1436 1445 # Look for the given name by splitting it in parts. If the head is
1437 1446 # found, then we look for all the remaining parts as members, and only
1438 1447 # declare success if we can find them all.
1439 1448 oname_parts = oname.split('.')
1440 1449 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1441 1450 for nsname,ns in namespaces:
1442 1451 try:
1443 1452 obj = ns[oname_head]
1444 1453 except KeyError:
1445 1454 continue
1446 1455 else:
1447 1456 #print 'oname_rest:', oname_rest # dbg
1448 1457 for idx, part in enumerate(oname_rest):
1449 1458 try:
1450 1459 parent = obj
1451 1460 # The last part is looked up in a special way to avoid
1452 1461 # descriptor invocation as it may raise or have side
1453 1462 # effects.
1454 1463 if idx == len(oname_rest) - 1:
1455 1464 obj = self._getattr_property(obj, part)
1456 1465 else:
1457 1466 obj = getattr(obj, part)
1458 1467 except:
1459 1468 # Blanket except b/c some badly implemented objects
1460 1469 # allow __getattr__ to raise exceptions other than
1461 1470 # AttributeError, which then crashes IPython.
1462 1471 break
1463 1472 else:
1464 1473 # If we finish the for loop (no break), we got all members
1465 1474 found = True
1466 1475 ospace = nsname
1467 1476 break # namespace loop
1468 1477
1469 1478 # Try to see if it's magic
1470 1479 if not found:
1471 1480 obj = None
1472 1481 if oname.startswith(ESC_MAGIC2):
1473 1482 oname = oname.lstrip(ESC_MAGIC2)
1474 1483 obj = self.find_cell_magic(oname)
1475 1484 elif oname.startswith(ESC_MAGIC):
1476 1485 oname = oname.lstrip(ESC_MAGIC)
1477 1486 obj = self.find_line_magic(oname)
1478 1487 else:
1479 1488 # search without prefix, so run? will find %run?
1480 1489 obj = self.find_line_magic(oname)
1481 1490 if obj is None:
1482 1491 obj = self.find_cell_magic(oname)
1483 1492 if obj is not None:
1484 1493 found = True
1485 1494 ospace = 'IPython internal'
1486 1495 ismagic = True
1487 1496
1488 1497 # Last try: special-case some literals like '', [], {}, etc:
1489 1498 if not found and oname_head in ["''",'""','[]','{}','()']:
1490 1499 obj = eval(oname_head)
1491 1500 found = True
1492 1501 ospace = 'Interactive'
1493 1502
1494 1503 return {'found':found, 'obj':obj, 'namespace':ospace,
1495 1504 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1496 1505
1497 1506 @staticmethod
1498 1507 def _getattr_property(obj, attrname):
1499 1508 """Property-aware getattr to use in object finding.
1500 1509
1501 1510 If attrname represents a property, return it unevaluated (in case it has
1502 1511 side effects or raises an error.
1503 1512
1504 1513 """
1505 1514 if not isinstance(obj, type):
1506 1515 try:
1507 1516 # `getattr(type(obj), attrname)` is not guaranteed to return
1508 1517 # `obj`, but does so for property:
1509 1518 #
1510 1519 # property.__get__(self, None, cls) -> self
1511 1520 #
1512 1521 # The universal alternative is to traverse the mro manually
1513 1522 # searching for attrname in class dicts.
1514 1523 attr = getattr(type(obj), attrname)
1515 1524 except AttributeError:
1516 1525 pass
1517 1526 else:
1518 1527 # This relies on the fact that data descriptors (with both
1519 1528 # __get__ & __set__ magic methods) take precedence over
1520 1529 # instance-level attributes:
1521 1530 #
1522 1531 # class A(object):
1523 1532 # @property
1524 1533 # def foobar(self): return 123
1525 1534 # a = A()
1526 1535 # a.__dict__['foobar'] = 345
1527 1536 # a.foobar # == 123
1528 1537 #
1529 1538 # So, a property may be returned right away.
1530 1539 if isinstance(attr, property):
1531 1540 return attr
1532 1541
1533 1542 # Nothing helped, fall back.
1534 1543 return getattr(obj, attrname)
1535 1544
1536 1545 def _object_find(self, oname, namespaces=None):
1537 1546 """Find an object and return a struct with info about it."""
1538 1547 return Struct(self._ofind(oname, namespaces))
1539 1548
1540 1549 def _inspect(self, meth, oname, namespaces=None, **kw):
1541 1550 """Generic interface to the inspector system.
1542 1551
1543 1552 This function is meant to be called by pdef, pdoc & friends."""
1544 1553 info = self._object_find(oname, namespaces)
1545 1554 if info.found:
1546 1555 pmethod = getattr(self.inspector, meth)
1547 1556 formatter = format_screen if info.ismagic else None
1548 1557 if meth == 'pdoc':
1549 1558 pmethod(info.obj, oname, formatter)
1550 1559 elif meth == 'pinfo':
1551 1560 pmethod(info.obj, oname, formatter, info, **kw)
1552 1561 else:
1553 1562 pmethod(info.obj, oname)
1554 1563 else:
1555 1564 print('Object `%s` not found.' % oname)
1556 1565 return 'not found' # so callers can take other action
1557 1566
1558 1567 def object_inspect(self, oname, detail_level=0):
1559 1568 """Get object info about oname"""
1560 1569 with self.builtin_trap:
1561 1570 info = self._object_find(oname)
1562 1571 if info.found:
1563 1572 return self.inspector.info(info.obj, oname, info=info,
1564 1573 detail_level=detail_level
1565 1574 )
1566 1575 else:
1567 1576 return oinspect.object_info(name=oname, found=False)
1568 1577
1569 1578 def object_inspect_text(self, oname, detail_level=0):
1570 1579 """Get object info as formatted text"""
1571 1580 with self.builtin_trap:
1572 1581 info = self._object_find(oname)
1573 1582 if info.found:
1574 1583 return self.inspector._format_info(info.obj, oname, info=info,
1575 1584 detail_level=detail_level
1576 1585 )
1577 1586 else:
1578 1587 raise KeyError(oname)
1579 1588
1580 1589 #-------------------------------------------------------------------------
1581 1590 # Things related to history management
1582 1591 #-------------------------------------------------------------------------
1583 1592
1584 1593 def init_history(self):
1585 1594 """Sets up the command history, and starts regular autosaves."""
1586 1595 self.history_manager = HistoryManager(shell=self, parent=self)
1587 1596 self.configurables.append(self.history_manager)
1588 1597
1589 1598 #-------------------------------------------------------------------------
1590 1599 # Things related to exception handling and tracebacks (not debugging)
1591 1600 #-------------------------------------------------------------------------
1592 1601
1593 1602 def init_traceback_handlers(self, custom_exceptions):
1594 1603 # Syntax error handler.
1595 1604 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor')
1596 1605
1597 1606 # The interactive one is initialized with an offset, meaning we always
1598 1607 # want to remove the topmost item in the traceback, which is our own
1599 1608 # internal code. Valid modes: ['Plain','Context','Verbose']
1600 1609 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1601 1610 color_scheme='NoColor',
1602 1611 tb_offset = 1,
1603 1612 check_cache=check_linecache_ipython)
1604 1613
1605 1614 # The instance will store a pointer to the system-wide exception hook,
1606 1615 # so that runtime code (such as magics) can access it. This is because
1607 1616 # during the read-eval loop, it may get temporarily overwritten.
1608 1617 self.sys_excepthook = sys.excepthook
1609 1618
1610 1619 # and add any custom exception handlers the user may have specified
1611 1620 self.set_custom_exc(*custom_exceptions)
1612 1621
1613 1622 # Set the exception mode
1614 1623 self.InteractiveTB.set_mode(mode=self.xmode)
1615 1624
1616 1625 def set_custom_exc(self, exc_tuple, handler):
1617 1626 """set_custom_exc(exc_tuple,handler)
1618 1627
1619 1628 Set a custom exception handler, which will be called if any of the
1620 1629 exceptions in exc_tuple occur in the mainloop (specifically, in the
1621 1630 run_code() method).
1622 1631
1623 1632 Parameters
1624 1633 ----------
1625 1634
1626 1635 exc_tuple : tuple of exception classes
1627 1636 A *tuple* of exception classes, for which to call the defined
1628 1637 handler. It is very important that you use a tuple, and NOT A
1629 1638 LIST here, because of the way Python's except statement works. If
1630 1639 you only want to trap a single exception, use a singleton tuple::
1631 1640
1632 1641 exc_tuple == (MyCustomException,)
1633 1642
1634 1643 handler : callable
1635 1644 handler must have the following signature::
1636 1645
1637 1646 def my_handler(self, etype, value, tb, tb_offset=None):
1638 1647 ...
1639 1648 return structured_traceback
1640 1649
1641 1650 Your handler must return a structured traceback (a list of strings),
1642 1651 or None.
1643 1652
1644 1653 This will be made into an instance method (via types.MethodType)
1645 1654 of IPython itself, and it will be called if any of the exceptions
1646 1655 listed in the exc_tuple are caught. If the handler is None, an
1647 1656 internal basic one is used, which just prints basic info.
1648 1657
1649 1658 To protect IPython from crashes, if your handler ever raises an
1650 1659 exception or returns an invalid result, it will be immediately
1651 1660 disabled.
1652 1661
1653 1662 WARNING: by putting in your own exception handler into IPython's main
1654 1663 execution loop, you run a very good chance of nasty crashes. This
1655 1664 facility should only be used if you really know what you are doing."""
1656 1665
1657 1666 assert type(exc_tuple)==type(()) , \
1658 1667 "The custom exceptions must be given AS A TUPLE."
1659 1668
1660 1669 def dummy_handler(self,etype,value,tb,tb_offset=None):
1661 1670 print('*** Simple custom exception handler ***')
1662 1671 print('Exception type :',etype)
1663 1672 print('Exception value:',value)
1664 1673 print('Traceback :',tb)
1665 1674 #print 'Source code :','\n'.join(self.buffer)
1666 1675
1667 1676 def validate_stb(stb):
1668 1677 """validate structured traceback return type
1669 1678
1670 1679 return type of CustomTB *should* be a list of strings, but allow
1671 1680 single strings or None, which are harmless.
1672 1681
1673 1682 This function will *always* return a list of strings,
1674 1683 and will raise a TypeError if stb is inappropriate.
1675 1684 """
1676 1685 msg = "CustomTB must return list of strings, not %r" % stb
1677 1686 if stb is None:
1678 1687 return []
1679 1688 elif isinstance(stb, string_types):
1680 1689 return [stb]
1681 1690 elif not isinstance(stb, list):
1682 1691 raise TypeError(msg)
1683 1692 # it's a list
1684 1693 for line in stb:
1685 1694 # check every element
1686 1695 if not isinstance(line, string_types):
1687 1696 raise TypeError(msg)
1688 1697 return stb
1689 1698
1690 1699 if handler is None:
1691 1700 wrapped = dummy_handler
1692 1701 else:
1693 1702 def wrapped(self,etype,value,tb,tb_offset=None):
1694 1703 """wrap CustomTB handler, to protect IPython from user code
1695 1704
1696 1705 This makes it harder (but not impossible) for custom exception
1697 1706 handlers to crash IPython.
1698 1707 """
1699 1708 try:
1700 1709 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1701 1710 return validate_stb(stb)
1702 1711 except:
1703 1712 # clear custom handler immediately
1704 1713 self.set_custom_exc((), None)
1705 1714 print("Custom TB Handler failed, unregistering", file=io.stderr)
1706 1715 # show the exception in handler first
1707 1716 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1708 1717 print(self.InteractiveTB.stb2text(stb), file=io.stdout)
1709 1718 print("The original exception:", file=io.stdout)
1710 1719 stb = self.InteractiveTB.structured_traceback(
1711 1720 (etype,value,tb), tb_offset=tb_offset
1712 1721 )
1713 1722 return stb
1714 1723
1715 1724 self.CustomTB = types.MethodType(wrapped,self)
1716 1725 self.custom_exceptions = exc_tuple
1717 1726
1718 1727 def excepthook(self, etype, value, tb):
1719 1728 """One more defense for GUI apps that call sys.excepthook.
1720 1729
1721 1730 GUI frameworks like wxPython trap exceptions and call
1722 1731 sys.excepthook themselves. I guess this is a feature that
1723 1732 enables them to keep running after exceptions that would
1724 1733 otherwise kill their mainloop. This is a bother for IPython
1725 1734 which excepts to catch all of the program exceptions with a try:
1726 1735 except: statement.
1727 1736
1728 1737 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1729 1738 any app directly invokes sys.excepthook, it will look to the user like
1730 1739 IPython crashed. In order to work around this, we can disable the
1731 1740 CrashHandler and replace it with this excepthook instead, which prints a
1732 1741 regular traceback using our InteractiveTB. In this fashion, apps which
1733 1742 call sys.excepthook will generate a regular-looking exception from
1734 1743 IPython, and the CrashHandler will only be triggered by real IPython
1735 1744 crashes.
1736 1745
1737 1746 This hook should be used sparingly, only in places which are not likely
1738 1747 to be true IPython errors.
1739 1748 """
1740 1749 self.showtraceback((etype, value, tb), tb_offset=0)
1741 1750
1742 1751 def _get_exc_info(self, exc_tuple=None):
1743 1752 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1744 1753
1745 1754 Ensures sys.last_type,value,traceback hold the exc_info we found,
1746 1755 from whichever source.
1747 1756
1748 1757 raises ValueError if none of these contain any information
1749 1758 """
1750 1759 if exc_tuple is None:
1751 1760 etype, value, tb = sys.exc_info()
1752 1761 else:
1753 1762 etype, value, tb = exc_tuple
1754 1763
1755 1764 if etype is None:
1756 1765 if hasattr(sys, 'last_type'):
1757 1766 etype, value, tb = sys.last_type, sys.last_value, \
1758 1767 sys.last_traceback
1759 1768
1760 1769 if etype is None:
1761 1770 raise ValueError("No exception to find")
1762 1771
1763 1772 # Now store the exception info in sys.last_type etc.
1764 1773 # WARNING: these variables are somewhat deprecated and not
1765 1774 # necessarily safe to use in a threaded environment, but tools
1766 1775 # like pdb depend on their existence, so let's set them. If we
1767 1776 # find problems in the field, we'll need to revisit their use.
1768 1777 sys.last_type = etype
1769 1778 sys.last_value = value
1770 1779 sys.last_traceback = tb
1771 1780
1772 1781 return etype, value, tb
1773 1782
1774 1783 def show_usage_error(self, exc):
1775 1784 """Show a short message for UsageErrors
1776 1785
1777 1786 These are special exceptions that shouldn't show a traceback.
1778 1787 """
1779 1788 self.write_err("UsageError: %s" % exc)
1780 1789
1790 def get_exception_only(self, exc_tuple=None):
1791 """
1792 Return as a string (ending with a newline) the exception that
1793 just occurred, without any traceback.
1794 """
1795 etype, value, tb = self._get_exc_info(exc_tuple)
1796 msg = traceback.format_exception_only(etype, value)
1797 return ''.join(msg)
1798
1781 1799 def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None,
1782 1800 exception_only=False):
1783 1801 """Display the exception that just occurred.
1784 1802
1785 1803 If nothing is known about the exception, this is the method which
1786 1804 should be used throughout the code for presenting user tracebacks,
1787 1805 rather than directly invoking the InteractiveTB object.
1788 1806
1789 1807 A specific showsyntaxerror() also exists, but this method can take
1790 1808 care of calling it if needed, so unless you are explicitly catching a
1791 1809 SyntaxError exception, don't try to analyze the stack manually and
1792 1810 simply call this method."""
1793 1811
1794 1812 try:
1795 1813 try:
1796 1814 etype, value, tb = self._get_exc_info(exc_tuple)
1797 1815 except ValueError:
1798 1816 self.write_err('No traceback available to show.\n')
1799 1817 return
1800 1818
1801 1819 if issubclass(etype, SyntaxError):
1802 1820 # Though this won't be called by syntax errors in the input
1803 1821 # line, there may be SyntaxError cases with imported code.
1804 1822 self.showsyntaxerror(filename)
1805 1823 elif etype is UsageError:
1806 1824 self.show_usage_error(value)
1807 1825 else:
1808 1826 if exception_only:
1809 1827 stb = ['An exception has occurred, use %tb to see '
1810 1828 'the full traceback.\n']
1811 1829 stb.extend(self.InteractiveTB.get_exception_only(etype,
1812 1830 value))
1813 1831 else:
1814 1832 try:
1815 1833 # Exception classes can customise their traceback - we
1816 1834 # use this in IPython.parallel for exceptions occurring
1817 1835 # in the engines. This should return a list of strings.
1818 1836 stb = value._render_traceback_()
1819 1837 except Exception:
1820 1838 stb = self.InteractiveTB.structured_traceback(etype,
1821 1839 value, tb, tb_offset=tb_offset)
1822 1840
1823 1841 self._showtraceback(etype, value, stb)
1824 1842 if self.call_pdb:
1825 1843 # drop into debugger
1826 1844 self.debugger(force=True)
1827 1845 return
1828 1846
1829 1847 # Actually show the traceback
1830 1848 self._showtraceback(etype, value, stb)
1831 1849
1832 1850 except KeyboardInterrupt:
1833 self.write_err("\nKeyboardInterrupt\n")
1851 self.write_err('\n' + self.get_exception_only())
1834 1852
1835 1853 def _showtraceback(self, etype, evalue, stb):
1836 1854 """Actually show a traceback.
1837 1855
1838 1856 Subclasses may override this method to put the traceback on a different
1839 1857 place, like a side channel.
1840 1858 """
1841 1859 print(self.InteractiveTB.stb2text(stb), file=io.stdout)
1842 1860
1843 1861 def showsyntaxerror(self, filename=None):
1844 1862 """Display the syntax error that just occurred.
1845 1863
1846 1864 This doesn't display a stack trace because there isn't one.
1847 1865
1848 1866 If a filename is given, it is stuffed in the exception instead
1849 1867 of what was there before (because Python's parser always uses
1850 1868 "<string>" when reading from a string).
1851 1869 """
1852 1870 etype, value, last_traceback = self._get_exc_info()
1853 1871
1854 1872 if filename and issubclass(etype, SyntaxError):
1855 1873 try:
1856 1874 value.filename = filename
1857 1875 except:
1858 1876 # Not the format we expect; leave it alone
1859 1877 pass
1860 1878
1861 1879 stb = self.SyntaxTB.structured_traceback(etype, value, [])
1862 1880 self._showtraceback(etype, value, stb)
1863 1881
1864 1882 # This is overridden in TerminalInteractiveShell to show a message about
1865 1883 # the %paste magic.
1866 1884 def showindentationerror(self):
1867 1885 """Called by run_cell when there's an IndentationError in code entered
1868 1886 at the prompt.
1869 1887
1870 1888 This is overridden in TerminalInteractiveShell to show a message about
1871 1889 the %paste magic."""
1872 1890 self.showsyntaxerror()
1873 1891
1874 1892 #-------------------------------------------------------------------------
1875 1893 # Things related to readline
1876 1894 #-------------------------------------------------------------------------
1877 1895
1878 1896 def init_readline(self):
1879 1897 """Command history completion/saving/reloading."""
1880 1898
1881 1899 if self.readline_use:
1882 1900 import IPython.utils.rlineimpl as readline
1883 1901
1884 1902 self.rl_next_input = None
1885 1903 self.rl_do_indent = False
1886 1904
1887 1905 if not self.readline_use or not readline.have_readline:
1888 1906 self.has_readline = False
1889 1907 self.readline = None
1890 1908 # Set a number of methods that depend on readline to be no-op
1891 1909 self.readline_no_record = no_op_context
1892 1910 self.set_readline_completer = no_op
1893 1911 self.set_custom_completer = no_op
1894 1912 if self.readline_use:
1895 1913 warn('Readline services not available or not loaded.')
1896 1914 else:
1897 1915 self.has_readline = True
1898 1916 self.readline = readline
1899 1917 sys.modules['readline'] = readline
1900 1918
1901 1919 # Platform-specific configuration
1902 1920 if os.name == 'nt':
1903 1921 # FIXME - check with Frederick to see if we can harmonize
1904 1922 # naming conventions with pyreadline to avoid this
1905 1923 # platform-dependent check
1906 1924 self.readline_startup_hook = readline.set_pre_input_hook
1907 1925 else:
1908 1926 self.readline_startup_hook = readline.set_startup_hook
1909 1927
1910 1928 # Readline config order:
1911 1929 # - IPython config (default value)
1912 1930 # - custom inputrc
1913 1931 # - IPython config (user customized)
1914 1932
1915 1933 # load IPython config before inputrc if default
1916 1934 # skip if libedit because parse_and_bind syntax is different
1917 1935 if not self._custom_readline_config and not readline.uses_libedit:
1918 1936 for rlcommand in self.readline_parse_and_bind:
1919 1937 readline.parse_and_bind(rlcommand)
1920 1938
1921 1939 # Load user's initrc file (readline config)
1922 1940 # Or if libedit is used, load editrc.
1923 1941 inputrc_name = os.environ.get('INPUTRC')
1924 1942 if inputrc_name is None:
1925 1943 inputrc_name = '.inputrc'
1926 1944 if readline.uses_libedit:
1927 1945 inputrc_name = '.editrc'
1928 1946 inputrc_name = os.path.join(self.home_dir, inputrc_name)
1929 1947 if os.path.isfile(inputrc_name):
1930 1948 try:
1931 1949 readline.read_init_file(inputrc_name)
1932 1950 except:
1933 1951 warn('Problems reading readline initialization file <%s>'
1934 1952 % inputrc_name)
1935 1953
1936 1954 # load IPython config after inputrc if user has customized
1937 1955 if self._custom_readline_config:
1938 1956 for rlcommand in self.readline_parse_and_bind:
1939 1957 readline.parse_and_bind(rlcommand)
1940 1958
1941 1959 # Remove some chars from the delimiters list. If we encounter
1942 1960 # unicode chars, discard them.
1943 1961 delims = readline.get_completer_delims()
1944 1962 if not py3compat.PY3:
1945 1963 delims = delims.encode("ascii", "ignore")
1946 1964 for d in self.readline_remove_delims:
1947 1965 delims = delims.replace(d, "")
1948 1966 delims = delims.replace(ESC_MAGIC, '')
1949 1967 readline.set_completer_delims(delims)
1950 1968 # Store these so we can restore them if something like rpy2 modifies
1951 1969 # them.
1952 1970 self.readline_delims = delims
1953 1971 # otherwise we end up with a monster history after a while:
1954 1972 readline.set_history_length(self.history_length)
1955 1973
1956 1974 self.refill_readline_hist()
1957 1975 self.readline_no_record = ReadlineNoRecord(self)
1958 1976
1959 1977 # Configure auto-indent for all platforms
1960 1978 self.set_autoindent(self.autoindent)
1961 1979
1962 1980 def refill_readline_hist(self):
1963 1981 # Load the last 1000 lines from history
1964 1982 self.readline.clear_history()
1965 1983 stdin_encoding = sys.stdin.encoding or "utf-8"
1966 1984 last_cell = u""
1967 1985 for _, _, cell in self.history_manager.get_tail(1000,
1968 1986 include_latest=True):
1969 1987 # Ignore blank lines and consecutive duplicates
1970 1988 cell = cell.rstrip()
1971 1989 if cell and (cell != last_cell):
1972 1990 try:
1973 1991 if self.multiline_history:
1974 1992 self.readline.add_history(py3compat.unicode_to_str(cell,
1975 1993 stdin_encoding))
1976 1994 else:
1977 1995 for line in cell.splitlines():
1978 1996 self.readline.add_history(py3compat.unicode_to_str(line,
1979 1997 stdin_encoding))
1980 1998 last_cell = cell
1981 1999
1982 2000 except TypeError:
1983 2001 # The history DB can get corrupted so it returns strings
1984 2002 # containing null bytes, which readline objects to.
1985 2003 continue
1986 2004
1987 2005 @skip_doctest
1988 2006 def set_next_input(self, s):
1989 2007 """ Sets the 'default' input string for the next command line.
1990 2008
1991 2009 Requires readline.
1992 2010
1993 2011 Example::
1994 2012
1995 2013 In [1]: _ip.set_next_input("Hello Word")
1996 2014 In [2]: Hello Word_ # cursor is here
1997 2015 """
1998 2016 self.rl_next_input = py3compat.cast_bytes_py2(s)
1999 2017
2000 2018 # Maybe move this to the terminal subclass?
2001 2019 def pre_readline(self):
2002 2020 """readline hook to be used at the start of each line.
2003 2021
2004 2022 Currently it handles auto-indent only."""
2005 2023
2006 2024 if self.rl_do_indent:
2007 2025 self.readline.insert_text(self._indent_current_str())
2008 2026 if self.rl_next_input is not None:
2009 2027 self.readline.insert_text(self.rl_next_input)
2010 2028 self.rl_next_input = None
2011 2029
2012 2030 def _indent_current_str(self):
2013 2031 """return the current level of indentation as a string"""
2014 2032 return self.input_splitter.indent_spaces * ' '
2015 2033
2016 2034 #-------------------------------------------------------------------------
2017 2035 # Things related to text completion
2018 2036 #-------------------------------------------------------------------------
2019 2037
2020 2038 def init_completer(self):
2021 2039 """Initialize the completion machinery.
2022 2040
2023 2041 This creates completion machinery that can be used by client code,
2024 2042 either interactively in-process (typically triggered by the readline
2025 2043 library), programatically (such as in test suites) or out-of-prcess
2026 2044 (typically over the network by remote frontends).
2027 2045 """
2028 2046 from IPython.core.completer import IPCompleter
2029 2047 from IPython.core.completerlib import (module_completer,
2030 2048 magic_run_completer, cd_completer, reset_completer)
2031 2049
2032 2050 self.Completer = IPCompleter(shell=self,
2033 2051 namespace=self.user_ns,
2034 2052 global_namespace=self.user_global_ns,
2035 2053 use_readline=self.has_readline,
2036 2054 parent=self,
2037 2055 )
2038 2056 self.configurables.append(self.Completer)
2039 2057
2040 2058 # Add custom completers to the basic ones built into IPCompleter
2041 2059 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
2042 2060 self.strdispatchers['complete_command'] = sdisp
2043 2061 self.Completer.custom_completers = sdisp
2044 2062
2045 2063 self.set_hook('complete_command', module_completer, str_key = 'import')
2046 2064 self.set_hook('complete_command', module_completer, str_key = 'from')
2047 2065 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
2048 2066 self.set_hook('complete_command', cd_completer, str_key = '%cd')
2049 2067 self.set_hook('complete_command', reset_completer, str_key = '%reset')
2050 2068
2051 2069 # Only configure readline if we truly are using readline. IPython can
2052 2070 # do tab-completion over the network, in GUIs, etc, where readline
2053 2071 # itself may be absent
2054 2072 if self.has_readline:
2055 2073 self.set_readline_completer()
2056 2074
2057 2075 def complete(self, text, line=None, cursor_pos=None):
2058 2076 """Return the completed text and a list of completions.
2059 2077
2060 2078 Parameters
2061 2079 ----------
2062 2080
2063 2081 text : string
2064 2082 A string of text to be completed on. It can be given as empty and
2065 2083 instead a line/position pair are given. In this case, the
2066 2084 completer itself will split the line like readline does.
2067 2085
2068 2086 line : string, optional
2069 2087 The complete line that text is part of.
2070 2088
2071 2089 cursor_pos : int, optional
2072 2090 The position of the cursor on the input line.
2073 2091
2074 2092 Returns
2075 2093 -------
2076 2094 text : string
2077 2095 The actual text that was completed.
2078 2096
2079 2097 matches : list
2080 2098 A sorted list with all possible completions.
2081 2099
2082 2100 The optional arguments allow the completion to take more context into
2083 2101 account, and are part of the low-level completion API.
2084 2102
2085 2103 This is a wrapper around the completion mechanism, similar to what
2086 2104 readline does at the command line when the TAB key is hit. By
2087 2105 exposing it as a method, it can be used by other non-readline
2088 2106 environments (such as GUIs) for text completion.
2089 2107
2090 2108 Simple usage example:
2091 2109
2092 2110 In [1]: x = 'hello'
2093 2111
2094 2112 In [2]: _ip.complete('x.l')
2095 2113 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2096 2114 """
2097 2115
2098 2116 # Inject names into __builtin__ so we can complete on the added names.
2099 2117 with self.builtin_trap:
2100 2118 return self.Completer.complete(text, line, cursor_pos)
2101 2119
2102 2120 def set_custom_completer(self, completer, pos=0):
2103 2121 """Adds a new custom completer function.
2104 2122
2105 2123 The position argument (defaults to 0) is the index in the completers
2106 2124 list where you want the completer to be inserted."""
2107 2125
2108 2126 newcomp = types.MethodType(completer,self.Completer)
2109 2127 self.Completer.matchers.insert(pos,newcomp)
2110 2128
2111 2129 def set_readline_completer(self):
2112 2130 """Reset readline's completer to be our own."""
2113 2131 self.readline.set_completer(self.Completer.rlcomplete)
2114 2132
2115 2133 def set_completer_frame(self, frame=None):
2116 2134 """Set the frame of the completer."""
2117 2135 if frame:
2118 2136 self.Completer.namespace = frame.f_locals
2119 2137 self.Completer.global_namespace = frame.f_globals
2120 2138 else:
2121 2139 self.Completer.namespace = self.user_ns
2122 2140 self.Completer.global_namespace = self.user_global_ns
2123 2141
2124 2142 #-------------------------------------------------------------------------
2125 2143 # Things related to magics
2126 2144 #-------------------------------------------------------------------------
2127 2145
2128 2146 def init_magics(self):
2129 2147 from IPython.core import magics as m
2130 2148 self.magics_manager = magic.MagicsManager(shell=self,
2131 2149 parent=self,
2132 2150 user_magics=m.UserMagics(self))
2133 2151 self.configurables.append(self.magics_manager)
2134 2152
2135 2153 # Expose as public API from the magics manager
2136 2154 self.register_magics = self.magics_manager.register
2137 2155 self.define_magic = self.magics_manager.define_magic
2138 2156
2139 2157 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2140 2158 m.ConfigMagics, m.DeprecatedMagics, m.DisplayMagics, m.ExecutionMagics,
2141 2159 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2142 2160 m.NamespaceMagics, m.OSMagics, m.PylabMagics, m.ScriptMagics,
2143 2161 )
2144 2162
2145 2163 # Register Magic Aliases
2146 2164 mman = self.magics_manager
2147 2165 # FIXME: magic aliases should be defined by the Magics classes
2148 2166 # or in MagicsManager, not here
2149 2167 mman.register_alias('ed', 'edit')
2150 2168 mman.register_alias('hist', 'history')
2151 2169 mman.register_alias('rep', 'recall')
2152 2170 mman.register_alias('SVG', 'svg', 'cell')
2153 2171 mman.register_alias('HTML', 'html', 'cell')
2154 2172 mman.register_alias('file', 'writefile', 'cell')
2155 2173
2156 2174 # FIXME: Move the color initialization to the DisplayHook, which
2157 2175 # should be split into a prompt manager and displayhook. We probably
2158 2176 # even need a centralize colors management object.
2159 2177 self.magic('colors %s' % self.colors)
2160 2178
2161 2179 # Defined here so that it's included in the documentation
2162 2180 @functools.wraps(magic.MagicsManager.register_function)
2163 2181 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2164 2182 self.magics_manager.register_function(func,
2165 2183 magic_kind=magic_kind, magic_name=magic_name)
2166 2184
2167 2185 def run_line_magic(self, magic_name, line):
2168 2186 """Execute the given line magic.
2169 2187
2170 2188 Parameters
2171 2189 ----------
2172 2190 magic_name : str
2173 2191 Name of the desired magic function, without '%' prefix.
2174 2192
2175 2193 line : str
2176 2194 The rest of the input line as a single string.
2177 2195 """
2178 2196 fn = self.find_line_magic(magic_name)
2179 2197 if fn is None:
2180 2198 cm = self.find_cell_magic(magic_name)
2181 2199 etpl = "Line magic function `%%%s` not found%s."
2182 2200 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2183 2201 'did you mean that instead?)' % magic_name )
2184 2202 error(etpl % (magic_name, extra))
2185 2203 else:
2186 2204 # Note: this is the distance in the stack to the user's frame.
2187 2205 # This will need to be updated if the internal calling logic gets
2188 2206 # refactored, or else we'll be expanding the wrong variables.
2189 2207 stack_depth = 2
2190 2208 magic_arg_s = self.var_expand(line, stack_depth)
2191 2209 # Put magic args in a list so we can call with f(*a) syntax
2192 2210 args = [magic_arg_s]
2193 2211 kwargs = {}
2194 2212 # Grab local namespace if we need it:
2195 2213 if getattr(fn, "needs_local_scope", False):
2196 2214 kwargs['local_ns'] = sys._getframe(stack_depth).f_locals
2197 2215 with self.builtin_trap:
2198 2216 result = fn(*args,**kwargs)
2199 2217 return result
2200 2218
2201 2219 def run_cell_magic(self, magic_name, line, cell):
2202 2220 """Execute the given cell magic.
2203 2221
2204 2222 Parameters
2205 2223 ----------
2206 2224 magic_name : str
2207 2225 Name of the desired magic function, without '%' prefix.
2208 2226
2209 2227 line : str
2210 2228 The rest of the first input line as a single string.
2211 2229
2212 2230 cell : str
2213 2231 The body of the cell as a (possibly multiline) string.
2214 2232 """
2215 2233 fn = self.find_cell_magic(magic_name)
2216 2234 if fn is None:
2217 2235 lm = self.find_line_magic(magic_name)
2218 2236 etpl = "Cell magic `%%{0}` not found{1}."
2219 2237 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2220 2238 'did you mean that instead?)'.format(magic_name))
2221 2239 error(etpl.format(magic_name, extra))
2222 2240 elif cell == '':
2223 2241 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2224 2242 if self.find_line_magic(magic_name) is not None:
2225 2243 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2226 2244 raise UsageError(message)
2227 2245 else:
2228 2246 # Note: this is the distance in the stack to the user's frame.
2229 2247 # This will need to be updated if the internal calling logic gets
2230 2248 # refactored, or else we'll be expanding the wrong variables.
2231 2249 stack_depth = 2
2232 2250 magic_arg_s = self.var_expand(line, stack_depth)
2233 2251 with self.builtin_trap:
2234 2252 result = fn(magic_arg_s, cell)
2235 2253 return result
2236 2254
2237 2255 def find_line_magic(self, magic_name):
2238 2256 """Find and return a line magic by name.
2239 2257
2240 2258 Returns None if the magic isn't found."""
2241 2259 return self.magics_manager.magics['line'].get(magic_name)
2242 2260
2243 2261 def find_cell_magic(self, magic_name):
2244 2262 """Find and return a cell magic by name.
2245 2263
2246 2264 Returns None if the magic isn't found."""
2247 2265 return self.magics_manager.magics['cell'].get(magic_name)
2248 2266
2249 2267 def find_magic(self, magic_name, magic_kind='line'):
2250 2268 """Find and return a magic of the given type by name.
2251 2269
2252 2270 Returns None if the magic isn't found."""
2253 2271 return self.magics_manager.magics[magic_kind].get(magic_name)
2254 2272
2255 2273 def magic(self, arg_s):
2256 2274 """DEPRECATED. Use run_line_magic() instead.
2257 2275
2258 2276 Call a magic function by name.
2259 2277
2260 2278 Input: a string containing the name of the magic function to call and
2261 2279 any additional arguments to be passed to the magic.
2262 2280
2263 2281 magic('name -opt foo bar') is equivalent to typing at the ipython
2264 2282 prompt:
2265 2283
2266 2284 In[1]: %name -opt foo bar
2267 2285
2268 2286 To call a magic without arguments, simply use magic('name').
2269 2287
2270 2288 This provides a proper Python function to call IPython's magics in any
2271 2289 valid Python code you can type at the interpreter, including loops and
2272 2290 compound statements.
2273 2291 """
2274 2292 # TODO: should we issue a loud deprecation warning here?
2275 2293 magic_name, _, magic_arg_s = arg_s.partition(' ')
2276 2294 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2277 2295 return self.run_line_magic(magic_name, magic_arg_s)
2278 2296
2279 2297 #-------------------------------------------------------------------------
2280 2298 # Things related to macros
2281 2299 #-------------------------------------------------------------------------
2282 2300
2283 2301 def define_macro(self, name, themacro):
2284 2302 """Define a new macro
2285 2303
2286 2304 Parameters
2287 2305 ----------
2288 2306 name : str
2289 2307 The name of the macro.
2290 2308 themacro : str or Macro
2291 2309 The action to do upon invoking the macro. If a string, a new
2292 2310 Macro object is created by passing the string to it.
2293 2311 """
2294 2312
2295 2313 from IPython.core import macro
2296 2314
2297 2315 if isinstance(themacro, string_types):
2298 2316 themacro = macro.Macro(themacro)
2299 2317 if not isinstance(themacro, macro.Macro):
2300 2318 raise ValueError('A macro must be a string or a Macro instance.')
2301 2319 self.user_ns[name] = themacro
2302 2320
2303 2321 #-------------------------------------------------------------------------
2304 2322 # Things related to the running of system commands
2305 2323 #-------------------------------------------------------------------------
2306 2324
2307 2325 def system_piped(self, cmd):
2308 2326 """Call the given cmd in a subprocess, piping stdout/err
2309 2327
2310 2328 Parameters
2311 2329 ----------
2312 2330 cmd : str
2313 2331 Command to execute (can not end in '&', as background processes are
2314 2332 not supported. Should not be a command that expects input
2315 2333 other than simple text.
2316 2334 """
2317 2335 if cmd.rstrip().endswith('&'):
2318 2336 # this is *far* from a rigorous test
2319 2337 # We do not support backgrounding processes because we either use
2320 2338 # pexpect or pipes to read from. Users can always just call
2321 2339 # os.system() or use ip.system=ip.system_raw
2322 2340 # if they really want a background process.
2323 2341 raise OSError("Background processes not supported.")
2324 2342
2325 2343 # we explicitly do NOT return the subprocess status code, because
2326 2344 # a non-None value would trigger :func:`sys.displayhook` calls.
2327 2345 # Instead, we store the exit_code in user_ns.
2328 2346 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2329 2347
2330 2348 def system_raw(self, cmd):
2331 2349 """Call the given cmd in a subprocess using os.system on Windows or
2332 2350 subprocess.call using the system shell on other platforms.
2333 2351
2334 2352 Parameters
2335 2353 ----------
2336 2354 cmd : str
2337 2355 Command to execute.
2338 2356 """
2339 2357 cmd = self.var_expand(cmd, depth=1)
2340 2358 # protect os.system from UNC paths on Windows, which it can't handle:
2341 2359 if sys.platform == 'win32':
2342 2360 from IPython.utils._process_win32 import AvoidUNCPath
2343 2361 with AvoidUNCPath() as path:
2344 2362 if path is not None:
2345 2363 cmd = '"pushd %s &&"%s' % (path, cmd)
2346 2364 cmd = py3compat.unicode_to_str(cmd)
2347 ec = os.system(cmd)
2365 try:
2366 ec = os.system(cmd)
2367 except KeyboardInterrupt:
2368 self.write_err('\n' + self.get_exception_only())
2369 ec = -2
2348 2370 else:
2349 2371 cmd = py3compat.unicode_to_str(cmd)
2350 # Call the cmd using the OS shell, instead of the default /bin/sh, if set.
2351 ec = subprocess.call(cmd, shell=True, executable=os.environ.get('SHELL', None))
2352 # exit code is positive for program failure, or negative for
2353 # terminating signal number.
2354
2355 # Interpret ec > 128 as signal
2356 # Some shells (csh, fish) don't follow sh/bash conventions for exit codes
2372 # For posix the result of the subprocess.call() below is an exit
2373 # code, which by convention is zero for success, positive for
2374 # program failure. Exit codes above 128 are reserved for signals,
2375 # and the formula for converting a signal to an exit code is usually
2376 # signal_number+128. To more easily differentiate between exit
2377 # codes and signals, ipython uses negative numbers. For instance
2378 # since control-c is signal 2 but exit code 130, ipython's
2379 # _exit_code variable will read -2. Note that some shells like
2380 # csh and fish don't follow sh/bash conventions for exit codes.
2381 executable = os.environ.get('SHELL', None)
2382 try:
2383 # Use env shell instead of default /bin/sh
2384 ec = subprocess.call(cmd, shell=True, executable=executable)
2385 except KeyboardInterrupt:
2386 # intercept control-C; a long traceback is not useful here
2387 self.write_err('\n' + self.get_exception_only())
2388 ec = 130
2357 2389 if ec > 128:
2358 2390 ec = -(ec - 128)
2359 2391
2360 2392 # We explicitly do NOT return the subprocess status code, because
2361 2393 # a non-None value would trigger :func:`sys.displayhook` calls.
2362 # Instead, we store the exit_code in user_ns.
2394 # Instead, we store the exit_code in user_ns. Note the semantics
2395 # of _exit_code: for control-c, _exit_code == -signal.SIGNIT,
2396 # but raising SystemExit(_exit_code) will give status 254!
2363 2397 self.user_ns['_exit_code'] = ec
2364 2398
2365 2399 # use piped system by default, because it is better behaved
2366 2400 system = system_piped
2367 2401
2368 2402 def getoutput(self, cmd, split=True, depth=0):
2369 2403 """Get output (possibly including stderr) from a subprocess.
2370 2404
2371 2405 Parameters
2372 2406 ----------
2373 2407 cmd : str
2374 2408 Command to execute (can not end in '&', as background processes are
2375 2409 not supported.
2376 2410 split : bool, optional
2377 2411 If True, split the output into an IPython SList. Otherwise, an
2378 2412 IPython LSString is returned. These are objects similar to normal
2379 2413 lists and strings, with a few convenience attributes for easier
2380 2414 manipulation of line-based output. You can use '?' on them for
2381 2415 details.
2382 2416 depth : int, optional
2383 2417 How many frames above the caller are the local variables which should
2384 2418 be expanded in the command string? The default (0) assumes that the
2385 2419 expansion variables are in the stack frame calling this function.
2386 2420 """
2387 2421 if cmd.rstrip().endswith('&'):
2388 2422 # this is *far* from a rigorous test
2389 2423 raise OSError("Background processes not supported.")
2390 2424 out = getoutput(self.var_expand(cmd, depth=depth+1))
2391 2425 if split:
2392 2426 out = SList(out.splitlines())
2393 2427 else:
2394 2428 out = LSString(out)
2395 2429 return out
2396 2430
2397 2431 #-------------------------------------------------------------------------
2398 2432 # Things related to aliases
2399 2433 #-------------------------------------------------------------------------
2400 2434
2401 2435 def init_alias(self):
2402 2436 self.alias_manager = AliasManager(shell=self, parent=self)
2403 2437 self.configurables.append(self.alias_manager)
2404 2438
2405 2439 #-------------------------------------------------------------------------
2406 2440 # Things related to extensions
2407 2441 #-------------------------------------------------------------------------
2408 2442
2409 2443 def init_extension_manager(self):
2410 2444 self.extension_manager = ExtensionManager(shell=self, parent=self)
2411 2445 self.configurables.append(self.extension_manager)
2412 2446
2413 2447 #-------------------------------------------------------------------------
2414 2448 # Things related to payloads
2415 2449 #-------------------------------------------------------------------------
2416 2450
2417 2451 def init_payload(self):
2418 2452 self.payload_manager = PayloadManager(parent=self)
2419 2453 self.configurables.append(self.payload_manager)
2420 2454
2421 2455 #-------------------------------------------------------------------------
2422 # Things related to widgets
2423 #-------------------------------------------------------------------------
2424
2425 def init_comms(self):
2426 # not implemented in the base class
2427 pass
2428
2429 #-------------------------------------------------------------------------
2430 2456 # Things related to the prefilter
2431 2457 #-------------------------------------------------------------------------
2432 2458
2433 2459 def init_prefilter(self):
2434 2460 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2435 2461 self.configurables.append(self.prefilter_manager)
2436 2462 # Ultimately this will be refactored in the new interpreter code, but
2437 2463 # for now, we should expose the main prefilter method (there's legacy
2438 2464 # code out there that may rely on this).
2439 2465 self.prefilter = self.prefilter_manager.prefilter_lines
2440 2466
2441 2467 def auto_rewrite_input(self, cmd):
2442 2468 """Print to the screen the rewritten form of the user's command.
2443 2469
2444 2470 This shows visual feedback by rewriting input lines that cause
2445 2471 automatic calling to kick in, like::
2446 2472
2447 2473 /f x
2448 2474
2449 2475 into::
2450 2476
2451 2477 ------> f(x)
2452 2478
2453 2479 after the user's input prompt. This helps the user understand that the
2454 2480 input line was transformed automatically by IPython.
2455 2481 """
2456 2482 if not self.show_rewritten_input:
2457 2483 return
2458 2484
2459 2485 rw = self.prompt_manager.render('rewrite') + cmd
2460 2486
2461 2487 try:
2462 2488 # plain ascii works better w/ pyreadline, on some machines, so
2463 2489 # we use it and only print uncolored rewrite if we have unicode
2464 2490 rw = str(rw)
2465 2491 print(rw, file=io.stdout)
2466 2492 except UnicodeEncodeError:
2467 2493 print("------> " + cmd)
2468 2494
2469 2495 #-------------------------------------------------------------------------
2470 2496 # Things related to extracting values/expressions from kernel and user_ns
2471 2497 #-------------------------------------------------------------------------
2472 2498
2473 2499 def _user_obj_error(self):
2474 2500 """return simple exception dict
2475 2501
2476 2502 for use in user_expressions
2477 2503 """
2478 2504
2479 2505 etype, evalue, tb = self._get_exc_info()
2480 2506 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2481 2507
2482 2508 exc_info = {
2483 2509 u'status' : 'error',
2484 2510 u'traceback' : stb,
2485 2511 u'ename' : unicode_type(etype.__name__),
2486 2512 u'evalue' : py3compat.safe_unicode(evalue),
2487 2513 }
2488 2514
2489 2515 return exc_info
2490 2516
2491 2517 def _format_user_obj(self, obj):
2492 2518 """format a user object to display dict
2493 2519
2494 2520 for use in user_expressions
2495 2521 """
2496 2522
2497 2523 data, md = self.display_formatter.format(obj)
2498 2524 value = {
2499 2525 'status' : 'ok',
2500 2526 'data' : data,
2501 2527 'metadata' : md,
2502 2528 }
2503 2529 return value
2504 2530
2505 2531 def user_expressions(self, expressions):
2506 2532 """Evaluate a dict of expressions in the user's namespace.
2507 2533
2508 2534 Parameters
2509 2535 ----------
2510 2536 expressions : dict
2511 2537 A dict with string keys and string values. The expression values
2512 2538 should be valid Python expressions, each of which will be evaluated
2513 2539 in the user namespace.
2514 2540
2515 2541 Returns
2516 2542 -------
2517 2543 A dict, keyed like the input expressions dict, with the rich mime-typed
2518 2544 display_data of each value.
2519 2545 """
2520 2546 out = {}
2521 2547 user_ns = self.user_ns
2522 2548 global_ns = self.user_global_ns
2523 2549
2524 2550 for key, expr in iteritems(expressions):
2525 2551 try:
2526 2552 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2527 2553 except:
2528 2554 value = self._user_obj_error()
2529 2555 out[key] = value
2530 2556 return out
2531 2557
2532 2558 #-------------------------------------------------------------------------
2533 2559 # Things related to the running of code
2534 2560 #-------------------------------------------------------------------------
2535 2561
2536 2562 def ex(self, cmd):
2537 2563 """Execute a normal python statement in user namespace."""
2538 2564 with self.builtin_trap:
2539 2565 exec(cmd, self.user_global_ns, self.user_ns)
2540 2566
2541 2567 def ev(self, expr):
2542 2568 """Evaluate python expression expr in user namespace.
2543 2569
2544 2570 Returns the result of evaluation
2545 2571 """
2546 2572 with self.builtin_trap:
2547 2573 return eval(expr, self.user_global_ns, self.user_ns)
2548 2574
2549 2575 def safe_execfile(self, fname, *where, **kw):
2550 2576 """A safe version of the builtin execfile().
2551 2577
2552 2578 This version will never throw an exception, but instead print
2553 2579 helpful error messages to the screen. This only works on pure
2554 2580 Python files with the .py extension.
2555 2581
2556 2582 Parameters
2557 2583 ----------
2558 2584 fname : string
2559 2585 The name of the file to be executed.
2560 2586 where : tuple
2561 2587 One or two namespaces, passed to execfile() as (globals,locals).
2562 2588 If only one is given, it is passed as both.
2563 2589 exit_ignore : bool (False)
2564 2590 If True, then silence SystemExit for non-zero status (it is always
2565 2591 silenced for zero status, as it is so common).
2566 2592 raise_exceptions : bool (False)
2567 2593 If True raise exceptions everywhere. Meant for testing.
2594 shell_futures : bool (False)
2595 If True, the code will share future statements with the interactive
2596 shell. It will both be affected by previous __future__ imports, and
2597 any __future__ imports in the code will affect the shell. If False,
2598 __future__ imports are not shared in either direction.
2568 2599
2569 2600 """
2570 2601 kw.setdefault('exit_ignore', False)
2571 2602 kw.setdefault('raise_exceptions', False)
2603 kw.setdefault('shell_futures', False)
2572 2604
2573 2605 fname = os.path.abspath(os.path.expanduser(fname))
2574 2606
2575 2607 # Make sure we can open the file
2576 2608 try:
2577 2609 with open(fname) as thefile:
2578 2610 pass
2579 2611 except:
2580 2612 warn('Could not open file <%s> for safe execution.' % fname)
2581 2613 return
2582 2614
2583 2615 # Find things also in current directory. This is needed to mimic the
2584 2616 # behavior of running a script from the system command line, where
2585 2617 # Python inserts the script's directory into sys.path
2586 2618 dname = os.path.dirname(fname)
2587 2619
2588 2620 with prepended_to_syspath(dname):
2589 2621 try:
2590 py3compat.execfile(fname,*where)
2622 glob, loc = (where + (None, ))[:2]
2623 py3compat.execfile(
2624 fname, glob, loc,
2625 self.compile if kw['shell_futures'] else None)
2591 2626 except SystemExit as status:
2592 2627 # If the call was made with 0 or None exit status (sys.exit(0)
2593 2628 # or sys.exit() ), don't bother showing a traceback, as both of
2594 2629 # these are considered normal by the OS:
2595 2630 # > python -c'import sys;sys.exit(0)'; echo $?
2596 2631 # 0
2597 2632 # > python -c'import sys;sys.exit()'; echo $?
2598 2633 # 0
2599 2634 # For other exit status, we show the exception unless
2600 2635 # explicitly silenced, but only in short form.
2601 2636 if kw['raise_exceptions']:
2602 2637 raise
2603 2638 if status.code and not kw['exit_ignore']:
2604 2639 self.showtraceback(exception_only=True)
2605 2640 except:
2606 2641 if kw['raise_exceptions']:
2607 2642 raise
2608 2643 # tb offset is 2 because we wrap execfile
2609 2644 self.showtraceback(tb_offset=2)
2610 2645
2611 def safe_execfile_ipy(self, fname):
2646 def safe_execfile_ipy(self, fname, shell_futures=False):
2612 2647 """Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
2613 2648
2614 2649 Parameters
2615 2650 ----------
2616 2651 fname : str
2617 2652 The name of the file to execute. The filename must have a
2618 2653 .ipy or .ipynb extension.
2654 shell_futures : bool (False)
2655 If True, the code will share future statements with the interactive
2656 shell. It will both be affected by previous __future__ imports, and
2657 any __future__ imports in the code will affect the shell. If False,
2658 __future__ imports are not shared in either direction.
2619 2659 """
2620 2660 fname = os.path.abspath(os.path.expanduser(fname))
2621 2661
2622 2662 # Make sure we can open the file
2623 2663 try:
2624 2664 with open(fname) as thefile:
2625 2665 pass
2626 2666 except:
2627 2667 warn('Could not open file <%s> for safe execution.' % fname)
2628 2668 return
2629 2669
2630 2670 # Find things also in current directory. This is needed to mimic the
2631 2671 # behavior of running a script from the system command line, where
2632 2672 # Python inserts the script's directory into sys.path
2633 2673 dname = os.path.dirname(fname)
2634 2674
2635 2675 def get_cells():
2636 2676 """generator for sequence of code blocks to run"""
2637 2677 if fname.endswith('.ipynb'):
2638 from IPython.nbformat import current
2639 with open(fname) as f:
2640 nb = current.read(f, 'json')
2641 if not nb.worksheets:
2678 from IPython.nbformat import read
2679 with io_open(fname) as f:
2680 nb = read(f, as_version=4)
2681 if not nb.cells:
2642 2682 return
2643 for cell in nb.worksheets[0].cells:
2683 for cell in nb.cells:
2644 2684 if cell.cell_type == 'code':
2645 yield cell.input
2685 yield cell.source
2646 2686 else:
2647 2687 with open(fname) as f:
2648 2688 yield f.read()
2649 2689
2650 2690 with prepended_to_syspath(dname):
2651 2691 try:
2652 2692 for cell in get_cells():
2653 2693 # self.run_cell currently captures all exceptions
2654 2694 # raised in user code. It would be nice if there were
2655 2695 # versions of run_cell that did raise, so
2656 2696 # we could catch the errors.
2657 self.run_cell(cell, silent=True, shell_futures=False)
2697 self.run_cell(cell, silent=True, shell_futures=shell_futures)
2658 2698 except:
2659 2699 self.showtraceback()
2660 2700 warn('Unknown failure executing file: <%s>' % fname)
2661 2701
2662 2702 def safe_run_module(self, mod_name, where):
2663 2703 """A safe version of runpy.run_module().
2664 2704
2665 2705 This version will never throw an exception, but instead print
2666 2706 helpful error messages to the screen.
2667 2707
2668 2708 `SystemExit` exceptions with status code 0 or None are ignored.
2669 2709
2670 2710 Parameters
2671 2711 ----------
2672 2712 mod_name : string
2673 2713 The name of the module to be executed.
2674 2714 where : dict
2675 2715 The globals namespace.
2676 2716 """
2677 2717 try:
2678 2718 try:
2679 2719 where.update(
2680 2720 runpy.run_module(str(mod_name), run_name="__main__",
2681 2721 alter_sys=True)
2682 2722 )
2683 2723 except SystemExit as status:
2684 2724 if status.code:
2685 2725 raise
2686 2726 except:
2687 2727 self.showtraceback()
2688 2728 warn('Unknown failure executing module: <%s>' % mod_name)
2689 2729
2690 2730 def _run_cached_cell_magic(self, magic_name, line):
2691 2731 """Special method to call a cell magic with the data stored in self.
2692 2732 """
2693 2733 cell = self._current_cell_magic_body
2694 2734 self._current_cell_magic_body = None
2695 2735 return self.run_cell_magic(magic_name, line, cell)
2696 2736
2697 2737 def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=True):
2698 2738 """Run a complete IPython cell.
2699 2739
2700 2740 Parameters
2701 2741 ----------
2702 2742 raw_cell : str
2703 2743 The code (including IPython code such as %magic functions) to run.
2704 2744 store_history : bool
2705 2745 If True, the raw and translated cell will be stored in IPython's
2706 2746 history. For user code calling back into IPython's machinery, this
2707 2747 should be set to False.
2708 2748 silent : bool
2709 2749 If True, avoid side-effects, such as implicit displayhooks and
2710 2750 and logging. silent=True forces store_history=False.
2711 2751 shell_futures : bool
2712 2752 If True, the code will share future statements with the interactive
2713 2753 shell. It will both be affected by previous __future__ imports, and
2714 2754 any __future__ imports in the code will affect the shell. If False,
2715 2755 __future__ imports are not shared in either direction.
2716 2756 """
2717 2757 if (not raw_cell) or raw_cell.isspace():
2718 2758 return
2719 2759
2720 2760 if silent:
2721 2761 store_history = False
2722 2762
2723 2763 self.events.trigger('pre_execute')
2724 2764 if not silent:
2725 2765 self.events.trigger('pre_run_cell')
2726 2766
2727 2767 # If any of our input transformation (input_transformer_manager or
2728 2768 # prefilter_manager) raises an exception, we store it in this variable
2729 2769 # so that we can display the error after logging the input and storing
2730 2770 # it in the history.
2731 2771 preprocessing_exc_tuple = None
2732 2772 try:
2733 2773 # Static input transformations
2734 2774 cell = self.input_transformer_manager.transform_cell(raw_cell)
2735 2775 except SyntaxError:
2736 2776 preprocessing_exc_tuple = sys.exc_info()
2737 2777 cell = raw_cell # cell has to exist so it can be stored/logged
2738 2778 else:
2739 2779 if len(cell.splitlines()) == 1:
2740 2780 # Dynamic transformations - only applied for single line commands
2741 2781 with self.builtin_trap:
2742 2782 try:
2743 2783 # use prefilter_lines to handle trailing newlines
2744 2784 # restore trailing newline for ast.parse
2745 2785 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
2746 2786 except Exception:
2747 2787 # don't allow prefilter errors to crash IPython
2748 2788 preprocessing_exc_tuple = sys.exc_info()
2749 2789
2750 2790 # Store raw and processed history
2751 2791 if store_history:
2752 2792 self.history_manager.store_inputs(self.execution_count,
2753 2793 cell, raw_cell)
2754 2794 if not silent:
2755 2795 self.logger.log(cell, raw_cell)
2756 2796
2757 2797 # Display the exception if input processing failed.
2758 2798 if preprocessing_exc_tuple is not None:
2759 2799 self.showtraceback(preprocessing_exc_tuple)
2760 2800 if store_history:
2761 2801 self.execution_count += 1
2762 2802 return
2763 2803
2764 2804 # Our own compiler remembers the __future__ environment. If we want to
2765 2805 # run code with a separate __future__ environment, use the default
2766 2806 # compiler
2767 2807 compiler = self.compile if shell_futures else CachingCompiler()
2768 2808
2769 2809 with self.builtin_trap:
2770 2810 cell_name = self.compile.cache(cell, self.execution_count)
2771 2811
2772 2812 with self.display_trap:
2773 2813 # Compile to bytecode
2774 2814 try:
2775 2815 code_ast = compiler.ast_parse(cell, filename=cell_name)
2776 2816 except IndentationError:
2777 2817 self.showindentationerror()
2778 2818 if store_history:
2779 2819 self.execution_count += 1
2780 2820 return None
2781 2821 except (OverflowError, SyntaxError, ValueError, TypeError,
2782 2822 MemoryError):
2783 2823 self.showsyntaxerror()
2784 2824 if store_history:
2785 2825 self.execution_count += 1
2786 2826 return None
2787 2827
2788 2828 # Apply AST transformations
2789 2829 try:
2790 2830 code_ast = self.transform_ast(code_ast)
2791 2831 except InputRejected:
2792 2832 self.showtraceback()
2793 2833 if store_history:
2794 2834 self.execution_count += 1
2795 2835 return None
2796 2836
2797 2837 # Execute the user code
2798 2838 interactivity = "none" if silent else self.ast_node_interactivity
2799 2839 self.run_ast_nodes(code_ast.body, cell_name,
2800 2840 interactivity=interactivity, compiler=compiler)
2801 2841
2802 2842 self.events.trigger('post_execute')
2803 2843 if not silent:
2804 2844 self.events.trigger('post_run_cell')
2805 2845
2806 2846 if store_history:
2807 2847 # Write output to the database. Does nothing unless
2808 2848 # history output logging is enabled.
2809 2849 self.history_manager.store_output(self.execution_count)
2810 2850 # Each cell is a *single* input, regardless of how many lines it has
2811 2851 self.execution_count += 1
2812 2852
2813 2853 def transform_ast(self, node):
2814 2854 """Apply the AST transformations from self.ast_transformers
2815 2855
2816 2856 Parameters
2817 2857 ----------
2818 2858 node : ast.Node
2819 2859 The root node to be transformed. Typically called with the ast.Module
2820 2860 produced by parsing user input.
2821 2861
2822 2862 Returns
2823 2863 -------
2824 2864 An ast.Node corresponding to the node it was called with. Note that it
2825 2865 may also modify the passed object, so don't rely on references to the
2826 2866 original AST.
2827 2867 """
2828 2868 for transformer in self.ast_transformers:
2829 2869 try:
2830 2870 node = transformer.visit(node)
2831 2871 except InputRejected:
2832 2872 # User-supplied AST transformers can reject an input by raising
2833 2873 # an InputRejected. Short-circuit in this case so that we
2834 2874 # don't unregister the transform.
2835 2875 raise
2836 2876 except Exception:
2837 2877 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
2838 2878 self.ast_transformers.remove(transformer)
2839 2879
2840 2880 if self.ast_transformers:
2841 2881 ast.fix_missing_locations(node)
2842 2882 return node
2843 2883
2844 2884
2845 2885 def run_ast_nodes(self, nodelist, cell_name, interactivity='last_expr',
2846 2886 compiler=compile):
2847 2887 """Run a sequence of AST nodes. The execution mode depends on the
2848 2888 interactivity parameter.
2849 2889
2850 2890 Parameters
2851 2891 ----------
2852 2892 nodelist : list
2853 2893 A sequence of AST nodes to run.
2854 2894 cell_name : str
2855 2895 Will be passed to the compiler as the filename of the cell. Typically
2856 2896 the value returned by ip.compile.cache(cell).
2857 2897 interactivity : str
2858 2898 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
2859 2899 run interactively (displaying output from expressions). 'last_expr'
2860 2900 will run the last node interactively only if it is an expression (i.e.
2861 2901 expressions in loops or other blocks are not displayed. Other values
2862 2902 for this parameter will raise a ValueError.
2863 2903 compiler : callable
2864 2904 A function with the same interface as the built-in compile(), to turn
2865 2905 the AST nodes into code objects. Default is the built-in compile().
2866 2906 """
2867 2907 if not nodelist:
2868 2908 return
2869 2909
2870 2910 if interactivity == 'last_expr':
2871 2911 if isinstance(nodelist[-1], ast.Expr):
2872 2912 interactivity = "last"
2873 2913 else:
2874 2914 interactivity = "none"
2875 2915
2876 2916 if interactivity == 'none':
2877 2917 to_run_exec, to_run_interactive = nodelist, []
2878 2918 elif interactivity == 'last':
2879 2919 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
2880 2920 elif interactivity == 'all':
2881 2921 to_run_exec, to_run_interactive = [], nodelist
2882 2922 else:
2883 2923 raise ValueError("Interactivity was %r" % interactivity)
2884 2924
2885 2925 exec_count = self.execution_count
2886 2926
2887 2927 try:
2888 2928 for i, node in enumerate(to_run_exec):
2889 2929 mod = ast.Module([node])
2890 2930 code = compiler(mod, cell_name, "exec")
2891 2931 if self.run_code(code):
2892 2932 return True
2893 2933
2894 2934 for i, node in enumerate(to_run_interactive):
2895 2935 mod = ast.Interactive([node])
2896 2936 code = compiler(mod, cell_name, "single")
2897 2937 if self.run_code(code):
2898 2938 return True
2899 2939
2900 2940 # Flush softspace
2901 2941 if softspace(sys.stdout, 0):
2902 2942 print()
2903 2943
2904 2944 except:
2905 2945 # It's possible to have exceptions raised here, typically by
2906 2946 # compilation of odd code (such as a naked 'return' outside a
2907 2947 # function) that did parse but isn't valid. Typically the exception
2908 2948 # is a SyntaxError, but it's safest just to catch anything and show
2909 2949 # the user a traceback.
2910 2950
2911 2951 # We do only one try/except outside the loop to minimize the impact
2912 2952 # on runtime, and also because if any node in the node list is
2913 2953 # broken, we should stop execution completely.
2914 2954 self.showtraceback()
2915 2955
2916 2956 return False
2917 2957
2918 2958 def run_code(self, code_obj):
2919 2959 """Execute a code object.
2920 2960
2921 2961 When an exception occurs, self.showtraceback() is called to display a
2922 2962 traceback.
2923 2963
2924 2964 Parameters
2925 2965 ----------
2926 2966 code_obj : code object
2927 2967 A compiled code object, to be executed
2928 2968
2929 2969 Returns
2930 2970 -------
2931 2971 False : successful execution.
2932 2972 True : an error occurred.
2933 2973 """
2934 2974 # Set our own excepthook in case the user code tries to call it
2935 2975 # directly, so that the IPython crash handler doesn't get triggered
2936 2976 old_excepthook, sys.excepthook = sys.excepthook, self.excepthook
2937 2977
2938 2978 # we save the original sys.excepthook in the instance, in case config
2939 2979 # code (such as magics) needs access to it.
2940 2980 self.sys_excepthook = old_excepthook
2941 2981 outflag = 1 # happens in more places, so it's easier as default
2942 2982 try:
2943 2983 try:
2944 2984 self.hooks.pre_run_code_hook()
2945 2985 #rprint('Running code', repr(code_obj)) # dbg
2946 2986 exec(code_obj, self.user_global_ns, self.user_ns)
2947 2987 finally:
2948 2988 # Reset our crash handler in place
2949 2989 sys.excepthook = old_excepthook
2950 2990 except SystemExit:
2951 2991 self.showtraceback(exception_only=True)
2952 2992 warn("To exit: use 'exit', 'quit', or Ctrl-D.", level=1)
2953 2993 except self.custom_exceptions:
2954 2994 etype, value, tb = sys.exc_info()
2955 2995 self.CustomTB(etype, value, tb)
2956 2996 except:
2957 2997 self.showtraceback()
2958 2998 else:
2959 2999 outflag = 0
2960 3000 return outflag
2961 3001
2962 3002 # For backwards compatibility
2963 3003 runcode = run_code
2964 3004
2965 3005 #-------------------------------------------------------------------------
2966 3006 # Things related to GUI support and pylab
2967 3007 #-------------------------------------------------------------------------
2968 3008
2969 3009 def enable_gui(self, gui=None):
2970 3010 raise NotImplementedError('Implement enable_gui in a subclass')
2971 3011
2972 3012 def enable_matplotlib(self, gui=None):
2973 3013 """Enable interactive matplotlib and inline figure support.
2974 3014
2975 3015 This takes the following steps:
2976 3016
2977 3017 1. select the appropriate eventloop and matplotlib backend
2978 3018 2. set up matplotlib for interactive use with that backend
2979 3019 3. configure formatters for inline figure display
2980 3020 4. enable the selected gui eventloop
2981 3021
2982 3022 Parameters
2983 3023 ----------
2984 3024 gui : optional, string
2985 3025 If given, dictates the choice of matplotlib GUI backend to use
2986 3026 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
2987 3027 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
2988 3028 matplotlib (as dictated by the matplotlib build-time options plus the
2989 3029 user's matplotlibrc configuration file). Note that not all backends
2990 3030 make sense in all contexts, for example a terminal ipython can't
2991 3031 display figures inline.
2992 3032 """
2993 3033 from IPython.core import pylabtools as pt
2994 3034 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
2995 3035
2996 3036 if gui != 'inline':
2997 3037 # If we have our first gui selection, store it
2998 3038 if self.pylab_gui_select is None:
2999 3039 self.pylab_gui_select = gui
3000 3040 # Otherwise if they are different
3001 3041 elif gui != self.pylab_gui_select:
3002 3042 print ('Warning: Cannot change to a different GUI toolkit: %s.'
3003 3043 ' Using %s instead.' % (gui, self.pylab_gui_select))
3004 3044 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
3005 3045
3006 3046 pt.activate_matplotlib(backend)
3007 3047 pt.configure_inline_support(self, backend)
3008 3048
3009 3049 # Now we must activate the gui pylab wants to use, and fix %run to take
3010 3050 # plot updates into account
3011 3051 self.enable_gui(gui)
3012 3052 self.magics_manager.registry['ExecutionMagics'].default_runner = \
3013 3053 pt.mpl_runner(self.safe_execfile)
3014 3054
3015 3055 return gui, backend
3016 3056
3017 3057 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
3018 3058 """Activate pylab support at runtime.
3019 3059
3020 3060 This turns on support for matplotlib, preloads into the interactive
3021 3061 namespace all of numpy and pylab, and configures IPython to correctly
3022 3062 interact with the GUI event loop. The GUI backend to be used can be
3023 3063 optionally selected with the optional ``gui`` argument.
3024 3064
3025 3065 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
3026 3066
3027 3067 Parameters
3028 3068 ----------
3029 3069 gui : optional, string
3030 3070 If given, dictates the choice of matplotlib GUI backend to use
3031 3071 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3032 3072 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3033 3073 matplotlib (as dictated by the matplotlib build-time options plus the
3034 3074 user's matplotlibrc configuration file). Note that not all backends
3035 3075 make sense in all contexts, for example a terminal ipython can't
3036 3076 display figures inline.
3037 3077 import_all : optional, bool, default: True
3038 3078 Whether to do `from numpy import *` and `from pylab import *`
3039 3079 in addition to module imports.
3040 3080 welcome_message : deprecated
3041 3081 This argument is ignored, no welcome message will be displayed.
3042 3082 """
3043 3083 from IPython.core.pylabtools import import_pylab
3044 3084
3045 3085 gui, backend = self.enable_matplotlib(gui)
3046 3086
3047 3087 # We want to prevent the loading of pylab to pollute the user's
3048 3088 # namespace as shown by the %who* magics, so we execute the activation
3049 3089 # code in an empty namespace, and we update *both* user_ns and
3050 3090 # user_ns_hidden with this information.
3051 3091 ns = {}
3052 3092 import_pylab(ns, import_all)
3053 3093 # warn about clobbered names
3054 3094 ignored = set(["__builtins__"])
3055 3095 both = set(ns).intersection(self.user_ns).difference(ignored)
3056 3096 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
3057 3097 self.user_ns.update(ns)
3058 3098 self.user_ns_hidden.update(ns)
3059 3099 return gui, backend, clobbered
3060 3100
3061 3101 #-------------------------------------------------------------------------
3062 3102 # Utilities
3063 3103 #-------------------------------------------------------------------------
3064 3104
3065 3105 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
3066 3106 """Expand python variables in a string.
3067 3107
3068 3108 The depth argument indicates how many frames above the caller should
3069 3109 be walked to look for the local namespace where to expand variables.
3070 3110
3071 3111 The global namespace for expansion is always the user's interactive
3072 3112 namespace.
3073 3113 """
3074 3114 ns = self.user_ns.copy()
3075 ns.update(sys._getframe(depth+1).f_locals)
3115 try:
3116 frame = sys._getframe(depth+1)
3117 except ValueError:
3118 # This is thrown if there aren't that many frames on the stack,
3119 # e.g. if a script called run_line_magic() directly.
3120 pass
3121 else:
3122 ns.update(frame.f_locals)
3123
3076 3124 try:
3077 3125 # We have to use .vformat() here, because 'self' is a valid and common
3078 3126 # name, and expanding **ns for .format() would make it collide with
3079 3127 # the 'self' argument of the method.
3080 3128 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
3081 3129 except Exception:
3082 3130 # if formatter couldn't format, just let it go untransformed
3083 3131 pass
3084 3132 return cmd
3085 3133
3086 3134 def mktempfile(self, data=None, prefix='ipython_edit_'):
3087 3135 """Make a new tempfile and return its filename.
3088 3136
3089 3137 This makes a call to tempfile.mkstemp (created in a tempfile.mkdtemp),
3090 3138 but it registers the created filename internally so ipython cleans it up
3091 3139 at exit time.
3092 3140
3093 3141 Optional inputs:
3094 3142
3095 3143 - data(None): if data is given, it gets written out to the temp file
3096 3144 immediately, and the file is closed again."""
3097 3145
3098 3146 dirname = tempfile.mkdtemp(prefix=prefix)
3099 3147 self.tempdirs.append(dirname)
3100 3148
3101 3149 handle, filename = tempfile.mkstemp('.py', prefix, dir=dirname)
3102 3150 os.close(handle) # On Windows, there can only be one open handle on a file
3103 3151 self.tempfiles.append(filename)
3104 3152
3105 3153 if data:
3106 3154 tmp_file = open(filename,'w')
3107 3155 tmp_file.write(data)
3108 3156 tmp_file.close()
3109 3157 return filename
3110 3158
3111 3159 # TODO: This should be removed when Term is refactored.
3112 3160 def write(self,data):
3113 3161 """Write a string to the default output"""
3114 3162 io.stdout.write(data)
3115 3163
3116 3164 # TODO: This should be removed when Term is refactored.
3117 3165 def write_err(self,data):
3118 3166 """Write a string to the default error output"""
3119 3167 io.stderr.write(data)
3120 3168
3121 3169 def ask_yes_no(self, prompt, default=None):
3122 3170 if self.quiet:
3123 3171 return True
3124 3172 return ask_yes_no(prompt,default)
3125 3173
3126 3174 def show_usage(self):
3127 3175 """Show a usage message"""
3128 3176 page.page(IPython.core.usage.interactive_usage)
3129 3177
3130 3178 def extract_input_lines(self, range_str, raw=False):
3131 3179 """Return as a string a set of input history slices.
3132 3180
3133 3181 Parameters
3134 3182 ----------
3135 3183 range_str : string
3136 3184 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3137 3185 since this function is for use by magic functions which get their
3138 3186 arguments as strings. The number before the / is the session
3139 3187 number: ~n goes n back from the current session.
3140 3188
3141 3189 raw : bool, optional
3142 3190 By default, the processed input is used. If this is true, the raw
3143 3191 input history is used instead.
3144 3192
3145 3193 Notes
3146 3194 -----
3147 3195
3148 3196 Slices can be described with two notations:
3149 3197
3150 3198 * ``N:M`` -> standard python form, means including items N...(M-1).
3151 3199 * ``N-M`` -> include items N..M (closed endpoint).
3152 3200 """
3153 3201 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3154 3202 return "\n".join(x for _, _, x in lines)
3155 3203
3156 3204 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True, search_ns=False):
3157 3205 """Get a code string from history, file, url, or a string or macro.
3158 3206
3159 3207 This is mainly used by magic functions.
3160 3208
3161 3209 Parameters
3162 3210 ----------
3163 3211
3164 3212 target : str
3165 3213
3166 3214 A string specifying code to retrieve. This will be tried respectively
3167 3215 as: ranges of input history (see %history for syntax), url,
3168 3216 correspnding .py file, filename, or an expression evaluating to a
3169 3217 string or Macro in the user namespace.
3170 3218
3171 3219 raw : bool
3172 3220 If true (default), retrieve raw history. Has no effect on the other
3173 3221 retrieval mechanisms.
3174 3222
3175 3223 py_only : bool (default False)
3176 3224 Only try to fetch python code, do not try alternative methods to decode file
3177 3225 if unicode fails.
3178 3226
3179 3227 Returns
3180 3228 -------
3181 3229 A string of code.
3182 3230
3183 3231 ValueError is raised if nothing is found, and TypeError if it evaluates
3184 3232 to an object of another type. In each case, .args[0] is a printable
3185 3233 message.
3186 3234 """
3187 3235 code = self.extract_input_lines(target, raw=raw) # Grab history
3188 3236 if code:
3189 3237 return code
3190 3238 utarget = unquote_filename(target)
3191 3239 try:
3192 3240 if utarget.startswith(('http://', 'https://')):
3193 3241 return openpy.read_py_url(utarget, skip_encoding_cookie=skip_encoding_cookie)
3194 3242 except UnicodeDecodeError:
3195 3243 if not py_only :
3196 3244 # Deferred import
3197 3245 try:
3198 3246 from urllib.request import urlopen # Py3
3199 3247 except ImportError:
3200 3248 from urllib import urlopen
3201 3249 response = urlopen(target)
3202 3250 return response.read().decode('latin1')
3203 3251 raise ValueError(("'%s' seem to be unreadable.") % utarget)
3204 3252
3205 3253 potential_target = [target]
3206 3254 try :
3207 3255 potential_target.insert(0,get_py_filename(target))
3208 3256 except IOError:
3209 3257 pass
3210 3258
3211 3259 for tgt in potential_target :
3212 3260 if os.path.isfile(tgt): # Read file
3213 3261 try :
3214 3262 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3215 3263 except UnicodeDecodeError :
3216 3264 if not py_only :
3217 3265 with io_open(tgt,'r', encoding='latin1') as f :
3218 3266 return f.read()
3219 3267 raise ValueError(("'%s' seem to be unreadable.") % target)
3220 3268 elif os.path.isdir(os.path.expanduser(tgt)):
3221 3269 raise ValueError("'%s' is a directory, not a regular file." % target)
3222 3270
3223 3271 if search_ns:
3224 3272 # Inspect namespace to load object source
3225 3273 object_info = self.object_inspect(target, detail_level=1)
3226 3274 if object_info['found'] and object_info['source']:
3227 3275 return object_info['source']
3228 3276
3229 3277 try: # User namespace
3230 3278 codeobj = eval(target, self.user_ns)
3231 3279 except Exception:
3232 3280 raise ValueError(("'%s' was not found in history, as a file, url, "
3233 3281 "nor in the user namespace.") % target)
3234 3282
3235 3283 if isinstance(codeobj, string_types):
3236 3284 return codeobj
3237 3285 elif isinstance(codeobj, Macro):
3238 3286 return codeobj.value
3239 3287
3240 3288 raise TypeError("%s is neither a string nor a macro." % target,
3241 3289 codeobj)
3242 3290
3243 3291 #-------------------------------------------------------------------------
3244 3292 # Things related to IPython exiting
3245 3293 #-------------------------------------------------------------------------
3246 3294 def atexit_operations(self):
3247 3295 """This will be executed at the time of exit.
3248 3296
3249 3297 Cleanup operations and saving of persistent data that is done
3250 3298 unconditionally by IPython should be performed here.
3251 3299
3252 3300 For things that may depend on startup flags or platform specifics (such
3253 3301 as having readline or not), register a separate atexit function in the
3254 3302 code that has the appropriate information, rather than trying to
3255 3303 clutter
3256 3304 """
3257 3305 # Close the history session (this stores the end time and line count)
3258 3306 # this must be *before* the tempfile cleanup, in case of temporary
3259 3307 # history db
3260 3308 self.history_manager.end_session()
3261 3309
3262 3310 # Cleanup all tempfiles and folders left around
3263 3311 for tfile in self.tempfiles:
3264 3312 try:
3265 3313 os.unlink(tfile)
3266 3314 except OSError:
3267 3315 pass
3268 3316
3269 3317 for tdir in self.tempdirs:
3270 3318 try:
3271 3319 os.rmdir(tdir)
3272 3320 except OSError:
3273 3321 pass
3274 3322
3275 3323 # Clear all user namespaces to release all references cleanly.
3276 3324 self.reset(new_session=False)
3277 3325
3278 3326 # Run user hooks
3279 3327 self.hooks.shutdown_hook()
3280 3328
3281 3329 def cleanup(self):
3282 3330 self.restore_sys_module_state()
3283 3331
3284 3332
3285 3333 class InteractiveShellABC(with_metaclass(abc.ABCMeta, object)):
3286 3334 """An abstract base class for InteractiveShell."""
3287 3335
3288 3336 InteractiveShellABC.register(InteractiveShell)
@@ -1,656 +1,611 b''
1 """Implementation of basic magic functions.
2 """
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
5 #
6 # Distributed under the terms of the Modified BSD License.
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
10
11 #-----------------------------------------------------------------------------
12 # Imports
13 #-----------------------------------------------------------------------------
1 """Implementation of basic magic functions."""
2
14 3 from __future__ import print_function
15 4
16 # Stdlib
17 5 import io
18 6 import json
19 7 import sys
20 8 from pprint import pformat
21 9
22 # Our own packages
23 10 from IPython.core import magic_arguments, page
24 11 from IPython.core.error import UsageError
25 12 from IPython.core.magic import Magics, magics_class, line_magic, magic_escapes
26 13 from IPython.utils.text import format_screen, dedent, indent
27 14 from IPython.testing.skipdoctest import skip_doctest
28 15 from IPython.utils.ipstruct import Struct
29 16 from IPython.utils.path import unquote_filename
30 17 from IPython.utils.py3compat import unicode_type
31 18 from IPython.utils.warn import warn, error
32 19
33 #-----------------------------------------------------------------------------
34 # Magics class implementation
35 #-----------------------------------------------------------------------------
36 20
37 21 class MagicsDisplay(object):
38 22 def __init__(self, magics_manager):
39 23 self.magics_manager = magics_manager
40 24
41 25 def _lsmagic(self):
42 26 """The main implementation of the %lsmagic"""
43 27 mesc = magic_escapes['line']
44 28 cesc = magic_escapes['cell']
45 29 mman = self.magics_manager
46 30 magics = mman.lsmagic()
47 31 out = ['Available line magics:',
48 32 mesc + (' '+mesc).join(sorted(magics['line'])),
49 33 '',
50 34 'Available cell magics:',
51 35 cesc + (' '+cesc).join(sorted(magics['cell'])),
52 36 '',
53 37 mman.auto_status()]
54 38 return '\n'.join(out)
55 39
56 40 def _repr_pretty_(self, p, cycle):
57 41 p.text(self._lsmagic())
58 42
59 43 def __str__(self):
60 44 return self._lsmagic()
61 45
62 46 def _jsonable(self):
63 47 """turn magics dict into jsonable dict of the same structure
64 48
65 49 replaces object instances with their class names as strings
66 50 """
67 51 magic_dict = {}
68 52 mman = self.magics_manager
69 53 magics = mman.lsmagic()
70 54 for key, subdict in magics.items():
71 55 d = {}
72 56 magic_dict[key] = d
73 57 for name, obj in subdict.items():
74 58 try:
75 59 classname = obj.__self__.__class__.__name__
76 60 except AttributeError:
77 61 classname = 'Other'
78 62
79 63 d[name] = classname
80 64 return magic_dict
81 65
82 66 def _repr_json_(self):
83 67 return json.dumps(self._jsonable())
84 68
85 69
86 70 @magics_class
87 71 class BasicMagics(Magics):
88 72 """Magics that provide central IPython functionality.
89 73
90 74 These are various magics that don't fit into specific categories but that
91 75 are all part of the base 'IPython experience'."""
92 76
93 77 @magic_arguments.magic_arguments()
94 78 @magic_arguments.argument(
95 79 '-l', '--line', action='store_true',
96 80 help="""Create a line magic alias."""
97 81 )
98 82 @magic_arguments.argument(
99 83 '-c', '--cell', action='store_true',
100 84 help="""Create a cell magic alias."""
101 85 )
102 86 @magic_arguments.argument(
103 87 'name',
104 88 help="""Name of the magic to be created."""
105 89 )
106 90 @magic_arguments.argument(
107 91 'target',
108 92 help="""Name of the existing line or cell magic."""
109 93 )
110 94 @line_magic
111 95 def alias_magic(self, line=''):
112 96 """Create an alias for an existing line or cell magic.
113 97
114 98 Examples
115 99 --------
116 100 ::
117 101
118 102 In [1]: %alias_magic t timeit
119 103 Created `%t` as an alias for `%timeit`.
120 104 Created `%%t` as an alias for `%%timeit`.
121 105
122 106 In [2]: %t -n1 pass
123 107 1 loops, best of 3: 954 ns per loop
124 108
125 109 In [3]: %%t -n1
126 110 ...: pass
127 111 ...:
128 112 1 loops, best of 3: 954 ns per loop
129 113
130 114 In [4]: %alias_magic --cell whereami pwd
131 115 UsageError: Cell magic function `%%pwd` not found.
132 116 In [5]: %alias_magic --line whereami pwd
133 117 Created `%whereami` as an alias for `%pwd`.
134 118
135 119 In [6]: %whereami
136 120 Out[6]: u'/home/testuser'
137 121 """
138 122 args = magic_arguments.parse_argstring(self.alias_magic, line)
139 123 shell = self.shell
140 124 mman = self.shell.magics_manager
141 125 escs = ''.join(magic_escapes.values())
142 126
143 127 target = args.target.lstrip(escs)
144 128 name = args.name.lstrip(escs)
145 129
146 130 # Find the requested magics.
147 131 m_line = shell.find_magic(target, 'line')
148 132 m_cell = shell.find_magic(target, 'cell')
149 133 if args.line and m_line is None:
150 134 raise UsageError('Line magic function `%s%s` not found.' %
151 135 (magic_escapes['line'], target))
152 136 if args.cell and m_cell is None:
153 137 raise UsageError('Cell magic function `%s%s` not found.' %
154 138 (magic_escapes['cell'], target))
155 139
156 140 # If --line and --cell are not specified, default to the ones
157 141 # that are available.
158 142 if not args.line and not args.cell:
159 143 if not m_line and not m_cell:
160 144 raise UsageError(
161 145 'No line or cell magic with name `%s` found.' % target
162 146 )
163 147 args.line = bool(m_line)
164 148 args.cell = bool(m_cell)
165 149
166 150 if args.line:
167 151 mman.register_alias(name, target, 'line')
168 152 print('Created `%s%s` as an alias for `%s%s`.' % (
169 153 magic_escapes['line'], name,
170 154 magic_escapes['line'], target))
171 155
172 156 if args.cell:
173 157 mman.register_alias(name, target, 'cell')
174 158 print('Created `%s%s` as an alias for `%s%s`.' % (
175 159 magic_escapes['cell'], name,
176 160 magic_escapes['cell'], target))
177 161
178 162 @line_magic
179 163 def lsmagic(self, parameter_s=''):
180 164 """List currently available magic functions."""
181 165 return MagicsDisplay(self.shell.magics_manager)
182 166
183 167 def _magic_docs(self, brief=False, rest=False):
184 168 """Return docstrings from magic functions."""
185 169 mman = self.shell.magics_manager
186 170 docs = mman.lsmagic_docs(brief, missing='No documentation')
187 171
188 172 if rest:
189 173 format_string = '**%s%s**::\n\n%s\n\n'
190 174 else:
191 175 format_string = '%s%s:\n%s\n'
192 176
193 177 return ''.join(
194 178 [format_string % (magic_escapes['line'], fname,
195 179 indent(dedent(fndoc)))
196 180 for fname, fndoc in sorted(docs['line'].items())]
197 181 +
198 182 [format_string % (magic_escapes['cell'], fname,
199 183 indent(dedent(fndoc)))
200 184 for fname, fndoc in sorted(docs['cell'].items())]
201 185 )
202 186
203 187 @line_magic
204 188 def magic(self, parameter_s=''):
205 189 """Print information about the magic function system.
206 190
207 191 Supported formats: -latex, -brief, -rest
208 192 """
209 193
210 194 mode = ''
211 195 try:
212 196 mode = parameter_s.split()[0][1:]
213 197 if mode == 'rest':
214 198 rest_docs = []
215 199 except IndexError:
216 200 pass
217 201
218 202 brief = (mode == 'brief')
219 203 rest = (mode == 'rest')
220 204 magic_docs = self._magic_docs(brief, rest)
221 205
222 206 if mode == 'latex':
223 207 print(self.format_latex(magic_docs))
224 208 return
225 209 else:
226 210 magic_docs = format_screen(magic_docs)
227 211
228 212 out = ["""
229 213 IPython's 'magic' functions
230 214 ===========================
231 215
232 216 The magic function system provides a series of functions which allow you to
233 217 control the behavior of IPython itself, plus a lot of system-type
234 218 features. There are two kinds of magics, line-oriented and cell-oriented.
235 219
236 220 Line magics are prefixed with the % character and work much like OS
237 221 command-line calls: they get as an argument the rest of the line, where
238 222 arguments are passed without parentheses or quotes. For example, this will
239 223 time the given statement::
240 224
241 225 %timeit range(1000)
242 226
243 227 Cell magics are prefixed with a double %%, and they are functions that get as
244 228 an argument not only the rest of the line, but also the lines below it in a
245 229 separate argument. These magics are called with two arguments: the rest of the
246 230 call line and the body of the cell, consisting of the lines below the first.
247 231 For example::
248 232
249 233 %%timeit x = numpy.random.randn((100, 100))
250 234 numpy.linalg.svd(x)
251 235
252 236 will time the execution of the numpy svd routine, running the assignment of x
253 237 as part of the setup phase, which is not timed.
254 238
255 239 In a line-oriented client (the terminal or Qt console IPython), starting a new
256 240 input with %% will automatically enter cell mode, and IPython will continue
257 241 reading input until a blank line is given. In the notebook, simply type the
258 242 whole cell as one entity, but keep in mind that the %% escape can only be at
259 243 the very start of the cell.
260 244
261 245 NOTE: If you have 'automagic' enabled (via the command line option or with the
262 246 %automagic function), you don't need to type in the % explicitly for line
263 247 magics; cell magics always require an explicit '%%' escape. By default,
264 248 IPython ships with automagic on, so you should only rarely need the % escape.
265 249
266 250 Example: typing '%cd mydir' (without the quotes) changes you working directory
267 251 to 'mydir', if it exists.
268 252
269 253 For a list of the available magic functions, use %lsmagic. For a description
270 254 of any of them, type %magic_name?, e.g. '%cd?'.
271 255
272 256 Currently the magic system has the following functions:""",
273 257 magic_docs,
274 258 "Summary of magic functions (from %slsmagic):" % magic_escapes['line'],
275 259 str(self.lsmagic()),
276 260 ]
277 261 page.page('\n'.join(out))
278 262
279 263
280 264 @line_magic
281 265 def page(self, parameter_s=''):
282 266 """Pretty print the object and display it through a pager.
283 267
284 268 %page [options] OBJECT
285 269
286 270 If no object is given, use _ (last output).
287 271
288 272 Options:
289 273
290 274 -r: page str(object), don't pretty-print it."""
291 275
292 276 # After a function contributed by Olivier Aubert, slightly modified.
293 277
294 278 # Process options/args
295 279 opts, args = self.parse_options(parameter_s, 'r')
296 280 raw = 'r' in opts
297 281
298 282 oname = args and args or '_'
299 283 info = self.shell._ofind(oname)
300 284 if info['found']:
301 285 txt = (raw and str or pformat)( info['obj'] )
302 286 page.page(txt)
303 287 else:
304 288 print('Object `%s` not found' % oname)
305 289
306 290 @line_magic
307 291 def profile(self, parameter_s=''):
308 292 """Print your currently active IPython profile.
309 293
310 294 See Also
311 295 --------
312 296 prun : run code using the Python profiler
313 297 (:meth:`~IPython.core.magics.execution.ExecutionMagics.prun`)
314 298 """
315 299 warn("%profile is now deprecated. Please use get_ipython().profile instead.")
316 300 from IPython.core.application import BaseIPythonApplication
317 301 if BaseIPythonApplication.initialized():
318 302 print(BaseIPythonApplication.instance().profile)
319 303 else:
320 304 error("profile is an application-level value, but you don't appear to be in an IPython application")
321 305
322 306 @line_magic
323 307 def pprint(self, parameter_s=''):
324 308 """Toggle pretty printing on/off."""
325 309 ptformatter = self.shell.display_formatter.formatters['text/plain']
326 310 ptformatter.pprint = bool(1 - ptformatter.pprint)
327 311 print('Pretty printing has been turned',
328 312 ['OFF','ON'][ptformatter.pprint])
329 313
330 314 @line_magic
331 315 def colors(self, parameter_s=''):
332 316 """Switch color scheme for prompts, info system and exception handlers.
333 317
334 318 Currently implemented schemes: NoColor, Linux, LightBG.
335 319
336 320 Color scheme names are not case-sensitive.
337 321
338 322 Examples
339 323 --------
340 324 To get a plain black and white terminal::
341 325
342 326 %colors nocolor
343 327 """
344 328 def color_switch_err(name):
345 329 warn('Error changing %s color schemes.\n%s' %
346 330 (name, sys.exc_info()[1]))
347 331
348 332
349 333 new_scheme = parameter_s.strip()
350 334 if not new_scheme:
351 335 raise UsageError(
352 336 "%colors: you must specify a color scheme. See '%colors?'")
353 337 # local shortcut
354 338 shell = self.shell
355 339
356 340 import IPython.utils.rlineimpl as readline
357 341
358 342 if not shell.colors_force and \
359 343 not readline.have_readline and \
360 344 (sys.platform == "win32" or sys.platform == "cli"):
361 345 msg = """\
362 346 Proper color support under MS Windows requires the pyreadline library.
363 347 You can find it at:
364 348 http://ipython.org/pyreadline.html
365 Gary's readline needs the ctypes module, from:
366 http://starship.python.net/crew/theller/ctypes
367 (Note that ctypes is already part of Python versions 2.5 and newer).
368 349
369 350 Defaulting color scheme to 'NoColor'"""
370 351 new_scheme = 'NoColor'
371 352 warn(msg)
372 353
373 354 # readline option is 0
374 355 if not shell.colors_force and not shell.has_readline:
375 356 new_scheme = 'NoColor'
376 357
377 358 # Set prompt colors
378 359 try:
379 360 shell.prompt_manager.color_scheme = new_scheme
380 361 except:
381 362 color_switch_err('prompt')
382 363 else:
383 364 shell.colors = \
384 365 shell.prompt_manager.color_scheme_table.active_scheme_name
385 366 # Set exception colors
386 367 try:
387 368 shell.InteractiveTB.set_colors(scheme = new_scheme)
388 369 shell.SyntaxTB.set_colors(scheme = new_scheme)
389 370 except:
390 371 color_switch_err('exception')
391 372
392 373 # Set info (for 'object?') colors
393 374 if shell.color_info:
394 375 try:
395 376 shell.inspector.set_active_scheme(new_scheme)
396 377 except:
397 378 color_switch_err('object inspector')
398 379 else:
399 380 shell.inspector.set_active_scheme('NoColor')
400 381
401 382 @line_magic
402 383 def xmode(self, parameter_s=''):
403 384 """Switch modes for the exception handlers.
404 385
405 386 Valid modes: Plain, Context and Verbose.
406 387
407 388 If called without arguments, acts as a toggle."""
408 389
409 390 def xmode_switch_err(name):
410 391 warn('Error changing %s exception modes.\n%s' %
411 392 (name,sys.exc_info()[1]))
412 393
413 394 shell = self.shell
414 395 new_mode = parameter_s.strip().capitalize()
415 396 try:
416 397 shell.InteractiveTB.set_mode(mode=new_mode)
417 398 print('Exception reporting mode:',shell.InteractiveTB.mode)
418 399 except:
419 400 xmode_switch_err('user')
420 401
421 402 @line_magic
422 403 def quickref(self,arg):
423 404 """ Show a quick reference sheet """
424 405 from IPython.core.usage import quick_reference
425 406 qr = quick_reference + self._magic_docs(brief=True)
426 407 page.page(qr)
427 408
428 409 @line_magic
429 410 def doctest_mode(self, parameter_s=''):
430 411 """Toggle doctest mode on and off.
431 412
432 413 This mode is intended to make IPython behave as much as possible like a
433 414 plain Python shell, from the perspective of how its prompts, exceptions
434 415 and output look. This makes it easy to copy and paste parts of a
435 416 session into doctests. It does so by:
436 417
437 418 - Changing the prompts to the classic ``>>>`` ones.
438 419 - Changing the exception reporting mode to 'Plain'.
439 420 - Disabling pretty-printing of output.
440 421
441 422 Note that IPython also supports the pasting of code snippets that have
442 423 leading '>>>' and '...' prompts in them. This means that you can paste
443 424 doctests from files or docstrings (even if they have leading
444 425 whitespace), and the code will execute correctly. You can then use
445 426 '%history -t' to see the translated history; this will give you the
446 427 input after removal of all the leading prompts and whitespace, which
447 428 can be pasted back into an editor.
448 429
449 430 With these features, you can switch into this mode easily whenever you
450 431 need to do testing and changes to doctests, without having to leave
451 432 your existing IPython session.
452 433 """
453 434
454 435 # Shorthands
455 436 shell = self.shell
456 437 pm = shell.prompt_manager
457 438 meta = shell.meta
458 439 disp_formatter = self.shell.display_formatter
459 440 ptformatter = disp_formatter.formatters['text/plain']
460 441 # dstore is a data store kept in the instance metadata bag to track any
461 442 # changes we make, so we can undo them later.
462 443 dstore = meta.setdefault('doctest_mode',Struct())
463 444 save_dstore = dstore.setdefault
464 445
465 446 # save a few values we'll need to recover later
466 447 mode = save_dstore('mode',False)
467 448 save_dstore('rc_pprint',ptformatter.pprint)
468 449 save_dstore('xmode',shell.InteractiveTB.mode)
469 450 save_dstore('rc_separate_out',shell.separate_out)
470 451 save_dstore('rc_separate_out2',shell.separate_out2)
471 452 save_dstore('rc_prompts_pad_left',pm.justify)
472 453 save_dstore('rc_separate_in',shell.separate_in)
473 454 save_dstore('rc_active_types',disp_formatter.active_types)
474 455 save_dstore('prompt_templates',(pm.in_template, pm.in2_template, pm.out_template))
475 456
476 457 if mode == False:
477 458 # turn on
478 459 pm.in_template = '>>> '
479 460 pm.in2_template = '... '
480 461 pm.out_template = ''
481 462
482 463 # Prompt separators like plain python
483 464 shell.separate_in = ''
484 465 shell.separate_out = ''
485 466 shell.separate_out2 = ''
486 467
487 468 pm.justify = False
488 469
489 470 ptformatter.pprint = False
490 471 disp_formatter.active_types = ['text/plain']
491 472
492 473 shell.magic('xmode Plain')
493 474 else:
494 475 # turn off
495 476 pm.in_template, pm.in2_template, pm.out_template = dstore.prompt_templates
496 477
497 478 shell.separate_in = dstore.rc_separate_in
498 479
499 480 shell.separate_out = dstore.rc_separate_out
500 481 shell.separate_out2 = dstore.rc_separate_out2
501 482
502 483 pm.justify = dstore.rc_prompts_pad_left
503 484
504 485 ptformatter.pprint = dstore.rc_pprint
505 486 disp_formatter.active_types = dstore.rc_active_types
506 487
507 488 shell.magic('xmode ' + dstore.xmode)
508 489
509 490 # Store new mode and inform
510 491 dstore.mode = bool(1-int(mode))
511 492 mode_label = ['OFF','ON'][dstore.mode]
512 493 print('Doctest mode is:', mode_label)
513 494
514 495 @line_magic
515 496 def gui(self, parameter_s=''):
516 497 """Enable or disable IPython GUI event loop integration.
517 498
518 499 %gui [GUINAME]
519 500
520 501 This magic replaces IPython's threaded shells that were activated
521 502 using the (pylab/wthread/etc.) command line flags. GUI toolkits
522 503 can now be enabled at runtime and keyboard
523 504 interrupts should work without any problems. The following toolkits
524 505 are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX)::
525 506
526 507 %gui wx # enable wxPython event loop integration
527 508 %gui qt4|qt # enable PyQt4 event loop integration
528 509 %gui qt5 # enable PyQt5 event loop integration
529 510 %gui gtk # enable PyGTK event loop integration
530 511 %gui gtk3 # enable Gtk3 event loop integration
531 512 %gui tk # enable Tk event loop integration
532 513 %gui osx # enable Cocoa event loop integration
533 514 # (requires %matplotlib 1.1)
534 515 %gui # disable all event loop integration
535 516
536 517 WARNING: after any of these has been called you can simply create
537 518 an application object, but DO NOT start the event loop yourself, as
538 519 we have already handled that.
539 520 """
540 521 opts, arg = self.parse_options(parameter_s, '')
541 522 if arg=='': arg = None
542 523 try:
543 524 return self.shell.enable_gui(arg)
544 525 except Exception as e:
545 526 # print simple error message, rather than traceback if we can't
546 527 # hook up the GUI
547 528 error(str(e))
548 529
549 530 @skip_doctest
550 531 @line_magic
551 532 def precision(self, s=''):
552 533 """Set floating point precision for pretty printing.
553 534
554 535 Can set either integer precision or a format string.
555 536
556 537 If numpy has been imported and precision is an int,
557 538 numpy display precision will also be set, via ``numpy.set_printoptions``.
558 539
559 540 If no argument is given, defaults will be restored.
560 541
561 542 Examples
562 543 --------
563 544 ::
564 545
565 546 In [1]: from math import pi
566 547
567 548 In [2]: %precision 3
568 549 Out[2]: u'%.3f'
569 550
570 551 In [3]: pi
571 552 Out[3]: 3.142
572 553
573 554 In [4]: %precision %i
574 555 Out[4]: u'%i'
575 556
576 557 In [5]: pi
577 558 Out[5]: 3
578 559
579 560 In [6]: %precision %e
580 561 Out[6]: u'%e'
581 562
582 563 In [7]: pi**10
583 564 Out[7]: 9.364805e+04
584 565
585 566 In [8]: %precision
586 567 Out[8]: u'%r'
587 568
588 569 In [9]: pi**10
589 570 Out[9]: 93648.047476082982
590 571 """
591 572 ptformatter = self.shell.display_formatter.formatters['text/plain']
592 573 ptformatter.float_precision = s
593 574 return ptformatter.float_format
594 575
595 576 @magic_arguments.magic_arguments()
596 577 @magic_arguments.argument(
597 578 '-e', '--export', action='store_true', default=False,
598 579 help='Export IPython history as a notebook. The filename argument '
599 580 'is used to specify the notebook name and format. For example '
600 581 'a filename of notebook.ipynb will result in a notebook name '
601 582 'of "notebook" and a format of "json". Likewise using a ".py" '
602 583 'file extension will write the notebook as a Python script'
603 584 )
604 585 @magic_arguments.argument(
605 '-f', '--format',
606 help='Convert an existing IPython notebook to a new format. This option '
607 'specifies the new format and can have the values: json, py. '
608 'The target filename is chosen automatically based on the new '
609 'format. The filename argument gives the name of the source file.'
610 )
611 @magic_arguments.argument(
612 586 'filename', type=unicode_type,
613 587 help='Notebook name or filename'
614 588 )
615 589 @line_magic
616 590 def notebook(self, s):
617 591 """Export and convert IPython notebooks.
618 592
619 This function can export the current IPython history to a notebook file
620 or can convert an existing notebook file into a different format. For
621 example, to export the history to "foo.ipynb" do "%notebook -e foo.ipynb".
622 To export the history to "foo.py" do "%notebook -e foo.py". To convert
623 "foo.ipynb" to "foo.json" do "%notebook -f json foo.ipynb". Possible
624 formats include (json/ipynb, py).
593 This function can export the current IPython history to a notebook file.
594 For example, to export the history to "foo.ipynb" do "%notebook -e foo.ipynb".
595 To export the history to "foo.py" do "%notebook -e foo.py".
625 596 """
626 597 args = magic_arguments.parse_argstring(self.notebook, s)
627 598
628 from IPython.nbformat import current
599 from IPython.nbformat import write, v4
629 600 args.filename = unquote_filename(args.filename)
630 601 if args.export:
631 fname, name, format = current.parse_filename(args.filename)
632 602 cells = []
633 603 hist = list(self.shell.history_manager.get_range())
634 for session, prompt_number, input in hist[:-1]:
635 cells.append(current.new_code_cell(prompt_number=prompt_number,
636 input=input))
637 worksheet = current.new_worksheet(cells=cells)
638 nb = current.new_notebook(name=name,worksheets=[worksheet])
639 with io.open(fname, 'w', encoding='utf-8') as f:
640 current.write(nb, f, format);
641 elif args.format is not None:
642 old_fname, old_name, old_format = current.parse_filename(args.filename)
643 new_format = args.format
644 if new_format == u'xml':
645 raise ValueError('Notebooks cannot be written as xml.')
646 elif new_format == u'ipynb' or new_format == u'json':
647 new_fname = old_name + u'.ipynb'
648 new_format = u'json'
649 elif new_format == u'py':
650 new_fname = old_name + u'.py'
651 else:
652 raise ValueError('Invalid notebook format: %s' % new_format)
653 with io.open(old_fname, 'r', encoding='utf-8') as f:
654 nb = current.read(f, old_format)
655 with io.open(new_fname, 'w', encoding='utf-8') as f:
656 current.write(nb, f, new_format)
604 for session, execution_count, input in hist[:-1]:
605 cells.append(v4.new_code_cell(
606 execution_count=execution_count,
607 source=source
608 ))
609 nb = v4.new_notebook(cells=cells)
610 with io.open(args.filename, 'w', encoding='utf-8') as f:
611 write(nb, f, version=4)
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file, binary diff hidden
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from IPython/html/static/notebook/js/notificationwidget.js to IPython/html/static/base/js/notificationwidget.js
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from IPython/html/static/services/kernels/js/comm.js to IPython/html/static/services/kernels/comm.js
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from IPython/html/fabfile.py to IPython/html/tasks.py
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from IPython/nbformat/convert.py to IPython/nbformat/converter.py
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from IPython/nbformat/v4/v4.withref.json to IPython/nbformat/v3/nbformat.v3.schema.json
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now