##// END OF EJS Templates
Format code
gousaiyang -
Show More

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

@@ -1,490 +1,490 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 An application for IPython.
3 An application for IPython.
4
4
5 All top-level applications should use the classes in this module for
5 All top-level applications should use the classes in this module for
6 handling configuration and creating configurables.
6 handling configuration and creating configurables.
7
7
8 The job of an :class:`Application` is to create the master configuration
8 The job of an :class:`Application` is to create the master configuration
9 object and then create the configurable objects, passing the config to them.
9 object and then create the configurable objects, passing the config to them.
10 """
10 """
11
11
12 # Copyright (c) IPython Development Team.
12 # Copyright (c) IPython Development Team.
13 # Distributed under the terms of the Modified BSD License.
13 # Distributed under the terms of the Modified BSD License.
14
14
15 import atexit
15 import atexit
16 from copy import deepcopy
16 from copy import deepcopy
17 import glob
17 import glob
18 import logging
18 import logging
19 import os
19 import os
20 import shutil
20 import shutil
21 import sys
21 import sys
22
22
23 from pathlib import Path
23 from pathlib import Path
24
24
25 from traitlets.config.application import Application, catch_config_error
25 from traitlets.config.application import Application, catch_config_error
26 from traitlets.config.loader import ConfigFileNotFound, PyFileConfigLoader
26 from traitlets.config.loader import ConfigFileNotFound, PyFileConfigLoader
27 from IPython.core import release, crashhandler
27 from IPython.core import release, crashhandler
28 from IPython.core.profiledir import ProfileDir, ProfileDirError
28 from IPython.core.profiledir import ProfileDir, ProfileDirError
29 from IPython.paths import get_ipython_dir, get_ipython_package_dir
29 from IPython.paths import get_ipython_dir, get_ipython_package_dir
30 from IPython.utils.path import ensure_dir_exists
30 from IPython.utils.path import ensure_dir_exists
31 from traitlets import (
31 from traitlets import (
32 List, Unicode, Type, Bool, Set, Instance, Undefined,
32 List, Unicode, Type, Bool, Set, Instance, Undefined,
33 default, observe,
33 default, observe,
34 )
34 )
35
35
36 if os.name == "nt":
36 if os.name == "nt":
37 programdata = os.environ.get("PROGRAMDATA", None)
37 programdata = os.environ.get("PROGRAMDATA", None)
38 if programdata is not None:
38 if programdata is not None:
39 SYSTEM_CONFIG_DIRS = [str(Path(programdata) / "ipython")]
39 SYSTEM_CONFIG_DIRS = [str(Path(programdata) / "ipython")]
40 else: # PROGRAMDATA is not defined by default on XP.
40 else: # PROGRAMDATA is not defined by default on XP.
41 SYSTEM_CONFIG_DIRS = []
41 SYSTEM_CONFIG_DIRS = []
42 else:
42 else:
43 SYSTEM_CONFIG_DIRS = [
43 SYSTEM_CONFIG_DIRS = [
44 "/usr/local/etc/ipython",
44 "/usr/local/etc/ipython",
45 "/etc/ipython",
45 "/etc/ipython",
46 ]
46 ]
47
47
48
48
49 ENV_CONFIG_DIRS = []
49 ENV_CONFIG_DIRS = []
50 _env_config_dir = os.path.join(sys.prefix, 'etc', 'ipython')
50 _env_config_dir = os.path.join(sys.prefix, 'etc', 'ipython')
51 if _env_config_dir not in SYSTEM_CONFIG_DIRS:
51 if _env_config_dir not in SYSTEM_CONFIG_DIRS:
52 # only add ENV_CONFIG if sys.prefix is not already included
52 # only add ENV_CONFIG if sys.prefix is not already included
53 ENV_CONFIG_DIRS.append(_env_config_dir)
53 ENV_CONFIG_DIRS.append(_env_config_dir)
54
54
55
55
56 _envvar = os.environ.get('IPYTHON_SUPPRESS_CONFIG_ERRORS')
56 _envvar = os.environ.get('IPYTHON_SUPPRESS_CONFIG_ERRORS')
57 if _envvar in {None, ''}:
57 if _envvar in {None, ''}:
58 IPYTHON_SUPPRESS_CONFIG_ERRORS = None
58 IPYTHON_SUPPRESS_CONFIG_ERRORS = None
59 else:
59 else:
60 if _envvar.lower() in {'1','true'}:
60 if _envvar.lower() in {'1','true'}:
61 IPYTHON_SUPPRESS_CONFIG_ERRORS = True
61 IPYTHON_SUPPRESS_CONFIG_ERRORS = True
62 elif _envvar.lower() in {'0','false'} :
62 elif _envvar.lower() in {'0','false'} :
63 IPYTHON_SUPPRESS_CONFIG_ERRORS = False
63 IPYTHON_SUPPRESS_CONFIG_ERRORS = False
64 else:
64 else:
65 sys.exit("Unsupported value for environment variable: 'IPYTHON_SUPPRESS_CONFIG_ERRORS' is set to '%s' which is none of {'0', '1', 'false', 'true', ''}."% _envvar )
65 sys.exit("Unsupported value for environment variable: 'IPYTHON_SUPPRESS_CONFIG_ERRORS' is set to '%s' which is none of {'0', '1', 'false', 'true', ''}."% _envvar )
66
66
67 # aliases and flags
67 # aliases and flags
68
68
69 base_aliases = {}
69 base_aliases = {}
70 if isinstance(Application.aliases, dict):
70 if isinstance(Application.aliases, dict):
71 # traitlets 5
71 # traitlets 5
72 base_aliases.update(Application.aliases)
72 base_aliases.update(Application.aliases)
73 base_aliases.update(
73 base_aliases.update(
74 {
74 {
75 "profile-dir": "ProfileDir.location",
75 "profile-dir": "ProfileDir.location",
76 "profile": "BaseIPythonApplication.profile",
76 "profile": "BaseIPythonApplication.profile",
77 "ipython-dir": "BaseIPythonApplication.ipython_dir",
77 "ipython-dir": "BaseIPythonApplication.ipython_dir",
78 "log-level": "Application.log_level",
78 "log-level": "Application.log_level",
79 "config": "BaseIPythonApplication.extra_config_file",
79 "config": "BaseIPythonApplication.extra_config_file",
80 }
80 }
81 )
81 )
82
82
83 base_flags = dict()
83 base_flags = dict()
84 if isinstance(Application.flags, dict):
84 if isinstance(Application.flags, dict):
85 # traitlets 5
85 # traitlets 5
86 base_flags.update(Application.flags)
86 base_flags.update(Application.flags)
87 base_flags.update(
87 base_flags.update(
88 dict(
88 dict(
89 debug=(
89 debug=(
90 {"Application": {"log_level": logging.DEBUG}},
90 {"Application": {"log_level": logging.DEBUG}},
91 "set log level to logging.DEBUG (maximize logging output)",
91 "set log level to logging.DEBUG (maximize logging output)",
92 ),
92 ),
93 quiet=(
93 quiet=(
94 {"Application": {"log_level": logging.CRITICAL}},
94 {"Application": {"log_level": logging.CRITICAL}},
95 "set log level to logging.CRITICAL (minimize logging output)",
95 "set log level to logging.CRITICAL (minimize logging output)",
96 ),
96 ),
97 init=(
97 init=(
98 {
98 {
99 "BaseIPythonApplication": {
99 "BaseIPythonApplication": {
100 "copy_config_files": True,
100 "copy_config_files": True,
101 "auto_create": True,
101 "auto_create": True,
102 }
102 }
103 },
103 },
104 """Initialize profile with default config files. This is equivalent
104 """Initialize profile with default config files. This is equivalent
105 to running `ipython profile create <profile>` prior to startup.
105 to running `ipython profile create <profile>` prior to startup.
106 """,
106 """,
107 ),
107 ),
108 )
108 )
109 )
109 )
110
110
111
111
112 class ProfileAwareConfigLoader(PyFileConfigLoader):
112 class ProfileAwareConfigLoader(PyFileConfigLoader):
113 """A Python file config loader that is aware of IPython profiles."""
113 """A Python file config loader that is aware of IPython profiles."""
114 def load_subconfig(self, fname, path=None, profile=None):
114 def load_subconfig(self, fname, path=None, profile=None):
115 if profile is not None:
115 if profile is not None:
116 try:
116 try:
117 profile_dir = ProfileDir.find_profile_dir_by_name(
117 profile_dir = ProfileDir.find_profile_dir_by_name(
118 get_ipython_dir(),
118 get_ipython_dir(),
119 profile,
119 profile,
120 )
120 )
121 except ProfileDirError:
121 except ProfileDirError:
122 return
122 return
123 path = profile_dir.location
123 path = profile_dir.location
124 return super(ProfileAwareConfigLoader, self).load_subconfig(fname, path=path)
124 return super(ProfileAwareConfigLoader, self).load_subconfig(fname, path=path)
125
125
126 class BaseIPythonApplication(Application):
126 class BaseIPythonApplication(Application):
127
127
128 name = u'ipython'
128 name = u'ipython'
129 description = Unicode(u'IPython: an enhanced interactive Python shell.')
129 description = Unicode(u'IPython: an enhanced interactive Python shell.')
130 version = Unicode(release.version)
130 version = Unicode(release.version)
131
131
132 aliases = base_aliases
132 aliases = base_aliases
133 flags = base_flags
133 flags = base_flags
134 classes = List([ProfileDir])
134 classes = List([ProfileDir])
135
135
136 # enable `load_subconfig('cfg.py', profile='name')`
136 # enable `load_subconfig('cfg.py', profile='name')`
137 python_config_loader_class = ProfileAwareConfigLoader
137 python_config_loader_class = ProfileAwareConfigLoader
138
138
139 # Track whether the config_file has changed,
139 # Track whether the config_file has changed,
140 # because some logic happens only if we aren't using the default.
140 # because some logic happens only if we aren't using the default.
141 config_file_specified = Set()
141 config_file_specified = Set()
142
142
143 config_file_name = Unicode()
143 config_file_name = Unicode()
144 @default('config_file_name')
144 @default('config_file_name')
145 def _config_file_name_default(self):
145 def _config_file_name_default(self):
146 return self.name.replace('-','_') + u'_config.py'
146 return self.name.replace('-','_') + u'_config.py'
147 @observe('config_file_name')
147 @observe('config_file_name')
148 def _config_file_name_changed(self, change):
148 def _config_file_name_changed(self, change):
149 if change['new'] != change['old']:
149 if change['new'] != change['old']:
150 self.config_file_specified.add(change['new'])
150 self.config_file_specified.add(change['new'])
151
151
152 # The directory that contains IPython's builtin profiles.
152 # The directory that contains IPython's builtin profiles.
153 builtin_profile_dir = Unicode(
153 builtin_profile_dir = Unicode(
154 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
154 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
155 )
155 )
156
156
157 config_file_paths = List(Unicode())
157 config_file_paths = List(Unicode())
158 @default('config_file_paths')
158 @default('config_file_paths')
159 def _config_file_paths_default(self):
159 def _config_file_paths_default(self):
160 return []
160 return []
161
161
162 extra_config_file = Unicode(
162 extra_config_file = Unicode(
163 help="""Path to an extra config file to load.
163 help="""Path to an extra config file to load.
164
164
165 If specified, load this config file in addition to any other IPython config.
165 If specified, load this config file in addition to any other IPython config.
166 """).tag(config=True)
166 """).tag(config=True)
167 @observe('extra_config_file')
167 @observe('extra_config_file')
168 def _extra_config_file_changed(self, change):
168 def _extra_config_file_changed(self, change):
169 old = change['old']
169 old = change['old']
170 new = change['new']
170 new = change['new']
171 try:
171 try:
172 self.config_files.remove(old)
172 self.config_files.remove(old)
173 except ValueError:
173 except ValueError:
174 pass
174 pass
175 self.config_file_specified.add(new)
175 self.config_file_specified.add(new)
176 self.config_files.append(new)
176 self.config_files.append(new)
177
177
178 profile = Unicode(u'default',
178 profile = Unicode(u'default',
179 help="""The IPython profile to use."""
179 help="""The IPython profile to use."""
180 ).tag(config=True)
180 ).tag(config=True)
181
181
182 @observe('profile')
182 @observe('profile')
183 def _profile_changed(self, change):
183 def _profile_changed(self, change):
184 self.builtin_profile_dir = os.path.join(
184 self.builtin_profile_dir = os.path.join(
185 get_ipython_package_dir(), u'config', u'profile', change['new']
185 get_ipython_package_dir(), u'config', u'profile', change['new']
186 )
186 )
187
187
188 add_ipython_dir_to_sys_path = Bool(
188 add_ipython_dir_to_sys_path = Bool(
189 False,
189 False,
190 """Should the IPython profile directory be added to sys path ?
190 """Should the IPython profile directory be added to sys path ?
191
191
192 This option was non-existing before IPython 8.0, and ipython_dir was added to
192 This option was non-existing before IPython 8.0, and ipython_dir was added to
193 sys path to allow import of extensions present there. This was historical
193 sys path to allow import of extensions present there. This was historical
194 baggage from when pip did not exist. This now default to false,
194 baggage from when pip did not exist. This now default to false,
195 but can be set to true for legacy reasons.
195 but can be set to true for legacy reasons.
196 """,
196 """,
197 ).tag(config=True)
197 ).tag(config=True)
198
198
199 ipython_dir = Unicode(
199 ipython_dir = Unicode(
200 help="""
200 help="""
201 The name of the IPython directory. This directory is used for logging
201 The name of the IPython directory. This directory is used for logging
202 configuration (through profiles), history storage, etc. The default
202 configuration (through profiles), history storage, etc. The default
203 is usually $HOME/.ipython. This option can also be specified through
203 is usually $HOME/.ipython. This option can also be specified through
204 the environment variable IPYTHONDIR.
204 the environment variable IPYTHONDIR.
205 """
205 """
206 ).tag(config=True)
206 ).tag(config=True)
207 @default('ipython_dir')
207 @default('ipython_dir')
208 def _ipython_dir_default(self):
208 def _ipython_dir_default(self):
209 d = get_ipython_dir()
209 d = get_ipython_dir()
210 self._ipython_dir_changed({
210 self._ipython_dir_changed({
211 'name': 'ipython_dir',
211 'name': 'ipython_dir',
212 'old': d,
212 'old': d,
213 'new': d,
213 'new': d,
214 })
214 })
215 return d
215 return d
216
216
217 _in_init_profile_dir = False
217 _in_init_profile_dir = False
218 profile_dir = Instance(ProfileDir, allow_none=True)
218 profile_dir = Instance(ProfileDir, allow_none=True)
219 @default('profile_dir')
219 @default('profile_dir')
220 def _profile_dir_default(self):
220 def _profile_dir_default(self):
221 # avoid recursion
221 # avoid recursion
222 if self._in_init_profile_dir:
222 if self._in_init_profile_dir:
223 return
223 return
224 # profile_dir requested early, force initialization
224 # profile_dir requested early, force initialization
225 self.init_profile_dir()
225 self.init_profile_dir()
226 return self.profile_dir
226 return self.profile_dir
227
227
228 overwrite = Bool(False,
228 overwrite = Bool(False,
229 help="""Whether to overwrite existing config files when copying"""
229 help="""Whether to overwrite existing config files when copying"""
230 ).tag(config=True)
230 ).tag(config=True)
231 auto_create = Bool(False,
231 auto_create = Bool(False,
232 help="""Whether to create profile dir if it doesn't exist"""
232 help="""Whether to create profile dir if it doesn't exist"""
233 ).tag(config=True)
233 ).tag(config=True)
234
234
235 config_files = List(Unicode())
235 config_files = List(Unicode())
236 @default('config_files')
236 @default('config_files')
237 def _config_files_default(self):
237 def _config_files_default(self):
238 return [self.config_file_name]
238 return [self.config_file_name]
239
239
240 copy_config_files = Bool(False,
240 copy_config_files = Bool(False,
241 help="""Whether to install the default config files into the profile dir.
241 help="""Whether to install the default config files into the profile dir.
242 If a new profile is being created, and IPython contains config files for that
242 If a new profile is being created, and IPython contains config files for that
243 profile, then they will be staged into the new directory. Otherwise,
243 profile, then they will be staged into the new directory. Otherwise,
244 default config files will be automatically generated.
244 default config files will be automatically generated.
245 """).tag(config=True)
245 """).tag(config=True)
246
246
247 verbose_crash = Bool(False,
247 verbose_crash = Bool(False,
248 help="""Create a massive crash report when IPython encounters what may be an
248 help="""Create a massive crash report when IPython encounters what may be an
249 internal error. The default is to append a short message to the
249 internal error. The default is to append a short message to the
250 usual traceback""").tag(config=True)
250 usual traceback""").tag(config=True)
251
251
252 # The class to use as the crash handler.
252 # The class to use as the crash handler.
253 crash_handler_class = Type(crashhandler.CrashHandler)
253 crash_handler_class = Type(crashhandler.CrashHandler)
254
254
255 @catch_config_error
255 @catch_config_error
256 def __init__(self, **kwargs):
256 def __init__(self, **kwargs):
257 super(BaseIPythonApplication, self).__init__(**kwargs)
257 super(BaseIPythonApplication, self).__init__(**kwargs)
258 # ensure current working directory exists
258 # ensure current working directory exists
259 try:
259 try:
260 os.getcwd()
260 os.getcwd()
261 except:
261 except:
262 # exit if cwd doesn't exist
262 # exit if cwd doesn't exist
263 self.log.error("Current working directory doesn't exist.")
263 self.log.error("Current working directory doesn't exist.")
264 self.exit(1)
264 self.exit(1)
265
265
266 #-------------------------------------------------------------------------
266 #-------------------------------------------------------------------------
267 # Various stages of Application creation
267 # Various stages of Application creation
268 #-------------------------------------------------------------------------
268 #-------------------------------------------------------------------------
269
269
270 def init_crash_handler(self):
270 def init_crash_handler(self):
271 """Create a crash handler, typically setting sys.excepthook to it."""
271 """Create a crash handler, typically setting sys.excepthook to it."""
272 self.crash_handler = self.crash_handler_class(self)
272 self.crash_handler = self.crash_handler_class(self)
273 sys.excepthook = self.excepthook
273 sys.excepthook = self.excepthook
274 def unset_crashhandler():
274 def unset_crashhandler():
275 sys.excepthook = sys.__excepthook__
275 sys.excepthook = sys.__excepthook__
276 atexit.register(unset_crashhandler)
276 atexit.register(unset_crashhandler)
277
277
278 def excepthook(self, etype, evalue, tb):
278 def excepthook(self, etype, evalue, tb):
279 """this is sys.excepthook after init_crashhandler
279 """this is sys.excepthook after init_crashhandler
280
280
281 set self.verbose_crash=True to use our full crashhandler, instead of
281 set self.verbose_crash=True to use our full crashhandler, instead of
282 a regular traceback with a short message (crash_handler_lite)
282 a regular traceback with a short message (crash_handler_lite)
283 """
283 """
284
284
285 if self.verbose_crash:
285 if self.verbose_crash:
286 return self.crash_handler(etype, evalue, tb)
286 return self.crash_handler(etype, evalue, tb)
287 else:
287 else:
288 return crashhandler.crash_handler_lite(etype, evalue, tb)
288 return crashhandler.crash_handler_lite(etype, evalue, tb)
289
289
290 @observe('ipython_dir')
290 @observe('ipython_dir')
291 def _ipython_dir_changed(self, change):
291 def _ipython_dir_changed(self, change):
292 old = change['old']
292 old = change['old']
293 new = change['new']
293 new = change['new']
294 if old is not Undefined:
294 if old is not Undefined:
295 str_old = os.path.abspath(old)
295 str_old = os.path.abspath(old)
296 if str_old in sys.path:
296 if str_old in sys.path:
297 sys.path.remove(str_old)
297 sys.path.remove(str_old)
298 if self.add_ipython_dir_to_sys_path:
298 if self.add_ipython_dir_to_sys_path:
299 str_path = os.path.abspath(new)
299 str_path = os.path.abspath(new)
300 sys.path.append(str_path)
300 sys.path.append(str_path)
301 ensure_dir_exists(new)
301 ensure_dir_exists(new)
302 readme = os.path.join(new, "README")
302 readme = os.path.join(new, "README")
303 readme_src = os.path.join(
303 readme_src = os.path.join(
304 get_ipython_package_dir(), "config", "profile", "README"
304 get_ipython_package_dir(), "config", "profile", "README"
305 )
305 )
306 if not os.path.exists(readme) and os.path.exists(readme_src):
306 if not os.path.exists(readme) and os.path.exists(readme_src):
307 shutil.copy(readme_src, readme)
307 shutil.copy(readme_src, readme)
308 for d in ("extensions", "nbextensions"):
308 for d in ("extensions", "nbextensions"):
309 path = os.path.join(new, d)
309 path = os.path.join(new, d)
310 try:
310 try:
311 ensure_dir_exists(path)
311 ensure_dir_exists(path)
312 except OSError as e:
312 except OSError as e:
313 # this will not be EEXIST
313 # this will not be EEXIST
314 self.log.error("couldn't create path %s: %s", path, e)
314 self.log.error("couldn't create path %s: %s", path, e)
315 self.log.debug("IPYTHONDIR set to: %s" % new)
315 self.log.debug("IPYTHONDIR set to: %s" % new)
316
316
317 def load_config_file(self, suppress_errors=IPYTHON_SUPPRESS_CONFIG_ERRORS):
317 def load_config_file(self, suppress_errors=IPYTHON_SUPPRESS_CONFIG_ERRORS):
318 """Load the config file.
318 """Load the config file.
319
319
320 By default, errors in loading config are handled, and a warning
320 By default, errors in loading config are handled, and a warning
321 printed on screen. For testing, the suppress_errors option is set
321 printed on screen. For testing, the suppress_errors option is set
322 to False, so errors will make tests fail.
322 to False, so errors will make tests fail.
323
323
324 `suppress_errors` default value is to be `None` in which case the
324 `suppress_errors` default value is to be `None` in which case the
325 behavior default to the one of `traitlets.Application`.
325 behavior default to the one of `traitlets.Application`.
326
326
327 The default value can be set :
327 The default value can be set :
328 - to `False` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '0', or 'false' (case insensitive).
328 - to `False` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '0', or 'false' (case insensitive).
329 - to `True` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '1' or 'true' (case insensitive).
329 - to `True` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '1' or 'true' (case insensitive).
330 - to `None` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '' (empty string) or leaving it unset.
330 - to `None` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '' (empty string) or leaving it unset.
331
331
332 Any other value are invalid, and will make IPython exit with a non-zero return code.
332 Any other value are invalid, and will make IPython exit with a non-zero return code.
333 """
333 """
334
334
335
335
336 self.log.debug("Searching path %s for config files", self.config_file_paths)
336 self.log.debug("Searching path %s for config files", self.config_file_paths)
337 base_config = 'ipython_config.py'
337 base_config = 'ipython_config.py'
338 self.log.debug("Attempting to load config file: %s" %
338 self.log.debug("Attempting to load config file: %s" %
339 base_config)
339 base_config)
340 try:
340 try:
341 if suppress_errors is not None:
341 if suppress_errors is not None:
342 old_value = Application.raise_config_file_errors
342 old_value = Application.raise_config_file_errors
343 Application.raise_config_file_errors = not suppress_errors;
343 Application.raise_config_file_errors = not suppress_errors;
344 Application.load_config_file(
344 Application.load_config_file(
345 self,
345 self,
346 base_config,
346 base_config,
347 path=self.config_file_paths
347 path=self.config_file_paths
348 )
348 )
349 except ConfigFileNotFound:
349 except ConfigFileNotFound:
350 # ignore errors loading parent
350 # ignore errors loading parent
351 self.log.debug("Config file %s not found", base_config)
351 self.log.debug("Config file %s not found", base_config)
352 pass
352 pass
353 if suppress_errors is not None:
353 if suppress_errors is not None:
354 Application.raise_config_file_errors = old_value
354 Application.raise_config_file_errors = old_value
355
355
356 for config_file_name in self.config_files:
356 for config_file_name in self.config_files:
357 if not config_file_name or config_file_name == base_config:
357 if not config_file_name or config_file_name == base_config:
358 continue
358 continue
359 self.log.debug("Attempting to load config file: %s" %
359 self.log.debug("Attempting to load config file: %s" %
360 self.config_file_name)
360 self.config_file_name)
361 try:
361 try:
362 Application.load_config_file(
362 Application.load_config_file(
363 self,
363 self,
364 config_file_name,
364 config_file_name,
365 path=self.config_file_paths
365 path=self.config_file_paths
366 )
366 )
367 except ConfigFileNotFound:
367 except ConfigFileNotFound:
368 # Only warn if the default config file was NOT being used.
368 # Only warn if the default config file was NOT being used.
369 if config_file_name in self.config_file_specified:
369 if config_file_name in self.config_file_specified:
370 msg = self.log.warning
370 msg = self.log.warning
371 else:
371 else:
372 msg = self.log.debug
372 msg = self.log.debug
373 msg("Config file not found, skipping: %s", config_file_name)
373 msg("Config file not found, skipping: %s", config_file_name)
374 except Exception:
374 except Exception:
375 # For testing purposes.
375 # For testing purposes.
376 if not suppress_errors:
376 if not suppress_errors:
377 raise
377 raise
378 self.log.warning("Error loading config file: %s" %
378 self.log.warning("Error loading config file: %s" %
379 self.config_file_name, exc_info=True)
379 self.config_file_name, exc_info=True)
380
380
381 def init_profile_dir(self):
381 def init_profile_dir(self):
382 """initialize the profile dir"""
382 """initialize the profile dir"""
383 self._in_init_profile_dir = True
383 self._in_init_profile_dir = True
384 if self.profile_dir is not None:
384 if self.profile_dir is not None:
385 # already ran
385 # already ran
386 return
386 return
387 if 'ProfileDir.location' not in self.config:
387 if 'ProfileDir.location' not in self.config:
388 # location not specified, find by profile name
388 # location not specified, find by profile name
389 try:
389 try:
390 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
390 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
391 except ProfileDirError:
391 except ProfileDirError:
392 # not found, maybe create it (always create default profile)
392 # not found, maybe create it (always create default profile)
393 if self.auto_create or self.profile == 'default':
393 if self.auto_create or self.profile == 'default':
394 try:
394 try:
395 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
395 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
396 except ProfileDirError:
396 except ProfileDirError:
397 self.log.fatal("Could not create profile: %r"%self.profile)
397 self.log.fatal("Could not create profile: %r"%self.profile)
398 self.exit(1)
398 self.exit(1)
399 else:
399 else:
400 self.log.info("Created profile dir: %r"%p.location)
400 self.log.info("Created profile dir: %r"%p.location)
401 else:
401 else:
402 self.log.fatal("Profile %r not found."%self.profile)
402 self.log.fatal("Profile %r not found."%self.profile)
403 self.exit(1)
403 self.exit(1)
404 else:
404 else:
405 self.log.debug(f"Using existing profile dir: {p.location!r}")
405 self.log.debug(f"Using existing profile dir: {p.location!r}")
406 else:
406 else:
407 location = self.config.ProfileDir.location
407 location = self.config.ProfileDir.location
408 # location is fully specified
408 # location is fully specified
409 try:
409 try:
410 p = ProfileDir.find_profile_dir(location, self.config)
410 p = ProfileDir.find_profile_dir(location, self.config)
411 except ProfileDirError:
411 except ProfileDirError:
412 # not found, maybe create it
412 # not found, maybe create it
413 if self.auto_create:
413 if self.auto_create:
414 try:
414 try:
415 p = ProfileDir.create_profile_dir(location, self.config)
415 p = ProfileDir.create_profile_dir(location, self.config)
416 except ProfileDirError:
416 except ProfileDirError:
417 self.log.fatal("Could not create profile directory: %r"%location)
417 self.log.fatal("Could not create profile directory: %r"%location)
418 self.exit(1)
418 self.exit(1)
419 else:
419 else:
420 self.log.debug("Creating new profile dir: %r"%location)
420 self.log.debug("Creating new profile dir: %r"%location)
421 else:
421 else:
422 self.log.fatal("Profile directory %r not found."%location)
422 self.log.fatal("Profile directory %r not found."%location)
423 self.exit(1)
423 self.exit(1)
424 else:
424 else:
425 self.log.debug(f"Using existing profile dir: {p.location!r}")
425 self.log.debug(f"Using existing profile dir: {p.location!r}")
426 # if profile_dir is specified explicitly, set profile name
426 # if profile_dir is specified explicitly, set profile name
427 dir_name = os.path.basename(p.location)
427 dir_name = os.path.basename(p.location)
428 if dir_name.startswith('profile_'):
428 if dir_name.startswith('profile_'):
429 self.profile = dir_name[8:]
429 self.profile = dir_name[8:]
430
430
431 self.profile_dir = p
431 self.profile_dir = p
432 self.config_file_paths.append(p.location)
432 self.config_file_paths.append(p.location)
433 self._in_init_profile_dir = False
433 self._in_init_profile_dir = False
434
434
435 def init_config_files(self):
435 def init_config_files(self):
436 """[optionally] copy default config files into profile dir."""
436 """[optionally] copy default config files into profile dir."""
437 self.config_file_paths.extend(ENV_CONFIG_DIRS)
437 self.config_file_paths.extend(ENV_CONFIG_DIRS)
438 self.config_file_paths.extend(SYSTEM_CONFIG_DIRS)
438 self.config_file_paths.extend(SYSTEM_CONFIG_DIRS)
439 # copy config files
439 # copy config files
440 path = Path(self.builtin_profile_dir)
440 path = Path(self.builtin_profile_dir)
441 if self.copy_config_files:
441 if self.copy_config_files:
442 src = self.profile
442 src = self.profile
443
443
444 cfg = self.config_file_name
444 cfg = self.config_file_name
445 if path and (path / cfg).exists():
445 if path and (path / cfg).exists():
446 self.log.warning(
446 self.log.warning(
447 "Staging %r from %s into %r [overwrite=%s]"
447 "Staging %r from %s into %r [overwrite=%s]"
448 % (cfg, src, self.profile_dir.location, self.overwrite)
448 % (cfg, src, self.profile_dir.location, self.overwrite)
449 )
449 )
450 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
450 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
451 else:
451 else:
452 self.stage_default_config_file()
452 self.stage_default_config_file()
453 else:
453 else:
454 # Still stage *bundled* config files, but not generated ones
454 # Still stage *bundled* config files, but not generated ones
455 # This is necessary for `ipython profile=sympy` to load the profile
455 # This is necessary for `ipython profile=sympy` to load the profile
456 # on the first go
456 # on the first go
457 files = path.glob("*.py")
457 files = path.glob("*.py")
458 for fullpath in files:
458 for fullpath in files:
459 cfg = fullpath.name
459 cfg = fullpath.name
460 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
460 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
461 # file was copied
461 # file was copied
462 self.log.warning("Staging bundled %s from %s into %r"%(
462 self.log.warning("Staging bundled %s from %s into %r"%(
463 cfg, self.profile, self.profile_dir.location)
463 cfg, self.profile, self.profile_dir.location)
464 )
464 )
465
465
466
466
467 def stage_default_config_file(self):
467 def stage_default_config_file(self):
468 """auto generate default config file, and stage it into the profile."""
468 """auto generate default config file, and stage it into the profile."""
469 s = self.generate_config_file()
469 s = self.generate_config_file()
470 config_file = Path(self.profile_dir.location) / self.config_file_name
470 config_file = Path(self.profile_dir.location) / self.config_file_name
471 if self.overwrite or not config_file.exists():
471 if self.overwrite or not config_file.exists():
472 self.log.warning("Generating default config file: %r" % (config_file))
472 self.log.warning("Generating default config file: %r" % (config_file))
473 config_file.write_text(s, encoding='utf-8')
473 config_file.write_text(s, encoding="utf-8")
474
474
475 @catch_config_error
475 @catch_config_error
476 def initialize(self, argv=None):
476 def initialize(self, argv=None):
477 # don't hook up crash handler before parsing command-line
477 # don't hook up crash handler before parsing command-line
478 self.parse_command_line(argv)
478 self.parse_command_line(argv)
479 self.init_crash_handler()
479 self.init_crash_handler()
480 if self.subapp is not None:
480 if self.subapp is not None:
481 # stop here if subapp is taking over
481 # stop here if subapp is taking over
482 return
482 return
483 # save a copy of CLI config to re-load after config files
483 # save a copy of CLI config to re-load after config files
484 # so that it has highest priority
484 # so that it has highest priority
485 cl_config = deepcopy(self.config)
485 cl_config = deepcopy(self.config)
486 self.init_profile_dir()
486 self.init_profile_dir()
487 self.init_config_files()
487 self.init_config_files()
488 self.load_config_file()
488 self.load_config_file()
489 # enforce cl-opts override configfile opts:
489 # enforce cl-opts override configfile opts:
490 self.update_config(cl_config)
490 self.update_config(cl_config)
@@ -1,237 +1,237 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
3
3
4 Authors:
4 Authors:
5
5
6 * Fernando Perez
6 * Fernando Perez
7 * Brian E. Granger
7 * Brian E. Granger
8 """
8 """
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
11 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
12 # Copyright (C) 2008-2011 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 import os
22 import os
23 import sys
23 import sys
24 import traceback
24 import traceback
25 from pprint import pformat
25 from pprint import pformat
26 from pathlib import Path
26 from pathlib import Path
27
27
28 from IPython.core import ultratb
28 from IPython.core import ultratb
29 from IPython.core.release import author_email
29 from IPython.core.release import author_email
30 from IPython.utils.sysinfo import sys_info
30 from IPython.utils.sysinfo import sys_info
31 from IPython.utils.py3compat import input
31 from IPython.utils.py3compat import input
32
32
33 from IPython.core.release import __version__ as version
33 from IPython.core.release import __version__ as version
34
34
35 from typing import Optional
35 from typing import Optional
36
36
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38 # Code
38 # Code
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40
40
41 # Template for the user message.
41 # Template for the user message.
42 _default_message_template = """\
42 _default_message_template = """\
43 Oops, {app_name} crashed. We do our best to make it stable, but...
43 Oops, {app_name} crashed. We do our best to make it stable, but...
44
44
45 A crash report was automatically generated with the following information:
45 A crash report was automatically generated with the following information:
46 - A verbatim copy of the crash traceback.
46 - A verbatim copy of the crash traceback.
47 - A copy of your input history during this session.
47 - A copy of your input history during this session.
48 - Data on your current {app_name} configuration.
48 - Data on your current {app_name} configuration.
49
49
50 It was left in the file named:
50 It was left in the file named:
51 \t'{crash_report_fname}'
51 \t'{crash_report_fname}'
52 If you can email this file to the developers, the information in it will help
52 If you can email this file to the developers, the information in it will help
53 them in understanding and correcting the problem.
53 them in understanding and correcting the problem.
54
54
55 You can mail it to: {contact_name} at {contact_email}
55 You can mail it to: {contact_name} at {contact_email}
56 with the subject '{app_name} Crash Report'.
56 with the subject '{app_name} Crash Report'.
57
57
58 If you want to do it now, the following command will work (under Unix):
58 If you want to do it now, the following command will work (under Unix):
59 mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
59 mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
60
60
61 In your email, please also include information about:
61 In your email, please also include information about:
62 - The operating system under which the crash happened: Linux, macOS, Windows,
62 - The operating system under which the crash happened: Linux, macOS, Windows,
63 other, and which exact version (for example: Ubuntu 16.04.3, macOS 10.13.2,
63 other, and which exact version (for example: Ubuntu 16.04.3, macOS 10.13.2,
64 Windows 10 Pro), and whether it is 32-bit or 64-bit;
64 Windows 10 Pro), and whether it is 32-bit or 64-bit;
65 - How {app_name} was installed: using pip or conda, from GitHub, as part of
65 - How {app_name} was installed: using pip or conda, from GitHub, as part of
66 a Docker container, or other, providing more detail if possible;
66 a Docker container, or other, providing more detail if possible;
67 - How to reproduce the crash: what exact sequence of instructions can one
67 - How to reproduce the crash: what exact sequence of instructions can one
68 input to get the same crash? Ideally, find a minimal yet complete sequence
68 input to get the same crash? Ideally, find a minimal yet complete sequence
69 of instructions that yields the crash.
69 of instructions that yields the crash.
70
70
71 To ensure accurate tracking of this issue, please file a report about it at:
71 To ensure accurate tracking of this issue, please file a report about it at:
72 {bug_tracker}
72 {bug_tracker}
73 """
73 """
74
74
75 _lite_message_template = """
75 _lite_message_template = """
76 If you suspect this is an IPython {version} bug, please report it at:
76 If you suspect this is an IPython {version} bug, please report it at:
77 https://github.com/ipython/ipython/issues
77 https://github.com/ipython/ipython/issues
78 or send an email to the mailing list at {email}
78 or send an email to the mailing list at {email}
79
79
80 You can print a more detailed traceback right now with "%tb", or use "%debug"
80 You can print a more detailed traceback right now with "%tb", or use "%debug"
81 to interactively debug it.
81 to interactively debug it.
82
82
83 Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
83 Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
84 {config}Application.verbose_crash=True
84 {config}Application.verbose_crash=True
85 """
85 """
86
86
87
87
88 class CrashHandler(object):
88 class CrashHandler(object):
89 """Customizable crash handlers for IPython applications.
89 """Customizable crash handlers for IPython applications.
90
90
91 Instances of this class provide a :meth:`__call__` method which can be
91 Instances of this class provide a :meth:`__call__` method which can be
92 used as a ``sys.excepthook``. The :meth:`__call__` signature is::
92 used as a ``sys.excepthook``. The :meth:`__call__` signature is::
93
93
94 def __call__(self, etype, evalue, etb)
94 def __call__(self, etype, evalue, etb)
95 """
95 """
96
96
97 message_template = _default_message_template
97 message_template = _default_message_template
98 section_sep = '\n\n'+'*'*75+'\n\n'
98 section_sep = '\n\n'+'*'*75+'\n\n'
99
99
100 def __init__(
100 def __init__(
101 self,
101 self,
102 app,
102 app,
103 contact_name: Optional[str] = None,
103 contact_name: Optional[str] = None,
104 contact_email: Optional[str] = None,
104 contact_email: Optional[str] = None,
105 bug_tracker: Optional[str] = None,
105 bug_tracker: Optional[str] = None,
106 show_crash_traceback: bool = True,
106 show_crash_traceback: bool = True,
107 call_pdb: bool = False,
107 call_pdb: bool = False,
108 ):
108 ):
109 """Create a new crash handler
109 """Create a new crash handler
110
110
111 Parameters
111 Parameters
112 ----------
112 ----------
113 app : Application
113 app : Application
114 A running :class:`Application` instance, which will be queried at
114 A running :class:`Application` instance, which will be queried at
115 crash time for internal information.
115 crash time for internal information.
116 contact_name : str
116 contact_name : str
117 A string with the name of the person to contact.
117 A string with the name of the person to contact.
118 contact_email : str
118 contact_email : str
119 A string with the email address of the contact.
119 A string with the email address of the contact.
120 bug_tracker : str
120 bug_tracker : str
121 A string with the URL for your project's bug tracker.
121 A string with the URL for your project's bug tracker.
122 show_crash_traceback : bool
122 show_crash_traceback : bool
123 If false, don't print the crash traceback on stderr, only generate
123 If false, don't print the crash traceback on stderr, only generate
124 the on-disk report
124 the on-disk report
125 call_pdb
125 call_pdb
126 Whether to call pdb on crash
126 Whether to call pdb on crash
127
127
128 Attributes
128 Attributes
129 ----------
129 ----------
130 These instances contain some non-argument attributes which allow for
130 These instances contain some non-argument attributes which allow for
131 further customization of the crash handler's behavior. Please see the
131 further customization of the crash handler's behavior. Please see the
132 source for further details.
132 source for further details.
133
133
134 """
134 """
135 self.crash_report_fname = "Crash_report_%s.txt" % app.name
135 self.crash_report_fname = "Crash_report_%s.txt" % app.name
136 self.app = app
136 self.app = app
137 self.call_pdb = call_pdb
137 self.call_pdb = call_pdb
138 #self.call_pdb = True # dbg
138 #self.call_pdb = True # dbg
139 self.show_crash_traceback = show_crash_traceback
139 self.show_crash_traceback = show_crash_traceback
140 self.info = dict(app_name = app.name,
140 self.info = dict(app_name = app.name,
141 contact_name = contact_name,
141 contact_name = contact_name,
142 contact_email = contact_email,
142 contact_email = contact_email,
143 bug_tracker = bug_tracker,
143 bug_tracker = bug_tracker,
144 crash_report_fname = self.crash_report_fname)
144 crash_report_fname = self.crash_report_fname)
145
145
146
146
147 def __call__(self, etype, evalue, etb):
147 def __call__(self, etype, evalue, etb):
148 """Handle an exception, call for compatible with sys.excepthook"""
148 """Handle an exception, call for compatible with sys.excepthook"""
149
149
150 # do not allow the crash handler to be called twice without reinstalling it
150 # do not allow the crash handler to be called twice without reinstalling it
151 # this prevents unlikely errors in the crash handling from entering an
151 # this prevents unlikely errors in the crash handling from entering an
152 # infinite loop.
152 # infinite loop.
153 sys.excepthook = sys.__excepthook__
153 sys.excepthook = sys.__excepthook__
154
154
155 # Report tracebacks shouldn't use color in general (safer for users)
155 # Report tracebacks shouldn't use color in general (safer for users)
156 color_scheme = 'NoColor'
156 color_scheme = 'NoColor'
157
157
158 # Use this ONLY for developer debugging (keep commented out for release)
158 # Use this ONLY for developer debugging (keep commented out for release)
159 #color_scheme = 'Linux' # dbg
159 #color_scheme = 'Linux' # dbg
160 try:
160 try:
161 rptdir = self.app.ipython_dir
161 rptdir = self.app.ipython_dir
162 except:
162 except:
163 rptdir = Path.cwd()
163 rptdir = Path.cwd()
164 if rptdir is None or not Path.is_dir(rptdir):
164 if rptdir is None or not Path.is_dir(rptdir):
165 rptdir = Path.cwd()
165 rptdir = Path.cwd()
166 report_name = rptdir / self.crash_report_fname
166 report_name = rptdir / self.crash_report_fname
167 # write the report filename into the instance dict so it can get
167 # write the report filename into the instance dict so it can get
168 # properly expanded out in the user message template
168 # properly expanded out in the user message template
169 self.crash_report_fname = report_name
169 self.crash_report_fname = report_name
170 self.info['crash_report_fname'] = report_name
170 self.info['crash_report_fname'] = report_name
171 TBhandler = ultratb.VerboseTB(
171 TBhandler = ultratb.VerboseTB(
172 color_scheme=color_scheme,
172 color_scheme=color_scheme,
173 long_header=1,
173 long_header=1,
174 call_pdb=self.call_pdb,
174 call_pdb=self.call_pdb,
175 )
175 )
176 if self.call_pdb:
176 if self.call_pdb:
177 TBhandler(etype,evalue,etb)
177 TBhandler(etype,evalue,etb)
178 return
178 return
179 else:
179 else:
180 traceback = TBhandler.text(etype,evalue,etb,context=31)
180 traceback = TBhandler.text(etype,evalue,etb,context=31)
181
181
182 # print traceback to screen
182 # print traceback to screen
183 if self.show_crash_traceback:
183 if self.show_crash_traceback:
184 print(traceback, file=sys.stderr)
184 print(traceback, file=sys.stderr)
185
185
186 # and generate a complete report on disk
186 # and generate a complete report on disk
187 try:
187 try:
188 report = open(report_name, 'w', encoding='utf-8')
188 report = open(report_name, "w", encoding="utf-8")
189 except:
189 except:
190 print('Could not create crash report on disk.', file=sys.stderr)
190 print('Could not create crash report on disk.', file=sys.stderr)
191 return
191 return
192
192
193 with report:
193 with report:
194 # Inform user on stderr of what happened
194 # Inform user on stderr of what happened
195 print('\n'+'*'*70+'\n', file=sys.stderr)
195 print('\n'+'*'*70+'\n', file=sys.stderr)
196 print(self.message_template.format(**self.info), file=sys.stderr)
196 print(self.message_template.format(**self.info), file=sys.stderr)
197
197
198 # Construct report on disk
198 # Construct report on disk
199 report.write(self.make_report(traceback))
199 report.write(self.make_report(traceback))
200
200
201 input("Hit <Enter> to quit (your terminal may close):")
201 input("Hit <Enter> to quit (your terminal may close):")
202
202
203 def make_report(self,traceback):
203 def make_report(self,traceback):
204 """Return a string containing a crash report."""
204 """Return a string containing a crash report."""
205
205
206 sec_sep = self.section_sep
206 sec_sep = self.section_sep
207
207
208 report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
208 report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
209 rpt_add = report.append
209 rpt_add = report.append
210 rpt_add(sys_info())
210 rpt_add(sys_info())
211
211
212 try:
212 try:
213 config = pformat(self.app.config)
213 config = pformat(self.app.config)
214 rpt_add(sec_sep)
214 rpt_add(sec_sep)
215 rpt_add('Application name: %s\n\n' % self.app_name)
215 rpt_add('Application name: %s\n\n' % self.app_name)
216 rpt_add('Current user configuration structure:\n\n')
216 rpt_add('Current user configuration structure:\n\n')
217 rpt_add(config)
217 rpt_add(config)
218 except:
218 except:
219 pass
219 pass
220 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
220 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
221
221
222 return ''.join(report)
222 return ''.join(report)
223
223
224
224
225 def crash_handler_lite(etype, evalue, tb):
225 def crash_handler_lite(etype, evalue, tb):
226 """a light excepthook, adding a small message to the usual traceback"""
226 """a light excepthook, adding a small message to the usual traceback"""
227 traceback.print_exception(etype, evalue, tb)
227 traceback.print_exception(etype, evalue, tb)
228
228
229 from IPython.core.interactiveshell import InteractiveShell
229 from IPython.core.interactiveshell import InteractiveShell
230 if InteractiveShell.initialized():
230 if InteractiveShell.initialized():
231 # we are in a Shell environment, give %magic example
231 # we are in a Shell environment, give %magic example
232 config = "%config "
232 config = "%config "
233 else:
233 else:
234 # we are not in a shell, show generic config
234 # we are not in a shell, show generic config
235 config = "c."
235 config = "c."
236 print(_lite_message_template.format(email=author_email, config=config, version=version), file=sys.stderr)
236 print(_lite_message_template.format(email=author_email, config=config, version=version), file=sys.stderr)
237
237
@@ -1,1274 +1,1277 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Top-level display functions for displaying object in different formats."""
2 """Top-level display functions for displaying object in different formats."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7
7
8 from binascii import b2a_base64, hexlify
8 from binascii import b2a_base64, hexlify
9 import html
9 import html
10 import json
10 import json
11 import mimetypes
11 import mimetypes
12 import os
12 import os
13 import struct
13 import struct
14 import warnings
14 import warnings
15 from copy import deepcopy
15 from copy import deepcopy
16 from os.path import splitext
16 from os.path import splitext
17 from pathlib import Path, PurePath
17 from pathlib import Path, PurePath
18
18
19 from IPython.utils.py3compat import cast_unicode
19 from IPython.utils.py3compat import cast_unicode
20 from IPython.testing.skipdoctest import skip_doctest
20 from IPython.testing.skipdoctest import skip_doctest
21 from . import display_functions
21 from . import display_functions
22
22
23
23
24 __all__ = ['display_pretty', 'display_html', 'display_markdown',
24 __all__ = ['display_pretty', 'display_html', 'display_markdown',
25 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
25 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
26 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
26 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
27 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'ProgressBar', 'JSON',
27 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'ProgressBar', 'JSON',
28 'GeoJSON', 'Javascript', 'Image', 'set_matplotlib_formats',
28 'GeoJSON', 'Javascript', 'Image', 'set_matplotlib_formats',
29 'set_matplotlib_close',
29 'set_matplotlib_close',
30 'Video']
30 'Video']
31
31
32 _deprecated_names = ["display", "clear_output", "publish_display_data", "update_display", "DisplayHandle"]
32 _deprecated_names = ["display", "clear_output", "publish_display_data", "update_display", "DisplayHandle"]
33
33
34 __all__ = __all__ + _deprecated_names
34 __all__ = __all__ + _deprecated_names
35
35
36
36
37 # ----- warn to import from IPython.display -----
37 # ----- warn to import from IPython.display -----
38
38
39 from warnings import warn
39 from warnings import warn
40
40
41
41
42 def __getattr__(name):
42 def __getattr__(name):
43 if name in _deprecated_names:
43 if name in _deprecated_names:
44 warn(f"Importing {name} from IPython.core.display is deprecated since IPython 7.14, please import from IPython display", DeprecationWarning, stacklevel=2)
44 warn(f"Importing {name} from IPython.core.display is deprecated since IPython 7.14, please import from IPython display", DeprecationWarning, stacklevel=2)
45 return getattr(display_functions, name)
45 return getattr(display_functions, name)
46
46
47 if name in globals().keys():
47 if name in globals().keys():
48 return globals()[name]
48 return globals()[name]
49 else:
49 else:
50 raise AttributeError(f"module {__name__} has no attribute {name}")
50 raise AttributeError(f"module {__name__} has no attribute {name}")
51
51
52
52
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54 # utility functions
54 # utility functions
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56
56
57 def _safe_exists(path):
57 def _safe_exists(path):
58 """Check path, but don't let exceptions raise"""
58 """Check path, but don't let exceptions raise"""
59 try:
59 try:
60 return os.path.exists(path)
60 return os.path.exists(path)
61 except Exception:
61 except Exception:
62 return False
62 return False
63
63
64
64
65 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
65 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
66 """internal implementation of all display_foo methods
66 """internal implementation of all display_foo methods
67
67
68 Parameters
68 Parameters
69 ----------
69 ----------
70 mimetype : str
70 mimetype : str
71 The mimetype to be published (e.g. 'image/png')
71 The mimetype to be published (e.g. 'image/png')
72 *objs : object
72 *objs : object
73 The Python objects to display, or if raw=True raw text data to
73 The Python objects to display, or if raw=True raw text data to
74 display.
74 display.
75 raw : bool
75 raw : bool
76 Are the data objects raw data or Python objects that need to be
76 Are the data objects raw data or Python objects that need to be
77 formatted before display? [default: False]
77 formatted before display? [default: False]
78 metadata : dict (optional)
78 metadata : dict (optional)
79 Metadata to be associated with the specific mimetype output.
79 Metadata to be associated with the specific mimetype output.
80 """
80 """
81 if metadata:
81 if metadata:
82 metadata = {mimetype: metadata}
82 metadata = {mimetype: metadata}
83 if raw:
83 if raw:
84 # turn list of pngdata into list of { 'image/png': pngdata }
84 # turn list of pngdata into list of { 'image/png': pngdata }
85 objs = [ {mimetype: obj} for obj in objs ]
85 objs = [ {mimetype: obj} for obj in objs ]
86 display_functions.display(*objs, raw=raw, metadata=metadata, include=[mimetype])
86 display_functions.display(*objs, raw=raw, metadata=metadata, include=[mimetype])
87
87
88 #-----------------------------------------------------------------------------
88 #-----------------------------------------------------------------------------
89 # Main functions
89 # Main functions
90 #-----------------------------------------------------------------------------
90 #-----------------------------------------------------------------------------
91
91
92
92
93 def display_pretty(*objs, **kwargs):
93 def display_pretty(*objs, **kwargs):
94 """Display the pretty (default) representation of an object.
94 """Display the pretty (default) representation of an object.
95
95
96 Parameters
96 Parameters
97 ----------
97 ----------
98 *objs : object
98 *objs : object
99 The Python objects to display, or if raw=True raw text data to
99 The Python objects to display, or if raw=True raw text data to
100 display.
100 display.
101 raw : bool
101 raw : bool
102 Are the data objects raw data or Python objects that need to be
102 Are the data objects raw data or Python objects that need to be
103 formatted before display? [default: False]
103 formatted before display? [default: False]
104 metadata : dict (optional)
104 metadata : dict (optional)
105 Metadata to be associated with the specific mimetype output.
105 Metadata to be associated with the specific mimetype output.
106 """
106 """
107 _display_mimetype('text/plain', objs, **kwargs)
107 _display_mimetype('text/plain', objs, **kwargs)
108
108
109
109
110 def display_html(*objs, **kwargs):
110 def display_html(*objs, **kwargs):
111 """Display the HTML representation of an object.
111 """Display the HTML representation of an object.
112
112
113 Note: If raw=False and the object does not have a HTML
113 Note: If raw=False and the object does not have a HTML
114 representation, no HTML will be shown.
114 representation, no HTML will be shown.
115
115
116 Parameters
116 Parameters
117 ----------
117 ----------
118 *objs : object
118 *objs : object
119 The Python objects to display, or if raw=True raw HTML data to
119 The Python objects to display, or if raw=True raw HTML data to
120 display.
120 display.
121 raw : bool
121 raw : bool
122 Are the data objects raw data or Python objects that need to be
122 Are the data objects raw data or Python objects that need to be
123 formatted before display? [default: False]
123 formatted before display? [default: False]
124 metadata : dict (optional)
124 metadata : dict (optional)
125 Metadata to be associated with the specific mimetype output.
125 Metadata to be associated with the specific mimetype output.
126 """
126 """
127 _display_mimetype('text/html', objs, **kwargs)
127 _display_mimetype('text/html', objs, **kwargs)
128
128
129
129
130 def display_markdown(*objs, **kwargs):
130 def display_markdown(*objs, **kwargs):
131 """Displays the Markdown representation of an object.
131 """Displays the Markdown representation of an object.
132
132
133 Parameters
133 Parameters
134 ----------
134 ----------
135 *objs : object
135 *objs : object
136 The Python objects to display, or if raw=True raw markdown data to
136 The Python objects to display, or if raw=True raw markdown data to
137 display.
137 display.
138 raw : bool
138 raw : bool
139 Are the data objects raw data or Python objects that need to be
139 Are the data objects raw data or Python objects that need to be
140 formatted before display? [default: False]
140 formatted before display? [default: False]
141 metadata : dict (optional)
141 metadata : dict (optional)
142 Metadata to be associated with the specific mimetype output.
142 Metadata to be associated with the specific mimetype output.
143 """
143 """
144
144
145 _display_mimetype('text/markdown', objs, **kwargs)
145 _display_mimetype('text/markdown', objs, **kwargs)
146
146
147
147
148 def display_svg(*objs, **kwargs):
148 def display_svg(*objs, **kwargs):
149 """Display the SVG representation of an object.
149 """Display the SVG representation of an object.
150
150
151 Parameters
151 Parameters
152 ----------
152 ----------
153 *objs : object
153 *objs : object
154 The Python objects to display, or if raw=True raw svg data to
154 The Python objects to display, or if raw=True raw svg data to
155 display.
155 display.
156 raw : bool
156 raw : bool
157 Are the data objects raw data or Python objects that need to be
157 Are the data objects raw data or Python objects that need to be
158 formatted before display? [default: False]
158 formatted before display? [default: False]
159 metadata : dict (optional)
159 metadata : dict (optional)
160 Metadata to be associated with the specific mimetype output.
160 Metadata to be associated with the specific mimetype output.
161 """
161 """
162 _display_mimetype('image/svg+xml', objs, **kwargs)
162 _display_mimetype('image/svg+xml', objs, **kwargs)
163
163
164
164
165 def display_png(*objs, **kwargs):
165 def display_png(*objs, **kwargs):
166 """Display the PNG representation of an object.
166 """Display the PNG representation of an object.
167
167
168 Parameters
168 Parameters
169 ----------
169 ----------
170 *objs : object
170 *objs : object
171 The Python objects to display, or if raw=True raw png data to
171 The Python objects to display, or if raw=True raw png data to
172 display.
172 display.
173 raw : bool
173 raw : bool
174 Are the data objects raw data or Python objects that need to be
174 Are the data objects raw data or Python objects that need to be
175 formatted before display? [default: False]
175 formatted before display? [default: False]
176 metadata : dict (optional)
176 metadata : dict (optional)
177 Metadata to be associated with the specific mimetype output.
177 Metadata to be associated with the specific mimetype output.
178 """
178 """
179 _display_mimetype('image/png', objs, **kwargs)
179 _display_mimetype('image/png', objs, **kwargs)
180
180
181
181
182 def display_jpeg(*objs, **kwargs):
182 def display_jpeg(*objs, **kwargs):
183 """Display the JPEG representation of an object.
183 """Display the JPEG representation of an object.
184
184
185 Parameters
185 Parameters
186 ----------
186 ----------
187 *objs : object
187 *objs : object
188 The Python objects to display, or if raw=True raw JPEG data to
188 The Python objects to display, or if raw=True raw JPEG data to
189 display.
189 display.
190 raw : bool
190 raw : bool
191 Are the data objects raw data or Python objects that need to be
191 Are the data objects raw data or Python objects that need to be
192 formatted before display? [default: False]
192 formatted before display? [default: False]
193 metadata : dict (optional)
193 metadata : dict (optional)
194 Metadata to be associated with the specific mimetype output.
194 Metadata to be associated with the specific mimetype output.
195 """
195 """
196 _display_mimetype('image/jpeg', objs, **kwargs)
196 _display_mimetype('image/jpeg', objs, **kwargs)
197
197
198
198
199 def display_latex(*objs, **kwargs):
199 def display_latex(*objs, **kwargs):
200 """Display the LaTeX representation of an object.
200 """Display the LaTeX representation of an object.
201
201
202 Parameters
202 Parameters
203 ----------
203 ----------
204 *objs : object
204 *objs : object
205 The Python objects to display, or if raw=True raw latex data to
205 The Python objects to display, or if raw=True raw latex data to
206 display.
206 display.
207 raw : bool
207 raw : bool
208 Are the data objects raw data or Python objects that need to be
208 Are the data objects raw data or Python objects that need to be
209 formatted before display? [default: False]
209 formatted before display? [default: False]
210 metadata : dict (optional)
210 metadata : dict (optional)
211 Metadata to be associated with the specific mimetype output.
211 Metadata to be associated with the specific mimetype output.
212 """
212 """
213 _display_mimetype('text/latex', objs, **kwargs)
213 _display_mimetype('text/latex', objs, **kwargs)
214
214
215
215
216 def display_json(*objs, **kwargs):
216 def display_json(*objs, **kwargs):
217 """Display the JSON representation of an object.
217 """Display the JSON representation of an object.
218
218
219 Note that not many frontends support displaying JSON.
219 Note that not many frontends support displaying JSON.
220
220
221 Parameters
221 Parameters
222 ----------
222 ----------
223 *objs : object
223 *objs : object
224 The Python objects to display, or if raw=True raw json data to
224 The Python objects to display, or if raw=True raw json data to
225 display.
225 display.
226 raw : bool
226 raw : bool
227 Are the data objects raw data or Python objects that need to be
227 Are the data objects raw data or Python objects that need to be
228 formatted before display? [default: False]
228 formatted before display? [default: False]
229 metadata : dict (optional)
229 metadata : dict (optional)
230 Metadata to be associated with the specific mimetype output.
230 Metadata to be associated with the specific mimetype output.
231 """
231 """
232 _display_mimetype('application/json', objs, **kwargs)
232 _display_mimetype('application/json', objs, **kwargs)
233
233
234
234
235 def display_javascript(*objs, **kwargs):
235 def display_javascript(*objs, **kwargs):
236 """Display the Javascript representation of an object.
236 """Display the Javascript representation of an object.
237
237
238 Parameters
238 Parameters
239 ----------
239 ----------
240 *objs : object
240 *objs : object
241 The Python objects to display, or if raw=True raw javascript data to
241 The Python objects to display, or if raw=True raw javascript data to
242 display.
242 display.
243 raw : bool
243 raw : bool
244 Are the data objects raw data or Python objects that need to be
244 Are the data objects raw data or Python objects that need to be
245 formatted before display? [default: False]
245 formatted before display? [default: False]
246 metadata : dict (optional)
246 metadata : dict (optional)
247 Metadata to be associated with the specific mimetype output.
247 Metadata to be associated with the specific mimetype output.
248 """
248 """
249 _display_mimetype('application/javascript', objs, **kwargs)
249 _display_mimetype('application/javascript', objs, **kwargs)
250
250
251
251
252 def display_pdf(*objs, **kwargs):
252 def display_pdf(*objs, **kwargs):
253 """Display the PDF representation of an object.
253 """Display the PDF representation of an object.
254
254
255 Parameters
255 Parameters
256 ----------
256 ----------
257 *objs : object
257 *objs : object
258 The Python objects to display, or if raw=True raw javascript data to
258 The Python objects to display, or if raw=True raw javascript data to
259 display.
259 display.
260 raw : bool
260 raw : bool
261 Are the data objects raw data or Python objects that need to be
261 Are the data objects raw data or Python objects that need to be
262 formatted before display? [default: False]
262 formatted before display? [default: False]
263 metadata : dict (optional)
263 metadata : dict (optional)
264 Metadata to be associated with the specific mimetype output.
264 Metadata to be associated with the specific mimetype output.
265 """
265 """
266 _display_mimetype('application/pdf', objs, **kwargs)
266 _display_mimetype('application/pdf', objs, **kwargs)
267
267
268
268
269 #-----------------------------------------------------------------------------
269 #-----------------------------------------------------------------------------
270 # Smart classes
270 # Smart classes
271 #-----------------------------------------------------------------------------
271 #-----------------------------------------------------------------------------
272
272
273
273
274 class DisplayObject(object):
274 class DisplayObject(object):
275 """An object that wraps data to be displayed."""
275 """An object that wraps data to be displayed."""
276
276
277 _read_flags = 'r'
277 _read_flags = 'r'
278 _show_mem_addr = False
278 _show_mem_addr = False
279 metadata = None
279 metadata = None
280
280
281 def __init__(self, data=None, url=None, filename=None, metadata=None):
281 def __init__(self, data=None, url=None, filename=None, metadata=None):
282 """Create a display object given raw data.
282 """Create a display object given raw data.
283
283
284 When this object is returned by an expression or passed to the
284 When this object is returned by an expression or passed to the
285 display function, it will result in the data being displayed
285 display function, it will result in the data being displayed
286 in the frontend. The MIME type of the data should match the
286 in the frontend. The MIME type of the data should match the
287 subclasses used, so the Png subclass should be used for 'image/png'
287 subclasses used, so the Png subclass should be used for 'image/png'
288 data. If the data is a URL, the data will first be downloaded
288 data. If the data is a URL, the data will first be downloaded
289 and then displayed. If
289 and then displayed. If
290
290
291 Parameters
291 Parameters
292 ----------
292 ----------
293 data : unicode, str or bytes
293 data : unicode, str or bytes
294 The raw data or a URL or file to load the data from
294 The raw data or a URL or file to load the data from
295 url : unicode
295 url : unicode
296 A URL to download the data from.
296 A URL to download the data from.
297 filename : unicode
297 filename : unicode
298 Path to a local file to load the data from.
298 Path to a local file to load the data from.
299 metadata : dict
299 metadata : dict
300 Dict of metadata associated to be the object when displayed
300 Dict of metadata associated to be the object when displayed
301 """
301 """
302 if isinstance(data, (Path, PurePath)):
302 if isinstance(data, (Path, PurePath)):
303 data = str(data)
303 data = str(data)
304
304
305 if data is not None and isinstance(data, str):
305 if data is not None and isinstance(data, str):
306 if data.startswith('http') and url is None:
306 if data.startswith('http') and url is None:
307 url = data
307 url = data
308 filename = None
308 filename = None
309 data = None
309 data = None
310 elif _safe_exists(data) and filename is None:
310 elif _safe_exists(data) and filename is None:
311 url = None
311 url = None
312 filename = data
312 filename = data
313 data = None
313 data = None
314
314
315 self.url = url
315 self.url = url
316 self.filename = filename
316 self.filename = filename
317 # because of @data.setter methods in
317 # because of @data.setter methods in
318 # subclasses ensure url and filename are set
318 # subclasses ensure url and filename are set
319 # before assigning to self.data
319 # before assigning to self.data
320 self.data = data
320 self.data = data
321
321
322 if metadata is not None:
322 if metadata is not None:
323 self.metadata = metadata
323 self.metadata = metadata
324 elif self.metadata is None:
324 elif self.metadata is None:
325 self.metadata = {}
325 self.metadata = {}
326
326
327 self.reload()
327 self.reload()
328 self._check_data()
328 self._check_data()
329
329
330 def __repr__(self):
330 def __repr__(self):
331 if not self._show_mem_addr:
331 if not self._show_mem_addr:
332 cls = self.__class__
332 cls = self.__class__
333 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
333 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
334 else:
334 else:
335 r = super(DisplayObject, self).__repr__()
335 r = super(DisplayObject, self).__repr__()
336 return r
336 return r
337
337
338 def _check_data(self):
338 def _check_data(self):
339 """Override in subclasses if there's something to check."""
339 """Override in subclasses if there's something to check."""
340 pass
340 pass
341
341
342 def _data_and_metadata(self):
342 def _data_and_metadata(self):
343 """shortcut for returning metadata with shape information, if defined"""
343 """shortcut for returning metadata with shape information, if defined"""
344 if self.metadata:
344 if self.metadata:
345 return self.data, deepcopy(self.metadata)
345 return self.data, deepcopy(self.metadata)
346 else:
346 else:
347 return self.data
347 return self.data
348
348
349 def reload(self):
349 def reload(self):
350 """Reload the raw data from file or URL."""
350 """Reload the raw data from file or URL."""
351 if self.filename is not None:
351 if self.filename is not None:
352 encoding = None if 'b' in self._read_flags else 'utf-8'
352 encoding = None if "b" in self._read_flags else "utf-8"
353 with open(self.filename, self._read_flags, encoding=encoding) as f:
353 with open(self.filename, self._read_flags, encoding=encoding) as f:
354 self.data = f.read()
354 self.data = f.read()
355 elif self.url is not None:
355 elif self.url is not None:
356 # Deferred import
356 # Deferred import
357 from urllib.request import urlopen
357 from urllib.request import urlopen
358 response = urlopen(self.url)
358 response = urlopen(self.url)
359 data = response.read()
359 data = response.read()
360 # extract encoding from header, if there is one:
360 # extract encoding from header, if there is one:
361 encoding = None
361 encoding = None
362 if 'content-type' in response.headers:
362 if 'content-type' in response.headers:
363 for sub in response.headers['content-type'].split(';'):
363 for sub in response.headers['content-type'].split(';'):
364 sub = sub.strip()
364 sub = sub.strip()
365 if sub.startswith('charset'):
365 if sub.startswith('charset'):
366 encoding = sub.split('=')[-1].strip()
366 encoding = sub.split('=')[-1].strip()
367 break
367 break
368 if 'content-encoding' in response.headers:
368 if 'content-encoding' in response.headers:
369 # TODO: do deflate?
369 # TODO: do deflate?
370 if 'gzip' in response.headers['content-encoding']:
370 if 'gzip' in response.headers['content-encoding']:
371 import gzip
371 import gzip
372 from io import BytesIO
372 from io import BytesIO
373
373 # assume utf-8 if encoding is not specified
374 # assume utf-8 if encoding is not specified
374 with gzip.open(BytesIO(data), 'rt', encoding=encoding or 'utf-8') as fp:
375 with gzip.open(
376 BytesIO(data), "rt", encoding=encoding or "utf-8"
377 ) as fp:
375 encoding = None
378 encoding = None
376 data = fp.read()
379 data = fp.read()
377
380
378 # decode data, if an encoding was specified
381 # decode data, if an encoding was specified
379 # We only touch self.data once since
382 # We only touch self.data once since
380 # subclasses such as SVG have @data.setter methods
383 # subclasses such as SVG have @data.setter methods
381 # that transform self.data into ... well svg.
384 # that transform self.data into ... well svg.
382 if encoding:
385 if encoding:
383 self.data = data.decode(encoding, 'replace')
386 self.data = data.decode(encoding, 'replace')
384 else:
387 else:
385 self.data = data
388 self.data = data
386
389
387
390
388 class TextDisplayObject(DisplayObject):
391 class TextDisplayObject(DisplayObject):
389 """Validate that display data is text"""
392 """Validate that display data is text"""
390 def _check_data(self):
393 def _check_data(self):
391 if self.data is not None and not isinstance(self.data, str):
394 if self.data is not None and not isinstance(self.data, str):
392 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
395 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
393
396
394 class Pretty(TextDisplayObject):
397 class Pretty(TextDisplayObject):
395
398
396 def _repr_pretty_(self, pp, cycle):
399 def _repr_pretty_(self, pp, cycle):
397 return pp.text(self.data)
400 return pp.text(self.data)
398
401
399
402
400 class HTML(TextDisplayObject):
403 class HTML(TextDisplayObject):
401
404
402 def __init__(self, data=None, url=None, filename=None, metadata=None):
405 def __init__(self, data=None, url=None, filename=None, metadata=None):
403 def warn():
406 def warn():
404 if not data:
407 if not data:
405 return False
408 return False
406
409
407 #
410 #
408 # Avoid calling lower() on the entire data, because it could be a
411 # Avoid calling lower() on the entire data, because it could be a
409 # long string and we're only interested in its beginning and end.
412 # long string and we're only interested in its beginning and end.
410 #
413 #
411 prefix = data[:10].lower()
414 prefix = data[:10].lower()
412 suffix = data[-10:].lower()
415 suffix = data[-10:].lower()
413 return prefix.startswith("<iframe ") and suffix.endswith("</iframe>")
416 return prefix.startswith("<iframe ") and suffix.endswith("</iframe>")
414
417
415 if warn():
418 if warn():
416 warnings.warn("Consider using IPython.display.IFrame instead")
419 warnings.warn("Consider using IPython.display.IFrame instead")
417 super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata)
420 super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata)
418
421
419 def _repr_html_(self):
422 def _repr_html_(self):
420 return self._data_and_metadata()
423 return self._data_and_metadata()
421
424
422 def __html__(self):
425 def __html__(self):
423 """
426 """
424 This method exists to inform other HTML-using modules (e.g. Markupsafe,
427 This method exists to inform other HTML-using modules (e.g. Markupsafe,
425 htmltag, etc) that this object is HTML and does not need things like
428 htmltag, etc) that this object is HTML and does not need things like
426 special characters (<>&) escaped.
429 special characters (<>&) escaped.
427 """
430 """
428 return self._repr_html_()
431 return self._repr_html_()
429
432
430
433
431 class Markdown(TextDisplayObject):
434 class Markdown(TextDisplayObject):
432
435
433 def _repr_markdown_(self):
436 def _repr_markdown_(self):
434 return self._data_and_metadata()
437 return self._data_and_metadata()
435
438
436
439
437 class Math(TextDisplayObject):
440 class Math(TextDisplayObject):
438
441
439 def _repr_latex_(self):
442 def _repr_latex_(self):
440 s = r"$\displaystyle %s$" % self.data.strip('$')
443 s = r"$\displaystyle %s$" % self.data.strip('$')
441 if self.metadata:
444 if self.metadata:
442 return s, deepcopy(self.metadata)
445 return s, deepcopy(self.metadata)
443 else:
446 else:
444 return s
447 return s
445
448
446
449
447 class Latex(TextDisplayObject):
450 class Latex(TextDisplayObject):
448
451
449 def _repr_latex_(self):
452 def _repr_latex_(self):
450 return self._data_and_metadata()
453 return self._data_and_metadata()
451
454
452
455
453 class SVG(DisplayObject):
456 class SVG(DisplayObject):
454 """Embed an SVG into the display.
457 """Embed an SVG into the display.
455
458
456 Note if you just want to view a svg image via a URL use `:class:Image` with
459 Note if you just want to view a svg image via a URL use `:class:Image` with
457 a url=URL keyword argument.
460 a url=URL keyword argument.
458 """
461 """
459
462
460 _read_flags = 'rb'
463 _read_flags = 'rb'
461 # wrap data in a property, which extracts the <svg> tag, discarding
464 # wrap data in a property, which extracts the <svg> tag, discarding
462 # document headers
465 # document headers
463 _data = None
466 _data = None
464
467
465 @property
468 @property
466 def data(self):
469 def data(self):
467 return self._data
470 return self._data
468
471
469 @data.setter
472 @data.setter
470 def data(self, svg):
473 def data(self, svg):
471 if svg is None:
474 if svg is None:
472 self._data = None
475 self._data = None
473 return
476 return
474 # parse into dom object
477 # parse into dom object
475 from xml.dom import minidom
478 from xml.dom import minidom
476 x = minidom.parseString(svg)
479 x = minidom.parseString(svg)
477 # get svg tag (should be 1)
480 # get svg tag (should be 1)
478 found_svg = x.getElementsByTagName('svg')
481 found_svg = x.getElementsByTagName('svg')
479 if found_svg:
482 if found_svg:
480 svg = found_svg[0].toxml()
483 svg = found_svg[0].toxml()
481 else:
484 else:
482 # fallback on the input, trust the user
485 # fallback on the input, trust the user
483 # but this is probably an error.
486 # but this is probably an error.
484 pass
487 pass
485 svg = cast_unicode(svg)
488 svg = cast_unicode(svg)
486 self._data = svg
489 self._data = svg
487
490
488 def _repr_svg_(self):
491 def _repr_svg_(self):
489 return self._data_and_metadata()
492 return self._data_and_metadata()
490
493
491 class ProgressBar(DisplayObject):
494 class ProgressBar(DisplayObject):
492 """Progressbar supports displaying a progressbar like element
495 """Progressbar supports displaying a progressbar like element
493 """
496 """
494 def __init__(self, total):
497 def __init__(self, total):
495 """Creates a new progressbar
498 """Creates a new progressbar
496
499
497 Parameters
500 Parameters
498 ----------
501 ----------
499 total : int
502 total : int
500 maximum size of the progressbar
503 maximum size of the progressbar
501 """
504 """
502 self.total = total
505 self.total = total
503 self._progress = 0
506 self._progress = 0
504 self.html_width = '60ex'
507 self.html_width = '60ex'
505 self.text_width = 60
508 self.text_width = 60
506 self._display_id = hexlify(os.urandom(8)).decode('ascii')
509 self._display_id = hexlify(os.urandom(8)).decode('ascii')
507
510
508 def __repr__(self):
511 def __repr__(self):
509 fraction = self.progress / self.total
512 fraction = self.progress / self.total
510 filled = '=' * int(fraction * self.text_width)
513 filled = '=' * int(fraction * self.text_width)
511 rest = ' ' * (self.text_width - len(filled))
514 rest = ' ' * (self.text_width - len(filled))
512 return '[{}{}] {}/{}'.format(
515 return '[{}{}] {}/{}'.format(
513 filled, rest,
516 filled, rest,
514 self.progress, self.total,
517 self.progress, self.total,
515 )
518 )
516
519
517 def _repr_html_(self):
520 def _repr_html_(self):
518 return "<progress style='width:{}' max='{}' value='{}'></progress>".format(
521 return "<progress style='width:{}' max='{}' value='{}'></progress>".format(
519 self.html_width, self.total, self.progress)
522 self.html_width, self.total, self.progress)
520
523
521 def display(self):
524 def display(self):
522 display_functions.display(self, display_id=self._display_id)
525 display_functions.display(self, display_id=self._display_id)
523
526
524 def update(self):
527 def update(self):
525 display_functions.display(self, display_id=self._display_id, update=True)
528 display_functions.display(self, display_id=self._display_id, update=True)
526
529
527 @property
530 @property
528 def progress(self):
531 def progress(self):
529 return self._progress
532 return self._progress
530
533
531 @progress.setter
534 @progress.setter
532 def progress(self, value):
535 def progress(self, value):
533 self._progress = value
536 self._progress = value
534 self.update()
537 self.update()
535
538
536 def __iter__(self):
539 def __iter__(self):
537 self.display()
540 self.display()
538 self._progress = -1 # First iteration is 0
541 self._progress = -1 # First iteration is 0
539 return self
542 return self
540
543
541 def __next__(self):
544 def __next__(self):
542 """Returns current value and increments display by one."""
545 """Returns current value and increments display by one."""
543 self.progress += 1
546 self.progress += 1
544 if self.progress < self.total:
547 if self.progress < self.total:
545 return self.progress
548 return self.progress
546 else:
549 else:
547 raise StopIteration()
550 raise StopIteration()
548
551
549 class JSON(DisplayObject):
552 class JSON(DisplayObject):
550 """JSON expects a JSON-able dict or list
553 """JSON expects a JSON-able dict or list
551
554
552 not an already-serialized JSON string.
555 not an already-serialized JSON string.
553
556
554 Scalar types (None, number, string) are not allowed, only dict or list containers.
557 Scalar types (None, number, string) are not allowed, only dict or list containers.
555 """
558 """
556 # wrap data in a property, which warns about passing already-serialized JSON
559 # wrap data in a property, which warns about passing already-serialized JSON
557 _data = None
560 _data = None
558 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, root='root', **kwargs):
561 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, root='root', **kwargs):
559 """Create a JSON display object given raw data.
562 """Create a JSON display object given raw data.
560
563
561 Parameters
564 Parameters
562 ----------
565 ----------
563 data : dict or list
566 data : dict or list
564 JSON data to display. Not an already-serialized JSON string.
567 JSON data to display. Not an already-serialized JSON string.
565 Scalar types (None, number, string) are not allowed, only dict
568 Scalar types (None, number, string) are not allowed, only dict
566 or list containers.
569 or list containers.
567 url : unicode
570 url : unicode
568 A URL to download the data from.
571 A URL to download the data from.
569 filename : unicode
572 filename : unicode
570 Path to a local file to load the data from.
573 Path to a local file to load the data from.
571 expanded : boolean
574 expanded : boolean
572 Metadata to control whether a JSON display component is expanded.
575 Metadata to control whether a JSON display component is expanded.
573 metadata : dict
576 metadata : dict
574 Specify extra metadata to attach to the json display object.
577 Specify extra metadata to attach to the json display object.
575 root : str
578 root : str
576 The name of the root element of the JSON tree
579 The name of the root element of the JSON tree
577 """
580 """
578 self.metadata = {
581 self.metadata = {
579 'expanded': expanded,
582 'expanded': expanded,
580 'root': root,
583 'root': root,
581 }
584 }
582 if metadata:
585 if metadata:
583 self.metadata.update(metadata)
586 self.metadata.update(metadata)
584 if kwargs:
587 if kwargs:
585 self.metadata.update(kwargs)
588 self.metadata.update(kwargs)
586 super(JSON, self).__init__(data=data, url=url, filename=filename)
589 super(JSON, self).__init__(data=data, url=url, filename=filename)
587
590
588 def _check_data(self):
591 def _check_data(self):
589 if self.data is not None and not isinstance(self.data, (dict, list)):
592 if self.data is not None and not isinstance(self.data, (dict, list)):
590 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
593 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
591
594
592 @property
595 @property
593 def data(self):
596 def data(self):
594 return self._data
597 return self._data
595
598
596 @data.setter
599 @data.setter
597 def data(self, data):
600 def data(self, data):
598 if isinstance(data, (Path, PurePath)):
601 if isinstance(data, (Path, PurePath)):
599 data = str(data)
602 data = str(data)
600
603
601 if isinstance(data, str):
604 if isinstance(data, str):
602 if self.filename is None and self.url is None:
605 if self.filename is None and self.url is None:
603 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
606 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
604 data = json.loads(data)
607 data = json.loads(data)
605 self._data = data
608 self._data = data
606
609
607 def _data_and_metadata(self):
610 def _data_and_metadata(self):
608 return self.data, self.metadata
611 return self.data, self.metadata
609
612
610 def _repr_json_(self):
613 def _repr_json_(self):
611 return self._data_and_metadata()
614 return self._data_and_metadata()
612
615
613 _css_t = """var link = document.createElement("link");
616 _css_t = """var link = document.createElement("link");
614 link.ref = "stylesheet";
617 link.ref = "stylesheet";
615 link.type = "text/css";
618 link.type = "text/css";
616 link.href = "%s";
619 link.href = "%s";
617 document.head.appendChild(link);
620 document.head.appendChild(link);
618 """
621 """
619
622
620 _lib_t1 = """new Promise(function(resolve, reject) {
623 _lib_t1 = """new Promise(function(resolve, reject) {
621 var script = document.createElement("script");
624 var script = document.createElement("script");
622 script.onload = resolve;
625 script.onload = resolve;
623 script.onerror = reject;
626 script.onerror = reject;
624 script.src = "%s";
627 script.src = "%s";
625 document.head.appendChild(script);
628 document.head.appendChild(script);
626 }).then(() => {
629 }).then(() => {
627 """
630 """
628
631
629 _lib_t2 = """
632 _lib_t2 = """
630 });"""
633 });"""
631
634
632 class GeoJSON(JSON):
635 class GeoJSON(JSON):
633 """GeoJSON expects JSON-able dict
636 """GeoJSON expects JSON-able dict
634
637
635 not an already-serialized JSON string.
638 not an already-serialized JSON string.
636
639
637 Scalar types (None, number, string) are not allowed, only dict containers.
640 Scalar types (None, number, string) are not allowed, only dict containers.
638 """
641 """
639
642
640 def __init__(self, *args, **kwargs):
643 def __init__(self, *args, **kwargs):
641 """Create a GeoJSON display object given raw data.
644 """Create a GeoJSON display object given raw data.
642
645
643 Parameters
646 Parameters
644 ----------
647 ----------
645 data : dict or list
648 data : dict or list
646 VegaLite data. Not an already-serialized JSON string.
649 VegaLite data. Not an already-serialized JSON string.
647 Scalar types (None, number, string) are not allowed, only dict
650 Scalar types (None, number, string) are not allowed, only dict
648 or list containers.
651 or list containers.
649 url_template : string
652 url_template : string
650 Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
653 Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
651 layer_options : dict
654 layer_options : dict
652 Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
655 Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
653 url : unicode
656 url : unicode
654 A URL to download the data from.
657 A URL to download the data from.
655 filename : unicode
658 filename : unicode
656 Path to a local file to load the data from.
659 Path to a local file to load the data from.
657 metadata : dict
660 metadata : dict
658 Specify extra metadata to attach to the json display object.
661 Specify extra metadata to attach to the json display object.
659
662
660 Examples
663 Examples
661 --------
664 --------
662 The following will display an interactive map of Mars with a point of
665 The following will display an interactive map of Mars with a point of
663 interest on frontend that do support GeoJSON display.
666 interest on frontend that do support GeoJSON display.
664
667
665 >>> from IPython.display import GeoJSON
668 >>> from IPython.display import GeoJSON
666
669
667 >>> GeoJSON(data={
670 >>> GeoJSON(data={
668 ... "type": "Feature",
671 ... "type": "Feature",
669 ... "geometry": {
672 ... "geometry": {
670 ... "type": "Point",
673 ... "type": "Point",
671 ... "coordinates": [-81.327, 296.038]
674 ... "coordinates": [-81.327, 296.038]
672 ... }
675 ... }
673 ... },
676 ... },
674 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
677 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
675 ... layer_options={
678 ... layer_options={
676 ... "basemap_id": "celestia_mars-shaded-16k_global",
679 ... "basemap_id": "celestia_mars-shaded-16k_global",
677 ... "attribution" : "Celestia/praesepe",
680 ... "attribution" : "Celestia/praesepe",
678 ... "minZoom" : 0,
681 ... "minZoom" : 0,
679 ... "maxZoom" : 18,
682 ... "maxZoom" : 18,
680 ... })
683 ... })
681 <IPython.core.display.GeoJSON object>
684 <IPython.core.display.GeoJSON object>
682
685
683 In the terminal IPython, you will only see the text representation of
686 In the terminal IPython, you will only see the text representation of
684 the GeoJSON object.
687 the GeoJSON object.
685
688
686 """
689 """
687
690
688 super(GeoJSON, self).__init__(*args, **kwargs)
691 super(GeoJSON, self).__init__(*args, **kwargs)
689
692
690
693
691 def _ipython_display_(self):
694 def _ipython_display_(self):
692 bundle = {
695 bundle = {
693 'application/geo+json': self.data,
696 'application/geo+json': self.data,
694 'text/plain': '<IPython.display.GeoJSON object>'
697 'text/plain': '<IPython.display.GeoJSON object>'
695 }
698 }
696 metadata = {
699 metadata = {
697 'application/geo+json': self.metadata
700 'application/geo+json': self.metadata
698 }
701 }
699 display_functions.display(bundle, metadata=metadata, raw=True)
702 display_functions.display(bundle, metadata=metadata, raw=True)
700
703
701 class Javascript(TextDisplayObject):
704 class Javascript(TextDisplayObject):
702
705
703 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
706 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
704 """Create a Javascript display object given raw data.
707 """Create a Javascript display object given raw data.
705
708
706 When this object is returned by an expression or passed to the
709 When this object is returned by an expression or passed to the
707 display function, it will result in the data being displayed
710 display function, it will result in the data being displayed
708 in the frontend. If the data is a URL, the data will first be
711 in the frontend. If the data is a URL, the data will first be
709 downloaded and then displayed.
712 downloaded and then displayed.
710
713
711 In the Notebook, the containing element will be available as `element`,
714 In the Notebook, the containing element will be available as `element`,
712 and jQuery will be available. Content appended to `element` will be
715 and jQuery will be available. Content appended to `element` will be
713 visible in the output area.
716 visible in the output area.
714
717
715 Parameters
718 Parameters
716 ----------
719 ----------
717 data : unicode, str or bytes
720 data : unicode, str or bytes
718 The Javascript source code or a URL to download it from.
721 The Javascript source code or a URL to download it from.
719 url : unicode
722 url : unicode
720 A URL to download the data from.
723 A URL to download the data from.
721 filename : unicode
724 filename : unicode
722 Path to a local file to load the data from.
725 Path to a local file to load the data from.
723 lib : list or str
726 lib : list or str
724 A sequence of Javascript library URLs to load asynchronously before
727 A sequence of Javascript library URLs to load asynchronously before
725 running the source code. The full URLs of the libraries should
728 running the source code. The full URLs of the libraries should
726 be given. A single Javascript library URL can also be given as a
729 be given. A single Javascript library URL can also be given as a
727 string.
730 string.
728 css : list or str
731 css : list or str
729 A sequence of css files to load before running the source code.
732 A sequence of css files to load before running the source code.
730 The full URLs of the css files should be given. A single css URL
733 The full URLs of the css files should be given. A single css URL
731 can also be given as a string.
734 can also be given as a string.
732 """
735 """
733 if isinstance(lib, str):
736 if isinstance(lib, str):
734 lib = [lib]
737 lib = [lib]
735 elif lib is None:
738 elif lib is None:
736 lib = []
739 lib = []
737 if isinstance(css, str):
740 if isinstance(css, str):
738 css = [css]
741 css = [css]
739 elif css is None:
742 elif css is None:
740 css = []
743 css = []
741 if not isinstance(lib, (list,tuple)):
744 if not isinstance(lib, (list,tuple)):
742 raise TypeError('expected sequence, got: %r' % lib)
745 raise TypeError('expected sequence, got: %r' % lib)
743 if not isinstance(css, (list,tuple)):
746 if not isinstance(css, (list,tuple)):
744 raise TypeError('expected sequence, got: %r' % css)
747 raise TypeError('expected sequence, got: %r' % css)
745 self.lib = lib
748 self.lib = lib
746 self.css = css
749 self.css = css
747 super(Javascript, self).__init__(data=data, url=url, filename=filename)
750 super(Javascript, self).__init__(data=data, url=url, filename=filename)
748
751
749 def _repr_javascript_(self):
752 def _repr_javascript_(self):
750 r = ''
753 r = ''
751 for c in self.css:
754 for c in self.css:
752 r += _css_t % c
755 r += _css_t % c
753 for l in self.lib:
756 for l in self.lib:
754 r += _lib_t1 % l
757 r += _lib_t1 % l
755 r += self.data
758 r += self.data
756 r += _lib_t2*len(self.lib)
759 r += _lib_t2*len(self.lib)
757 return r
760 return r
758
761
759 # constants for identifying png/jpeg data
762 # constants for identifying png/jpeg data
760 _PNG = b'\x89PNG\r\n\x1a\n'
763 _PNG = b'\x89PNG\r\n\x1a\n'
761 _JPEG = b'\xff\xd8'
764 _JPEG = b'\xff\xd8'
762
765
763 def _pngxy(data):
766 def _pngxy(data):
764 """read the (width, height) from a PNG header"""
767 """read the (width, height) from a PNG header"""
765 ihdr = data.index(b'IHDR')
768 ihdr = data.index(b'IHDR')
766 # next 8 bytes are width/height
769 # next 8 bytes are width/height
767 return struct.unpack('>ii', data[ihdr+4:ihdr+12])
770 return struct.unpack('>ii', data[ihdr+4:ihdr+12])
768
771
769 def _jpegxy(data):
772 def _jpegxy(data):
770 """read the (width, height) from a JPEG header"""
773 """read the (width, height) from a JPEG header"""
771 # adapted from http://www.64lines.com/jpeg-width-height
774 # adapted from http://www.64lines.com/jpeg-width-height
772
775
773 idx = 4
776 idx = 4
774 while True:
777 while True:
775 block_size = struct.unpack('>H', data[idx:idx+2])[0]
778 block_size = struct.unpack('>H', data[idx:idx+2])[0]
776 idx = idx + block_size
779 idx = idx + block_size
777 if data[idx:idx+2] == b'\xFF\xC0':
780 if data[idx:idx+2] == b'\xFF\xC0':
778 # found Start of Frame
781 # found Start of Frame
779 iSOF = idx
782 iSOF = idx
780 break
783 break
781 else:
784 else:
782 # read another block
785 # read another block
783 idx += 2
786 idx += 2
784
787
785 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
788 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
786 return w, h
789 return w, h
787
790
788 def _gifxy(data):
791 def _gifxy(data):
789 """read the (width, height) from a GIF header"""
792 """read the (width, height) from a GIF header"""
790 return struct.unpack('<HH', data[6:10])
793 return struct.unpack('<HH', data[6:10])
791
794
792
795
793 class Image(DisplayObject):
796 class Image(DisplayObject):
794
797
795 _read_flags = 'rb'
798 _read_flags = 'rb'
796 _FMT_JPEG = u'jpeg'
799 _FMT_JPEG = u'jpeg'
797 _FMT_PNG = u'png'
800 _FMT_PNG = u'png'
798 _FMT_GIF = u'gif'
801 _FMT_GIF = u'gif'
799 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
802 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
800 _MIMETYPES = {
803 _MIMETYPES = {
801 _FMT_PNG: 'image/png',
804 _FMT_PNG: 'image/png',
802 _FMT_JPEG: 'image/jpeg',
805 _FMT_JPEG: 'image/jpeg',
803 _FMT_GIF: 'image/gif',
806 _FMT_GIF: 'image/gif',
804 }
807 }
805
808
806 def __init__(
809 def __init__(
807 self,
810 self,
808 data=None,
811 data=None,
809 url=None,
812 url=None,
810 filename=None,
813 filename=None,
811 format=None,
814 format=None,
812 embed=None,
815 embed=None,
813 width=None,
816 width=None,
814 height=None,
817 height=None,
815 retina=False,
818 retina=False,
816 unconfined=False,
819 unconfined=False,
817 metadata=None,
820 metadata=None,
818 alt=None,
821 alt=None,
819 ):
822 ):
820 """Create a PNG/JPEG/GIF image object given raw data.
823 """Create a PNG/JPEG/GIF image object given raw data.
821
824
822 When this object is returned by an input cell or passed to the
825 When this object is returned by an input cell or passed to the
823 display function, it will result in the image being displayed
826 display function, it will result in the image being displayed
824 in the frontend.
827 in the frontend.
825
828
826 Parameters
829 Parameters
827 ----------
830 ----------
828 data : unicode, str or bytes
831 data : unicode, str or bytes
829 The raw image data or a URL or filename to load the data from.
832 The raw image data or a URL or filename to load the data from.
830 This always results in embedded image data.
833 This always results in embedded image data.
831
834
832 url : unicode
835 url : unicode
833 A URL to download the data from. If you specify `url=`,
836 A URL to download the data from. If you specify `url=`,
834 the image data will not be embedded unless you also specify `embed=True`.
837 the image data will not be embedded unless you also specify `embed=True`.
835
838
836 filename : unicode
839 filename : unicode
837 Path to a local file to load the data from.
840 Path to a local file to load the data from.
838 Images from a file are always embedded.
841 Images from a file are always embedded.
839
842
840 format : unicode
843 format : unicode
841 The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given
844 The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given
842 for format will be inferred from the filename extension.
845 for format will be inferred from the filename extension.
843
846
844 embed : bool
847 embed : bool
845 Should the image data be embedded using a data URI (True) or be
848 Should the image data be embedded using a data URI (True) or be
846 loaded using an <img> tag. Set this to True if you want the image
849 loaded using an <img> tag. Set this to True if you want the image
847 to be viewable later with no internet connection in the notebook.
850 to be viewable later with no internet connection in the notebook.
848
851
849 Default is `True`, unless the keyword argument `url` is set, then
852 Default is `True`, unless the keyword argument `url` is set, then
850 default value is `False`.
853 default value is `False`.
851
854
852 Note that QtConsole is not able to display images if `embed` is set to `False`
855 Note that QtConsole is not able to display images if `embed` is set to `False`
853
856
854 width : int
857 width : int
855 Width in pixels to which to constrain the image in html
858 Width in pixels to which to constrain the image in html
856
859
857 height : int
860 height : int
858 Height in pixels to which to constrain the image in html
861 Height in pixels to which to constrain the image in html
859
862
860 retina : bool
863 retina : bool
861 Automatically set the width and height to half of the measured
864 Automatically set the width and height to half of the measured
862 width and height.
865 width and height.
863 This only works for embedded images because it reads the width/height
866 This only works for embedded images because it reads the width/height
864 from image data.
867 from image data.
865 For non-embedded images, you can just set the desired display width
868 For non-embedded images, you can just set the desired display width
866 and height directly.
869 and height directly.
867
870
868 unconfined : bool
871 unconfined : bool
869 Set unconfined=True to disable max-width confinement of the image.
872 Set unconfined=True to disable max-width confinement of the image.
870
873
871 metadata : dict
874 metadata : dict
872 Specify extra metadata to attach to the image.
875 Specify extra metadata to attach to the image.
873
876
874 alt : unicode
877 alt : unicode
875 Alternative text for the image, for use by screen readers.
878 Alternative text for the image, for use by screen readers.
876
879
877 Examples
880 Examples
878 --------
881 --------
879 embedded image data, works in qtconsole and notebook
882 embedded image data, works in qtconsole and notebook
880 when passed positionally, the first arg can be any of raw image data,
883 when passed positionally, the first arg can be any of raw image data,
881 a URL, or a filename from which to load image data.
884 a URL, or a filename from which to load image data.
882 The result is always embedding image data for inline images.
885 The result is always embedding image data for inline images.
883
886
884 >>> Image('http://www.google.fr/images/srpr/logo3w.png')
887 >>> Image('http://www.google.fr/images/srpr/logo3w.png')
885 <IPython.core.display.Image object>
888 <IPython.core.display.Image object>
886
889
887 >>> Image('/path/to/image.jpg')
890 >>> Image('/path/to/image.jpg')
888 <IPython.core.display.Image object>
891 <IPython.core.display.Image object>
889
892
890 >>> Image(b'RAW_PNG_DATA...')
893 >>> Image(b'RAW_PNG_DATA...')
891 <IPython.core.display.Image object>
894 <IPython.core.display.Image object>
892
895
893 Specifying Image(url=...) does not embed the image data,
896 Specifying Image(url=...) does not embed the image data,
894 it only generates ``<img>`` tag with a link to the source.
897 it only generates ``<img>`` tag with a link to the source.
895 This will not work in the qtconsole or offline.
898 This will not work in the qtconsole or offline.
896
899
897 >>> Image(url='http://www.google.fr/images/srpr/logo3w.png')
900 >>> Image(url='http://www.google.fr/images/srpr/logo3w.png')
898 <IPython.core.display.Image object>
901 <IPython.core.display.Image object>
899
902
900 """
903 """
901 if isinstance(data, (Path, PurePath)):
904 if isinstance(data, (Path, PurePath)):
902 data = str(data)
905 data = str(data)
903
906
904 if filename is not None:
907 if filename is not None:
905 ext = self._find_ext(filename)
908 ext = self._find_ext(filename)
906 elif url is not None:
909 elif url is not None:
907 ext = self._find_ext(url)
910 ext = self._find_ext(url)
908 elif data is None:
911 elif data is None:
909 raise ValueError("No image data found. Expecting filename, url, or data.")
912 raise ValueError("No image data found. Expecting filename, url, or data.")
910 elif isinstance(data, str) and (
913 elif isinstance(data, str) and (
911 data.startswith('http') or _safe_exists(data)
914 data.startswith('http') or _safe_exists(data)
912 ):
915 ):
913 ext = self._find_ext(data)
916 ext = self._find_ext(data)
914 else:
917 else:
915 ext = None
918 ext = None
916
919
917 if format is None:
920 if format is None:
918 if ext is not None:
921 if ext is not None:
919 if ext == u'jpg' or ext == u'jpeg':
922 if ext == u'jpg' or ext == u'jpeg':
920 format = self._FMT_JPEG
923 format = self._FMT_JPEG
921 elif ext == u'png':
924 elif ext == u'png':
922 format = self._FMT_PNG
925 format = self._FMT_PNG
923 elif ext == u'gif':
926 elif ext == u'gif':
924 format = self._FMT_GIF
927 format = self._FMT_GIF
925 else:
928 else:
926 format = ext.lower()
929 format = ext.lower()
927 elif isinstance(data, bytes):
930 elif isinstance(data, bytes):
928 # infer image type from image data header,
931 # infer image type from image data header,
929 # only if format has not been specified.
932 # only if format has not been specified.
930 if data[:2] == _JPEG:
933 if data[:2] == _JPEG:
931 format = self._FMT_JPEG
934 format = self._FMT_JPEG
932
935
933 # failed to detect format, default png
936 # failed to detect format, default png
934 if format is None:
937 if format is None:
935 format = self._FMT_PNG
938 format = self._FMT_PNG
936
939
937 if format.lower() == 'jpg':
940 if format.lower() == 'jpg':
938 # jpg->jpeg
941 # jpg->jpeg
939 format = self._FMT_JPEG
942 format = self._FMT_JPEG
940
943
941 self.format = format.lower()
944 self.format = format.lower()
942 self.embed = embed if embed is not None else (url is None)
945 self.embed = embed if embed is not None else (url is None)
943
946
944 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
947 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
945 raise ValueError("Cannot embed the '%s' image format" % (self.format))
948 raise ValueError("Cannot embed the '%s' image format" % (self.format))
946 if self.embed:
949 if self.embed:
947 self._mimetype = self._MIMETYPES.get(self.format)
950 self._mimetype = self._MIMETYPES.get(self.format)
948
951
949 self.width = width
952 self.width = width
950 self.height = height
953 self.height = height
951 self.retina = retina
954 self.retina = retina
952 self.unconfined = unconfined
955 self.unconfined = unconfined
953 self.alt = alt
956 self.alt = alt
954 super(Image, self).__init__(data=data, url=url, filename=filename,
957 super(Image, self).__init__(data=data, url=url, filename=filename,
955 metadata=metadata)
958 metadata=metadata)
956
959
957 if self.width is None and self.metadata.get('width', {}):
960 if self.width is None and self.metadata.get('width', {}):
958 self.width = metadata['width']
961 self.width = metadata['width']
959
962
960 if self.height is None and self.metadata.get('height', {}):
963 if self.height is None and self.metadata.get('height', {}):
961 self.height = metadata['height']
964 self.height = metadata['height']
962
965
963 if self.alt is None and self.metadata.get("alt", {}):
966 if self.alt is None and self.metadata.get("alt", {}):
964 self.alt = metadata["alt"]
967 self.alt = metadata["alt"]
965
968
966 if retina:
969 if retina:
967 self._retina_shape()
970 self._retina_shape()
968
971
969
972
970 def _retina_shape(self):
973 def _retina_shape(self):
971 """load pixel-doubled width and height from image data"""
974 """load pixel-doubled width and height from image data"""
972 if not self.embed:
975 if not self.embed:
973 return
976 return
974 if self.format == self._FMT_PNG:
977 if self.format == self._FMT_PNG:
975 w, h = _pngxy(self.data)
978 w, h = _pngxy(self.data)
976 elif self.format == self._FMT_JPEG:
979 elif self.format == self._FMT_JPEG:
977 w, h = _jpegxy(self.data)
980 w, h = _jpegxy(self.data)
978 elif self.format == self._FMT_GIF:
981 elif self.format == self._FMT_GIF:
979 w, h = _gifxy(self.data)
982 w, h = _gifxy(self.data)
980 else:
983 else:
981 # retina only supports png
984 # retina only supports png
982 return
985 return
983 self.width = w // 2
986 self.width = w // 2
984 self.height = h // 2
987 self.height = h // 2
985
988
986 def reload(self):
989 def reload(self):
987 """Reload the raw data from file or URL."""
990 """Reload the raw data from file or URL."""
988 if self.embed:
991 if self.embed:
989 super(Image,self).reload()
992 super(Image,self).reload()
990 if self.retina:
993 if self.retina:
991 self._retina_shape()
994 self._retina_shape()
992
995
993 def _repr_html_(self):
996 def _repr_html_(self):
994 if not self.embed:
997 if not self.embed:
995 width = height = klass = alt = ""
998 width = height = klass = alt = ""
996 if self.width:
999 if self.width:
997 width = ' width="%d"' % self.width
1000 width = ' width="%d"' % self.width
998 if self.height:
1001 if self.height:
999 height = ' height="%d"' % self.height
1002 height = ' height="%d"' % self.height
1000 if self.unconfined:
1003 if self.unconfined:
1001 klass = ' class="unconfined"'
1004 klass = ' class="unconfined"'
1002 if self.alt:
1005 if self.alt:
1003 alt = ' alt="%s"' % html.escape(self.alt)
1006 alt = ' alt="%s"' % html.escape(self.alt)
1004 return '<img src="{url}"{width}{height}{klass}{alt}/>'.format(
1007 return '<img src="{url}"{width}{height}{klass}{alt}/>'.format(
1005 url=self.url,
1008 url=self.url,
1006 width=width,
1009 width=width,
1007 height=height,
1010 height=height,
1008 klass=klass,
1011 klass=klass,
1009 alt=alt,
1012 alt=alt,
1010 )
1013 )
1011
1014
1012 def _repr_mimebundle_(self, include=None, exclude=None):
1015 def _repr_mimebundle_(self, include=None, exclude=None):
1013 """Return the image as a mimebundle
1016 """Return the image as a mimebundle
1014
1017
1015 Any new mimetype support should be implemented here.
1018 Any new mimetype support should be implemented here.
1016 """
1019 """
1017 if self.embed:
1020 if self.embed:
1018 mimetype = self._mimetype
1021 mimetype = self._mimetype
1019 data, metadata = self._data_and_metadata(always_both=True)
1022 data, metadata = self._data_and_metadata(always_both=True)
1020 if metadata:
1023 if metadata:
1021 metadata = {mimetype: metadata}
1024 metadata = {mimetype: metadata}
1022 return {mimetype: data}, metadata
1025 return {mimetype: data}, metadata
1023 else:
1026 else:
1024 return {'text/html': self._repr_html_()}
1027 return {'text/html': self._repr_html_()}
1025
1028
1026 def _data_and_metadata(self, always_both=False):
1029 def _data_and_metadata(self, always_both=False):
1027 """shortcut for returning metadata with shape information, if defined"""
1030 """shortcut for returning metadata with shape information, if defined"""
1028 try:
1031 try:
1029 b64_data = b2a_base64(self.data).decode('ascii')
1032 b64_data = b2a_base64(self.data).decode('ascii')
1030 except TypeError as e:
1033 except TypeError as e:
1031 raise FileNotFoundError(
1034 raise FileNotFoundError(
1032 "No such file or directory: '%s'" % (self.data)) from e
1035 "No such file or directory: '%s'" % (self.data)) from e
1033 md = {}
1036 md = {}
1034 if self.metadata:
1037 if self.metadata:
1035 md.update(self.metadata)
1038 md.update(self.metadata)
1036 if self.width:
1039 if self.width:
1037 md['width'] = self.width
1040 md['width'] = self.width
1038 if self.height:
1041 if self.height:
1039 md['height'] = self.height
1042 md['height'] = self.height
1040 if self.unconfined:
1043 if self.unconfined:
1041 md['unconfined'] = self.unconfined
1044 md['unconfined'] = self.unconfined
1042 if self.alt:
1045 if self.alt:
1043 md["alt"] = self.alt
1046 md["alt"] = self.alt
1044 if md or always_both:
1047 if md or always_both:
1045 return b64_data, md
1048 return b64_data, md
1046 else:
1049 else:
1047 return b64_data
1050 return b64_data
1048
1051
1049 def _repr_png_(self):
1052 def _repr_png_(self):
1050 if self.embed and self.format == self._FMT_PNG:
1053 if self.embed and self.format == self._FMT_PNG:
1051 return self._data_and_metadata()
1054 return self._data_and_metadata()
1052
1055
1053 def _repr_jpeg_(self):
1056 def _repr_jpeg_(self):
1054 if self.embed and self.format == self._FMT_JPEG:
1057 if self.embed and self.format == self._FMT_JPEG:
1055 return self._data_and_metadata()
1058 return self._data_and_metadata()
1056
1059
1057 def _find_ext(self, s):
1060 def _find_ext(self, s):
1058 base, ext = splitext(s)
1061 base, ext = splitext(s)
1059
1062
1060 if not ext:
1063 if not ext:
1061 return base
1064 return base
1062
1065
1063 # `splitext` includes leading period, so we skip it
1066 # `splitext` includes leading period, so we skip it
1064 return ext[1:].lower()
1067 return ext[1:].lower()
1065
1068
1066
1069
1067 class Video(DisplayObject):
1070 class Video(DisplayObject):
1068
1071
1069 def __init__(self, data=None, url=None, filename=None, embed=False,
1072 def __init__(self, data=None, url=None, filename=None, embed=False,
1070 mimetype=None, width=None, height=None, html_attributes="controls"):
1073 mimetype=None, width=None, height=None, html_attributes="controls"):
1071 """Create a video object given raw data or an URL.
1074 """Create a video object given raw data or an URL.
1072
1075
1073 When this object is returned by an input cell or passed to the
1076 When this object is returned by an input cell or passed to the
1074 display function, it will result in the video being displayed
1077 display function, it will result in the video being displayed
1075 in the frontend.
1078 in the frontend.
1076
1079
1077 Parameters
1080 Parameters
1078 ----------
1081 ----------
1079 data : unicode, str or bytes
1082 data : unicode, str or bytes
1080 The raw video data or a URL or filename to load the data from.
1083 The raw video data or a URL or filename to load the data from.
1081 Raw data will require passing ``embed=True``.
1084 Raw data will require passing ``embed=True``.
1082
1085
1083 url : unicode
1086 url : unicode
1084 A URL for the video. If you specify ``url=``,
1087 A URL for the video. If you specify ``url=``,
1085 the image data will not be embedded.
1088 the image data will not be embedded.
1086
1089
1087 filename : unicode
1090 filename : unicode
1088 Path to a local file containing the video.
1091 Path to a local file containing the video.
1089 Will be interpreted as a local URL unless ``embed=True``.
1092 Will be interpreted as a local URL unless ``embed=True``.
1090
1093
1091 embed : bool
1094 embed : bool
1092 Should the video be embedded using a data URI (True) or be
1095 Should the video be embedded using a data URI (True) or be
1093 loaded using a <video> tag (False).
1096 loaded using a <video> tag (False).
1094
1097
1095 Since videos are large, embedding them should be avoided, if possible.
1098 Since videos are large, embedding them should be avoided, if possible.
1096 You must confirm embedding as your intention by passing ``embed=True``.
1099 You must confirm embedding as your intention by passing ``embed=True``.
1097
1100
1098 Local files can be displayed with URLs without embedding the content, via::
1101 Local files can be displayed with URLs without embedding the content, via::
1099
1102
1100 Video('./video.mp4')
1103 Video('./video.mp4')
1101
1104
1102 mimetype : unicode
1105 mimetype : unicode
1103 Specify the mimetype for embedded videos.
1106 Specify the mimetype for embedded videos.
1104 Default will be guessed from file extension, if available.
1107 Default will be guessed from file extension, if available.
1105
1108
1106 width : int
1109 width : int
1107 Width in pixels to which to constrain the video in HTML.
1110 Width in pixels to which to constrain the video in HTML.
1108 If not supplied, defaults to the width of the video.
1111 If not supplied, defaults to the width of the video.
1109
1112
1110 height : int
1113 height : int
1111 Height in pixels to which to constrain the video in html.
1114 Height in pixels to which to constrain the video in html.
1112 If not supplied, defaults to the height of the video.
1115 If not supplied, defaults to the height of the video.
1113
1116
1114 html_attributes : str
1117 html_attributes : str
1115 Attributes for the HTML ``<video>`` block.
1118 Attributes for the HTML ``<video>`` block.
1116 Default: ``"controls"`` to get video controls.
1119 Default: ``"controls"`` to get video controls.
1117 Other examples: ``"controls muted"`` for muted video with controls,
1120 Other examples: ``"controls muted"`` for muted video with controls,
1118 ``"loop autoplay"`` for looping autoplaying video without controls.
1121 ``"loop autoplay"`` for looping autoplaying video without controls.
1119
1122
1120 Examples
1123 Examples
1121 --------
1124 --------
1122 ::
1125 ::
1123
1126
1124 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1127 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1125 Video('path/to/video.mp4')
1128 Video('path/to/video.mp4')
1126 Video('path/to/video.mp4', embed=True)
1129 Video('path/to/video.mp4', embed=True)
1127 Video('path/to/video.mp4', embed=True, html_attributes="controls muted autoplay")
1130 Video('path/to/video.mp4', embed=True, html_attributes="controls muted autoplay")
1128 Video(b'raw-videodata', embed=True)
1131 Video(b'raw-videodata', embed=True)
1129 """
1132 """
1130 if isinstance(data, (Path, PurePath)):
1133 if isinstance(data, (Path, PurePath)):
1131 data = str(data)
1134 data = str(data)
1132
1135
1133 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1136 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1134 url = data
1137 url = data
1135 data = None
1138 data = None
1136 elif data is not None and os.path.exists(data):
1139 elif data is not None and os.path.exists(data):
1137 filename = data
1140 filename = data
1138 data = None
1141 data = None
1139
1142
1140 if data and not embed:
1143 if data and not embed:
1141 msg = ''.join([
1144 msg = ''.join([
1142 "To embed videos, you must pass embed=True ",
1145 "To embed videos, you must pass embed=True ",
1143 "(this may make your notebook files huge)\n",
1146 "(this may make your notebook files huge)\n",
1144 "Consider passing Video(url='...')",
1147 "Consider passing Video(url='...')",
1145 ])
1148 ])
1146 raise ValueError(msg)
1149 raise ValueError(msg)
1147
1150
1148 self.mimetype = mimetype
1151 self.mimetype = mimetype
1149 self.embed = embed
1152 self.embed = embed
1150 self.width = width
1153 self.width = width
1151 self.height = height
1154 self.height = height
1152 self.html_attributes = html_attributes
1155 self.html_attributes = html_attributes
1153 super(Video, self).__init__(data=data, url=url, filename=filename)
1156 super(Video, self).__init__(data=data, url=url, filename=filename)
1154
1157
1155 def _repr_html_(self):
1158 def _repr_html_(self):
1156 width = height = ''
1159 width = height = ''
1157 if self.width:
1160 if self.width:
1158 width = ' width="%d"' % self.width
1161 width = ' width="%d"' % self.width
1159 if self.height:
1162 if self.height:
1160 height = ' height="%d"' % self.height
1163 height = ' height="%d"' % self.height
1161
1164
1162 # External URLs and potentially local files are not embedded into the
1165 # External URLs and potentially local files are not embedded into the
1163 # notebook output.
1166 # notebook output.
1164 if not self.embed:
1167 if not self.embed:
1165 url = self.url if self.url is not None else self.filename
1168 url = self.url if self.url is not None else self.filename
1166 output = """<video src="{0}" {1} {2} {3}>
1169 output = """<video src="{0}" {1} {2} {3}>
1167 Your browser does not support the <code>video</code> element.
1170 Your browser does not support the <code>video</code> element.
1168 </video>""".format(url, self.html_attributes, width, height)
1171 </video>""".format(url, self.html_attributes, width, height)
1169 return output
1172 return output
1170
1173
1171 # Embedded videos are base64-encoded.
1174 # Embedded videos are base64-encoded.
1172 mimetype = self.mimetype
1175 mimetype = self.mimetype
1173 if self.filename is not None:
1176 if self.filename is not None:
1174 if not mimetype:
1177 if not mimetype:
1175 mimetype, _ = mimetypes.guess_type(self.filename)
1178 mimetype, _ = mimetypes.guess_type(self.filename)
1176
1179
1177 with open(self.filename, 'rb') as f:
1180 with open(self.filename, 'rb') as f:
1178 video = f.read()
1181 video = f.read()
1179 else:
1182 else:
1180 video = self.data
1183 video = self.data
1181 if isinstance(video, str):
1184 if isinstance(video, str):
1182 # unicode input is already b64-encoded
1185 # unicode input is already b64-encoded
1183 b64_video = video
1186 b64_video = video
1184 else:
1187 else:
1185 b64_video = b2a_base64(video).decode('ascii').rstrip()
1188 b64_video = b2a_base64(video).decode('ascii').rstrip()
1186
1189
1187 output = """<video {0} {1} {2}>
1190 output = """<video {0} {1} {2}>
1188 <source src="data:{3};base64,{4}" type="{3}">
1191 <source src="data:{3};base64,{4}" type="{3}">
1189 Your browser does not support the video tag.
1192 Your browser does not support the video tag.
1190 </video>""".format(self.html_attributes, width, height, mimetype, b64_video)
1193 </video>""".format(self.html_attributes, width, height, mimetype, b64_video)
1191 return output
1194 return output
1192
1195
1193 def reload(self):
1196 def reload(self):
1194 # TODO
1197 # TODO
1195 pass
1198 pass
1196
1199
1197
1200
1198 @skip_doctest
1201 @skip_doctest
1199 def set_matplotlib_formats(*formats, **kwargs):
1202 def set_matplotlib_formats(*formats, **kwargs):
1200 """
1203 """
1201 .. deprecated:: 7.23
1204 .. deprecated:: 7.23
1202
1205
1203 use `matplotlib_inline.backend_inline.set_matplotlib_formats()`
1206 use `matplotlib_inline.backend_inline.set_matplotlib_formats()`
1204
1207
1205 Select figure formats for the inline backend. Optionally pass quality for JPEG.
1208 Select figure formats for the inline backend. Optionally pass quality for JPEG.
1206
1209
1207 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1210 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1208
1211
1209 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1212 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1210
1213
1211 To set this in your config files use the following::
1214 To set this in your config files use the following::
1212
1215
1213 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1216 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1214 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1217 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1215
1218
1216 Parameters
1219 Parameters
1217 ----------
1220 ----------
1218 *formats : strs
1221 *formats : strs
1219 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1222 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1220 **kwargs
1223 **kwargs
1221 Keyword args will be relayed to ``figure.canvas.print_figure``.
1224 Keyword args will be relayed to ``figure.canvas.print_figure``.
1222 """
1225 """
1223 warnings.warn(
1226 warnings.warn(
1224 "`set_matplotlib_formats` is deprecated since IPython 7.23, directly "
1227 "`set_matplotlib_formats` is deprecated since IPython 7.23, directly "
1225 "use `matplotlib_inline.backend_inline.set_matplotlib_formats()`",
1228 "use `matplotlib_inline.backend_inline.set_matplotlib_formats()`",
1226 DeprecationWarning,
1229 DeprecationWarning,
1227 stacklevel=2,
1230 stacklevel=2,
1228 )
1231 )
1229
1232
1230 from matplotlib_inline.backend_inline import (
1233 from matplotlib_inline.backend_inline import (
1231 set_matplotlib_formats as set_matplotlib_formats_orig,
1234 set_matplotlib_formats as set_matplotlib_formats_orig,
1232 )
1235 )
1233
1236
1234 set_matplotlib_formats_orig(*formats, **kwargs)
1237 set_matplotlib_formats_orig(*formats, **kwargs)
1235
1238
1236 @skip_doctest
1239 @skip_doctest
1237 def set_matplotlib_close(close=True):
1240 def set_matplotlib_close(close=True):
1238 """
1241 """
1239 .. deprecated:: 7.23
1242 .. deprecated:: 7.23
1240
1243
1241 use `matplotlib_inline.backend_inline.set_matplotlib_close()`
1244 use `matplotlib_inline.backend_inline.set_matplotlib_close()`
1242
1245
1243 Set whether the inline backend closes all figures automatically or not.
1246 Set whether the inline backend closes all figures automatically or not.
1244
1247
1245 By default, the inline backend used in the IPython Notebook will close all
1248 By default, the inline backend used in the IPython Notebook will close all
1246 matplotlib figures automatically after each cell is run. This means that
1249 matplotlib figures automatically after each cell is run. This means that
1247 plots in different cells won't interfere. Sometimes, you may want to make
1250 plots in different cells won't interfere. Sometimes, you may want to make
1248 a plot in one cell and then refine it in later cells. This can be accomplished
1251 a plot in one cell and then refine it in later cells. This can be accomplished
1249 by::
1252 by::
1250
1253
1251 In [1]: set_matplotlib_close(False)
1254 In [1]: set_matplotlib_close(False)
1252
1255
1253 To set this in your config files use the following::
1256 To set this in your config files use the following::
1254
1257
1255 c.InlineBackend.close_figures = False
1258 c.InlineBackend.close_figures = False
1256
1259
1257 Parameters
1260 Parameters
1258 ----------
1261 ----------
1259 close : bool
1262 close : bool
1260 Should all matplotlib figures be automatically closed after each cell is
1263 Should all matplotlib figures be automatically closed after each cell is
1261 run?
1264 run?
1262 """
1265 """
1263 warnings.warn(
1266 warnings.warn(
1264 "`set_matplotlib_close` is deprecated since IPython 7.23, directly "
1267 "`set_matplotlib_close` is deprecated since IPython 7.23, directly "
1265 "use `matplotlib_inline.backend_inline.set_matplotlib_close()`",
1268 "use `matplotlib_inline.backend_inline.set_matplotlib_close()`",
1266 DeprecationWarning,
1269 DeprecationWarning,
1267 stacklevel=2,
1270 stacklevel=2,
1268 )
1271 )
1269
1272
1270 from matplotlib_inline.backend_inline import (
1273 from matplotlib_inline.backend_inline import (
1271 set_matplotlib_close as set_matplotlib_close_orig,
1274 set_matplotlib_close as set_matplotlib_close_orig,
1272 )
1275 )
1273
1276
1274 set_matplotlib_close_orig(close)
1277 set_matplotlib_close_orig(close)
@@ -1,3654 +1,3654 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Main IPython class."""
2 """Main IPython class."""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13
13
14 import abc
14 import abc
15 import ast
15 import ast
16 import atexit
16 import atexit
17 import builtins as builtin_mod
17 import builtins as builtin_mod
18 import functools
18 import functools
19 import inspect
19 import inspect
20 import os
20 import os
21 import re
21 import re
22 import runpy
22 import runpy
23 import sys
23 import sys
24 import tempfile
24 import tempfile
25 import traceback
25 import traceback
26 import types
26 import types
27 import subprocess
27 import subprocess
28 import warnings
28 import warnings
29 from io import open as io_open
29 from io import open as io_open
30
30
31 from pathlib import Path
31 from pathlib import Path
32 from pickleshare import PickleShareDB
32 from pickleshare import PickleShareDB
33
33
34 from traitlets.config.configurable import SingletonConfigurable
34 from traitlets.config.configurable import SingletonConfigurable
35 from traitlets.utils.importstring import import_item
35 from traitlets.utils.importstring import import_item
36 from IPython.core import oinspect
36 from IPython.core import oinspect
37 from IPython.core import magic
37 from IPython.core import magic
38 from IPython.core import page
38 from IPython.core import page
39 from IPython.core import prefilter
39 from IPython.core import prefilter
40 from IPython.core import ultratb
40 from IPython.core import ultratb
41 from IPython.core.alias import Alias, AliasManager
41 from IPython.core.alias import Alias, AliasManager
42 from IPython.core.autocall import ExitAutocall
42 from IPython.core.autocall import ExitAutocall
43 from IPython.core.builtin_trap import BuiltinTrap
43 from IPython.core.builtin_trap import BuiltinTrap
44 from IPython.core.events import EventManager, available_events
44 from IPython.core.events import EventManager, available_events
45 from IPython.core.compilerop import CachingCompiler, check_linecache_ipython
45 from IPython.core.compilerop import CachingCompiler, check_linecache_ipython
46 from IPython.core.debugger import InterruptiblePdb
46 from IPython.core.debugger import InterruptiblePdb
47 from IPython.core.display_trap import DisplayTrap
47 from IPython.core.display_trap import DisplayTrap
48 from IPython.core.displayhook import DisplayHook
48 from IPython.core.displayhook import DisplayHook
49 from IPython.core.displaypub import DisplayPublisher
49 from IPython.core.displaypub import DisplayPublisher
50 from IPython.core.error import InputRejected, UsageError
50 from IPython.core.error import InputRejected, UsageError
51 from IPython.core.extensions import ExtensionManager
51 from IPython.core.extensions import ExtensionManager
52 from IPython.core.formatters import DisplayFormatter
52 from IPython.core.formatters import DisplayFormatter
53 from IPython.core.history import HistoryManager
53 from IPython.core.history import HistoryManager
54 from IPython.core.inputtransformer2 import ESC_MAGIC, ESC_MAGIC2
54 from IPython.core.inputtransformer2 import ESC_MAGIC, ESC_MAGIC2
55 from IPython.core.logger import Logger
55 from IPython.core.logger import Logger
56 from IPython.core.macro import Macro
56 from IPython.core.macro import Macro
57 from IPython.core.payload import PayloadManager
57 from IPython.core.payload import PayloadManager
58 from IPython.core.prefilter import PrefilterManager
58 from IPython.core.prefilter import PrefilterManager
59 from IPython.core.profiledir import ProfileDir
59 from IPython.core.profiledir import ProfileDir
60 from IPython.core.usage import default_banner
60 from IPython.core.usage import default_banner
61 from IPython.display import display
61 from IPython.display import display
62 from IPython.testing.skipdoctest import skip_doctest
62 from IPython.testing.skipdoctest import skip_doctest
63 from IPython.utils import PyColorize
63 from IPython.utils import PyColorize
64 from IPython.utils import io
64 from IPython.utils import io
65 from IPython.utils import py3compat
65 from IPython.utils import py3compat
66 from IPython.utils import openpy
66 from IPython.utils import openpy
67 from IPython.utils.decorators import undoc
67 from IPython.utils.decorators import undoc
68 from IPython.utils.io import ask_yes_no
68 from IPython.utils.io import ask_yes_no
69 from IPython.utils.ipstruct import Struct
69 from IPython.utils.ipstruct import Struct
70 from IPython.paths import get_ipython_dir
70 from IPython.paths import get_ipython_dir
71 from IPython.utils.path import get_home_dir, get_py_filename, ensure_dir_exists
71 from IPython.utils.path import get_home_dir, get_py_filename, ensure_dir_exists
72 from IPython.utils.process import system, getoutput
72 from IPython.utils.process import system, getoutput
73 from IPython.utils.strdispatch import StrDispatch
73 from IPython.utils.strdispatch import StrDispatch
74 from IPython.utils.syspathcontext import prepended_to_syspath
74 from IPython.utils.syspathcontext import prepended_to_syspath
75 from IPython.utils.text import format_screen, LSString, SList, DollarFormatter
75 from IPython.utils.text import format_screen, LSString, SList, DollarFormatter
76 from IPython.utils.tempdir import TemporaryDirectory
76 from IPython.utils.tempdir import TemporaryDirectory
77 from traitlets import (
77 from traitlets import (
78 Integer, Bool, CaselessStrEnum, Enum, List, Dict, Unicode, Instance, Type,
78 Integer, Bool, CaselessStrEnum, Enum, List, Dict, Unicode, Instance, Type,
79 observe, default, validate, Any
79 observe, default, validate, Any
80 )
80 )
81 from warnings import warn
81 from warnings import warn
82 from logging import error
82 from logging import error
83 import IPython.core.hooks
83 import IPython.core.hooks
84
84
85 from typing import List as ListType, Tuple, Optional, Callable
85 from typing import List as ListType, Tuple, Optional, Callable
86 from ast import stmt
86 from ast import stmt
87
87
88 sphinxify: Optional[Callable]
88 sphinxify: Optional[Callable]
89
89
90 try:
90 try:
91 import docrepr.sphinxify as sphx
91 import docrepr.sphinxify as sphx
92
92
93 def sphinxify(oinfo):
93 def sphinxify(oinfo):
94 wrapped_docstring = sphx.wrap_main_docstring(oinfo)
94 wrapped_docstring = sphx.wrap_main_docstring(oinfo)
95
95
96 def sphinxify_docstring(docstring):
96 def sphinxify_docstring(docstring):
97 with TemporaryDirectory() as dirname:
97 with TemporaryDirectory() as dirname:
98 return {
98 return {
99 "text/html": sphx.sphinxify(wrapped_docstring, dirname),
99 "text/html": sphx.sphinxify(wrapped_docstring, dirname),
100 "text/plain": docstring,
100 "text/plain": docstring,
101 }
101 }
102
102
103 return sphinxify_docstring
103 return sphinxify_docstring
104 except ImportError:
104 except ImportError:
105 sphinxify = None
105 sphinxify = None
106
106
107
107
108 class ProvisionalWarning(DeprecationWarning):
108 class ProvisionalWarning(DeprecationWarning):
109 """
109 """
110 Warning class for unstable features
110 Warning class for unstable features
111 """
111 """
112 pass
112 pass
113
113
114 from ast import Module
114 from ast import Module
115
115
116 _assign_nodes = (ast.AugAssign, ast.AnnAssign, ast.Assign)
116 _assign_nodes = (ast.AugAssign, ast.AnnAssign, ast.Assign)
117 _single_targets_nodes = (ast.AugAssign, ast.AnnAssign)
117 _single_targets_nodes = (ast.AugAssign, ast.AnnAssign)
118
118
119 #-----------------------------------------------------------------------------
119 #-----------------------------------------------------------------------------
120 # Await Helpers
120 # Await Helpers
121 #-----------------------------------------------------------------------------
121 #-----------------------------------------------------------------------------
122
122
123 # we still need to run things using the asyncio eventloop, but there is no
123 # we still need to run things using the asyncio eventloop, but there is no
124 # async integration
124 # async integration
125 from .async_helpers import _asyncio_runner, _pseudo_sync_runner
125 from .async_helpers import _asyncio_runner, _pseudo_sync_runner
126 from .async_helpers import _curio_runner, _trio_runner, _should_be_async
126 from .async_helpers import _curio_runner, _trio_runner, _should_be_async
127
127
128 #-----------------------------------------------------------------------------
128 #-----------------------------------------------------------------------------
129 # Globals
129 # Globals
130 #-----------------------------------------------------------------------------
130 #-----------------------------------------------------------------------------
131
131
132 # compiled regexps for autoindent management
132 # compiled regexps for autoindent management
133 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
133 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
134
134
135 #-----------------------------------------------------------------------------
135 #-----------------------------------------------------------------------------
136 # Utilities
136 # Utilities
137 #-----------------------------------------------------------------------------
137 #-----------------------------------------------------------------------------
138
138
139 @undoc
139 @undoc
140 def softspace(file, newvalue):
140 def softspace(file, newvalue):
141 """Copied from code.py, to remove the dependency"""
141 """Copied from code.py, to remove the dependency"""
142
142
143 oldvalue = 0
143 oldvalue = 0
144 try:
144 try:
145 oldvalue = file.softspace
145 oldvalue = file.softspace
146 except AttributeError:
146 except AttributeError:
147 pass
147 pass
148 try:
148 try:
149 file.softspace = newvalue
149 file.softspace = newvalue
150 except (AttributeError, TypeError):
150 except (AttributeError, TypeError):
151 # "attribute-less object" or "read-only attributes"
151 # "attribute-less object" or "read-only attributes"
152 pass
152 pass
153 return oldvalue
153 return oldvalue
154
154
155 @undoc
155 @undoc
156 def no_op(*a, **kw):
156 def no_op(*a, **kw):
157 pass
157 pass
158
158
159
159
160 class SpaceInInput(Exception): pass
160 class SpaceInInput(Exception): pass
161
161
162
162
163 class SeparateUnicode(Unicode):
163 class SeparateUnicode(Unicode):
164 r"""A Unicode subclass to validate separate_in, separate_out, etc.
164 r"""A Unicode subclass to validate separate_in, separate_out, etc.
165
165
166 This is a Unicode based trait that converts '0'->'' and ``'\\n'->'\n'``.
166 This is a Unicode based trait that converts '0'->'' and ``'\\n'->'\n'``.
167 """
167 """
168
168
169 def validate(self, obj, value):
169 def validate(self, obj, value):
170 if value == '0': value = ''
170 if value == '0': value = ''
171 value = value.replace('\\n','\n')
171 value = value.replace('\\n','\n')
172 return super(SeparateUnicode, self).validate(obj, value)
172 return super(SeparateUnicode, self).validate(obj, value)
173
173
174
174
175 @undoc
175 @undoc
176 class DummyMod(object):
176 class DummyMod(object):
177 """A dummy module used for IPython's interactive module when
177 """A dummy module used for IPython's interactive module when
178 a namespace must be assigned to the module's __dict__."""
178 a namespace must be assigned to the module's __dict__."""
179 __spec__ = None
179 __spec__ = None
180
180
181
181
182 class ExecutionInfo(object):
182 class ExecutionInfo(object):
183 """The arguments used for a call to :meth:`InteractiveShell.run_cell`
183 """The arguments used for a call to :meth:`InteractiveShell.run_cell`
184
184
185 Stores information about what is going to happen.
185 Stores information about what is going to happen.
186 """
186 """
187 raw_cell = None
187 raw_cell = None
188 store_history = False
188 store_history = False
189 silent = False
189 silent = False
190 shell_futures = True
190 shell_futures = True
191
191
192 def __init__(self, raw_cell, store_history, silent, shell_futures):
192 def __init__(self, raw_cell, store_history, silent, shell_futures):
193 self.raw_cell = raw_cell
193 self.raw_cell = raw_cell
194 self.store_history = store_history
194 self.store_history = store_history
195 self.silent = silent
195 self.silent = silent
196 self.shell_futures = shell_futures
196 self.shell_futures = shell_futures
197
197
198 def __repr__(self):
198 def __repr__(self):
199 name = self.__class__.__qualname__
199 name = self.__class__.__qualname__
200 raw_cell = ((self.raw_cell[:50] + '..')
200 raw_cell = ((self.raw_cell[:50] + '..')
201 if len(self.raw_cell) > 50 else self.raw_cell)
201 if len(self.raw_cell) > 50 else self.raw_cell)
202 return '<%s object at %x, raw_cell="%s" store_history=%s silent=%s shell_futures=%s>' %\
202 return '<%s object at %x, raw_cell="%s" store_history=%s silent=%s shell_futures=%s>' %\
203 (name, id(self), raw_cell, self.store_history, self.silent, self.shell_futures)
203 (name, id(self), raw_cell, self.store_history, self.silent, self.shell_futures)
204
204
205
205
206 class ExecutionResult(object):
206 class ExecutionResult(object):
207 """The result of a call to :meth:`InteractiveShell.run_cell`
207 """The result of a call to :meth:`InteractiveShell.run_cell`
208
208
209 Stores information about what took place.
209 Stores information about what took place.
210 """
210 """
211 execution_count = None
211 execution_count = None
212 error_before_exec = None
212 error_before_exec = None
213 error_in_exec: Optional[BaseException] = None
213 error_in_exec: Optional[BaseException] = None
214 info = None
214 info = None
215 result = None
215 result = None
216
216
217 def __init__(self, info):
217 def __init__(self, info):
218 self.info = info
218 self.info = info
219
219
220 @property
220 @property
221 def success(self):
221 def success(self):
222 return (self.error_before_exec is None) and (self.error_in_exec is None)
222 return (self.error_before_exec is None) and (self.error_in_exec is None)
223
223
224 def raise_error(self):
224 def raise_error(self):
225 """Reraises error if `success` is `False`, otherwise does nothing"""
225 """Reraises error if `success` is `False`, otherwise does nothing"""
226 if self.error_before_exec is not None:
226 if self.error_before_exec is not None:
227 raise self.error_before_exec
227 raise self.error_before_exec
228 if self.error_in_exec is not None:
228 if self.error_in_exec is not None:
229 raise self.error_in_exec
229 raise self.error_in_exec
230
230
231 def __repr__(self):
231 def __repr__(self):
232 name = self.__class__.__qualname__
232 name = self.__class__.__qualname__
233 return '<%s object at %x, execution_count=%s error_before_exec=%s error_in_exec=%s info=%s result=%s>' %\
233 return '<%s object at %x, execution_count=%s error_before_exec=%s error_in_exec=%s info=%s result=%s>' %\
234 (name, id(self), self.execution_count, self.error_before_exec, self.error_in_exec, repr(self.info), repr(self.result))
234 (name, id(self), self.execution_count, self.error_before_exec, self.error_in_exec, repr(self.info), repr(self.result))
235
235
236
236
237 class InteractiveShell(SingletonConfigurable):
237 class InteractiveShell(SingletonConfigurable):
238 """An enhanced, interactive shell for Python."""
238 """An enhanced, interactive shell for Python."""
239
239
240 _instance = None
240 _instance = None
241
241
242 ast_transformers = List([], help=
242 ast_transformers = List([], help=
243 """
243 """
244 A list of ast.NodeTransformer subclass instances, which will be applied
244 A list of ast.NodeTransformer subclass instances, which will be applied
245 to user input before code is run.
245 to user input before code is run.
246 """
246 """
247 ).tag(config=True)
247 ).tag(config=True)
248
248
249 autocall = Enum((0,1,2), default_value=0, help=
249 autocall = Enum((0,1,2), default_value=0, help=
250 """
250 """
251 Make IPython automatically call any callable object even if you didn't
251 Make IPython automatically call any callable object even if you didn't
252 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
252 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
253 automatically. The value can be '0' to disable the feature, '1' for
253 automatically. The value can be '0' to disable the feature, '1' for
254 'smart' autocall, where it is not applied if there are no more
254 'smart' autocall, where it is not applied if there are no more
255 arguments on the line, and '2' for 'full' autocall, where all callable
255 arguments on the line, and '2' for 'full' autocall, where all callable
256 objects are automatically called (even if no arguments are present).
256 objects are automatically called (even if no arguments are present).
257 """
257 """
258 ).tag(config=True)
258 ).tag(config=True)
259
259
260 autoindent = Bool(True, help=
260 autoindent = Bool(True, help=
261 """
261 """
262 Autoindent IPython code entered interactively.
262 Autoindent IPython code entered interactively.
263 """
263 """
264 ).tag(config=True)
264 ).tag(config=True)
265
265
266 autoawait = Bool(True, help=
266 autoawait = Bool(True, help=
267 """
267 """
268 Automatically run await statement in the top level repl.
268 Automatically run await statement in the top level repl.
269 """
269 """
270 ).tag(config=True)
270 ).tag(config=True)
271
271
272 loop_runner_map ={
272 loop_runner_map ={
273 'asyncio':(_asyncio_runner, True),
273 'asyncio':(_asyncio_runner, True),
274 'curio':(_curio_runner, True),
274 'curio':(_curio_runner, True),
275 'trio':(_trio_runner, True),
275 'trio':(_trio_runner, True),
276 'sync': (_pseudo_sync_runner, False)
276 'sync': (_pseudo_sync_runner, False)
277 }
277 }
278
278
279 loop_runner = Any(default_value="IPython.core.interactiveshell._asyncio_runner",
279 loop_runner = Any(default_value="IPython.core.interactiveshell._asyncio_runner",
280 allow_none=True,
280 allow_none=True,
281 help="""Select the loop runner that will be used to execute top-level asynchronous code"""
281 help="""Select the loop runner that will be used to execute top-level asynchronous code"""
282 ).tag(config=True)
282 ).tag(config=True)
283
283
284 @default('loop_runner')
284 @default('loop_runner')
285 def _default_loop_runner(self):
285 def _default_loop_runner(self):
286 return import_item("IPython.core.interactiveshell._asyncio_runner")
286 return import_item("IPython.core.interactiveshell._asyncio_runner")
287
287
288 @validate('loop_runner')
288 @validate('loop_runner')
289 def _import_runner(self, proposal):
289 def _import_runner(self, proposal):
290 if isinstance(proposal.value, str):
290 if isinstance(proposal.value, str):
291 if proposal.value in self.loop_runner_map:
291 if proposal.value in self.loop_runner_map:
292 runner, autoawait = self.loop_runner_map[proposal.value]
292 runner, autoawait = self.loop_runner_map[proposal.value]
293 self.autoawait = autoawait
293 self.autoawait = autoawait
294 return runner
294 return runner
295 runner = import_item(proposal.value)
295 runner = import_item(proposal.value)
296 if not callable(runner):
296 if not callable(runner):
297 raise ValueError('loop_runner must be callable')
297 raise ValueError('loop_runner must be callable')
298 return runner
298 return runner
299 if not callable(proposal.value):
299 if not callable(proposal.value):
300 raise ValueError('loop_runner must be callable')
300 raise ValueError('loop_runner must be callable')
301 return proposal.value
301 return proposal.value
302
302
303 automagic = Bool(True, help=
303 automagic = Bool(True, help=
304 """
304 """
305 Enable magic commands to be called without the leading %.
305 Enable magic commands to be called without the leading %.
306 """
306 """
307 ).tag(config=True)
307 ).tag(config=True)
308
308
309 banner1 = Unicode(default_banner,
309 banner1 = Unicode(default_banner,
310 help="""The part of the banner to be printed before the profile"""
310 help="""The part of the banner to be printed before the profile"""
311 ).tag(config=True)
311 ).tag(config=True)
312 banner2 = Unicode('',
312 banner2 = Unicode('',
313 help="""The part of the banner to be printed after the profile"""
313 help="""The part of the banner to be printed after the profile"""
314 ).tag(config=True)
314 ).tag(config=True)
315
315
316 cache_size = Integer(1000, help=
316 cache_size = Integer(1000, help=
317 """
317 """
318 Set the size of the output cache. The default is 1000, you can
318 Set the size of the output cache. The default is 1000, you can
319 change it permanently in your config file. Setting it to 0 completely
319 change it permanently in your config file. Setting it to 0 completely
320 disables the caching system, and the minimum value accepted is 3 (if
320 disables the caching system, and the minimum value accepted is 3 (if
321 you provide a value less than 3, it is reset to 0 and a warning is
321 you provide a value less than 3, it is reset to 0 and a warning is
322 issued). This limit is defined because otherwise you'll spend more
322 issued). This limit is defined because otherwise you'll spend more
323 time re-flushing a too small cache than working
323 time re-flushing a too small cache than working
324 """
324 """
325 ).tag(config=True)
325 ).tag(config=True)
326 color_info = Bool(True, help=
326 color_info = Bool(True, help=
327 """
327 """
328 Use colors for displaying information about objects. Because this
328 Use colors for displaying information about objects. Because this
329 information is passed through a pager (like 'less'), and some pagers
329 information is passed through a pager (like 'less'), and some pagers
330 get confused with color codes, this capability can be turned off.
330 get confused with color codes, this capability can be turned off.
331 """
331 """
332 ).tag(config=True)
332 ).tag(config=True)
333 colors = CaselessStrEnum(('Neutral', 'NoColor','LightBG','Linux'),
333 colors = CaselessStrEnum(('Neutral', 'NoColor','LightBG','Linux'),
334 default_value='Neutral',
334 default_value='Neutral',
335 help="Set the color scheme (NoColor, Neutral, Linux, or LightBG)."
335 help="Set the color scheme (NoColor, Neutral, Linux, or LightBG)."
336 ).tag(config=True)
336 ).tag(config=True)
337 debug = Bool(False).tag(config=True)
337 debug = Bool(False).tag(config=True)
338 disable_failing_post_execute = Bool(False,
338 disable_failing_post_execute = Bool(False,
339 help="Don't call post-execute functions that have failed in the past."
339 help="Don't call post-execute functions that have failed in the past."
340 ).tag(config=True)
340 ).tag(config=True)
341 display_formatter = Instance(DisplayFormatter, allow_none=True)
341 display_formatter = Instance(DisplayFormatter, allow_none=True)
342 displayhook_class = Type(DisplayHook)
342 displayhook_class = Type(DisplayHook)
343 display_pub_class = Type(DisplayPublisher)
343 display_pub_class = Type(DisplayPublisher)
344 compiler_class = Type(CachingCompiler)
344 compiler_class = Type(CachingCompiler)
345
345
346 sphinxify_docstring = Bool(False, help=
346 sphinxify_docstring = Bool(False, help=
347 """
347 """
348 Enables rich html representation of docstrings. (This requires the
348 Enables rich html representation of docstrings. (This requires the
349 docrepr module).
349 docrepr module).
350 """).tag(config=True)
350 """).tag(config=True)
351
351
352 @observe("sphinxify_docstring")
352 @observe("sphinxify_docstring")
353 def _sphinxify_docstring_changed(self, change):
353 def _sphinxify_docstring_changed(self, change):
354 if change['new']:
354 if change['new']:
355 warn("`sphinxify_docstring` is provisional since IPython 5.0 and might change in future versions." , ProvisionalWarning)
355 warn("`sphinxify_docstring` is provisional since IPython 5.0 and might change in future versions." , ProvisionalWarning)
356
356
357 enable_html_pager = Bool(False, help=
357 enable_html_pager = Bool(False, help=
358 """
358 """
359 (Provisional API) enables html representation in mime bundles sent
359 (Provisional API) enables html representation in mime bundles sent
360 to pagers.
360 to pagers.
361 """).tag(config=True)
361 """).tag(config=True)
362
362
363 @observe("enable_html_pager")
363 @observe("enable_html_pager")
364 def _enable_html_pager_changed(self, change):
364 def _enable_html_pager_changed(self, change):
365 if change['new']:
365 if change['new']:
366 warn("`enable_html_pager` is provisional since IPython 5.0 and might change in future versions.", ProvisionalWarning)
366 warn("`enable_html_pager` is provisional since IPython 5.0 and might change in future versions.", ProvisionalWarning)
367
367
368 data_pub_class = None
368 data_pub_class = None
369
369
370 exit_now = Bool(False)
370 exit_now = Bool(False)
371 exiter = Instance(ExitAutocall)
371 exiter = Instance(ExitAutocall)
372 @default('exiter')
372 @default('exiter')
373 def _exiter_default(self):
373 def _exiter_default(self):
374 return ExitAutocall(self)
374 return ExitAutocall(self)
375 # Monotonically increasing execution counter
375 # Monotonically increasing execution counter
376 execution_count = Integer(1)
376 execution_count = Integer(1)
377 filename = Unicode("<ipython console>")
377 filename = Unicode("<ipython console>")
378 ipython_dir= Unicode('').tag(config=True) # Set to get_ipython_dir() in __init__
378 ipython_dir= Unicode('').tag(config=True) # Set to get_ipython_dir() in __init__
379
379
380 # Used to transform cells before running them, and check whether code is complete
380 # Used to transform cells before running them, and check whether code is complete
381 input_transformer_manager = Instance('IPython.core.inputtransformer2.TransformerManager',
381 input_transformer_manager = Instance('IPython.core.inputtransformer2.TransformerManager',
382 ())
382 ())
383
383
384 @property
384 @property
385 def input_transformers_cleanup(self):
385 def input_transformers_cleanup(self):
386 return self.input_transformer_manager.cleanup_transforms
386 return self.input_transformer_manager.cleanup_transforms
387
387
388 input_transformers_post = List([],
388 input_transformers_post = List([],
389 help="A list of string input transformers, to be applied after IPython's "
389 help="A list of string input transformers, to be applied after IPython's "
390 "own input transformations."
390 "own input transformations."
391 )
391 )
392
392
393 @property
393 @property
394 def input_splitter(self):
394 def input_splitter(self):
395 """Make this available for backward compatibility (pre-7.0 release) with existing code.
395 """Make this available for backward compatibility (pre-7.0 release) with existing code.
396
396
397 For example, ipykernel ipykernel currently uses
397 For example, ipykernel ipykernel currently uses
398 `shell.input_splitter.check_complete`
398 `shell.input_splitter.check_complete`
399 """
399 """
400 from warnings import warn
400 from warnings import warn
401 warn("`input_splitter` is deprecated since IPython 7.0, prefer `input_transformer_manager`.",
401 warn("`input_splitter` is deprecated since IPython 7.0, prefer `input_transformer_manager`.",
402 DeprecationWarning, stacklevel=2
402 DeprecationWarning, stacklevel=2
403 )
403 )
404 return self.input_transformer_manager
404 return self.input_transformer_manager
405
405
406 logstart = Bool(False, help=
406 logstart = Bool(False, help=
407 """
407 """
408 Start logging to the default log file in overwrite mode.
408 Start logging to the default log file in overwrite mode.
409 Use `logappend` to specify a log file to **append** logs to.
409 Use `logappend` to specify a log file to **append** logs to.
410 """
410 """
411 ).tag(config=True)
411 ).tag(config=True)
412 logfile = Unicode('', help=
412 logfile = Unicode('', help=
413 """
413 """
414 The name of the logfile to use.
414 The name of the logfile to use.
415 """
415 """
416 ).tag(config=True)
416 ).tag(config=True)
417 logappend = Unicode('', help=
417 logappend = Unicode('', help=
418 """
418 """
419 Start logging to the given file in append mode.
419 Start logging to the given file in append mode.
420 Use `logfile` to specify a log file to **overwrite** logs to.
420 Use `logfile` to specify a log file to **overwrite** logs to.
421 """
421 """
422 ).tag(config=True)
422 ).tag(config=True)
423 object_info_string_level = Enum((0,1,2), default_value=0,
423 object_info_string_level = Enum((0,1,2), default_value=0,
424 ).tag(config=True)
424 ).tag(config=True)
425 pdb = Bool(False, help=
425 pdb = Bool(False, help=
426 """
426 """
427 Automatically call the pdb debugger after every exception.
427 Automatically call the pdb debugger after every exception.
428 """
428 """
429 ).tag(config=True)
429 ).tag(config=True)
430 display_page = Bool(False,
430 display_page = Bool(False,
431 help="""If True, anything that would be passed to the pager
431 help="""If True, anything that would be passed to the pager
432 will be displayed as regular output instead."""
432 will be displayed as regular output instead."""
433 ).tag(config=True)
433 ).tag(config=True)
434
434
435
435
436 show_rewritten_input = Bool(True,
436 show_rewritten_input = Bool(True,
437 help="Show rewritten input, e.g. for autocall."
437 help="Show rewritten input, e.g. for autocall."
438 ).tag(config=True)
438 ).tag(config=True)
439
439
440 quiet = Bool(False).tag(config=True)
440 quiet = Bool(False).tag(config=True)
441
441
442 history_length = Integer(10000,
442 history_length = Integer(10000,
443 help='Total length of command history'
443 help='Total length of command history'
444 ).tag(config=True)
444 ).tag(config=True)
445
445
446 history_load_length = Integer(1000, help=
446 history_load_length = Integer(1000, help=
447 """
447 """
448 The number of saved history entries to be loaded
448 The number of saved history entries to be loaded
449 into the history buffer at startup.
449 into the history buffer at startup.
450 """
450 """
451 ).tag(config=True)
451 ).tag(config=True)
452
452
453 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none', 'last_expr_or_assign'],
453 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none', 'last_expr_or_assign'],
454 default_value='last_expr',
454 default_value='last_expr',
455 help="""
455 help="""
456 'all', 'last', 'last_expr' or 'none', 'last_expr_or_assign' specifying
456 'all', 'last', 'last_expr' or 'none', 'last_expr_or_assign' specifying
457 which nodes should be run interactively (displaying output from expressions).
457 which nodes should be run interactively (displaying output from expressions).
458 """
458 """
459 ).tag(config=True)
459 ).tag(config=True)
460
460
461 # TODO: this part of prompt management should be moved to the frontends.
461 # TODO: this part of prompt management should be moved to the frontends.
462 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
462 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
463 separate_in = SeparateUnicode('\n').tag(config=True)
463 separate_in = SeparateUnicode('\n').tag(config=True)
464 separate_out = SeparateUnicode('').tag(config=True)
464 separate_out = SeparateUnicode('').tag(config=True)
465 separate_out2 = SeparateUnicode('').tag(config=True)
465 separate_out2 = SeparateUnicode('').tag(config=True)
466 wildcards_case_sensitive = Bool(True).tag(config=True)
466 wildcards_case_sensitive = Bool(True).tag(config=True)
467 xmode = CaselessStrEnum(('Context', 'Plain', 'Verbose', 'Minimal'),
467 xmode = CaselessStrEnum(('Context', 'Plain', 'Verbose', 'Minimal'),
468 default_value='Context',
468 default_value='Context',
469 help="Switch modes for the IPython exception handlers."
469 help="Switch modes for the IPython exception handlers."
470 ).tag(config=True)
470 ).tag(config=True)
471
471
472 # Subcomponents of InteractiveShell
472 # Subcomponents of InteractiveShell
473 alias_manager = Instance('IPython.core.alias.AliasManager', allow_none=True)
473 alias_manager = Instance('IPython.core.alias.AliasManager', allow_none=True)
474 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
474 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
475 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap', allow_none=True)
475 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap', allow_none=True)
476 display_trap = Instance('IPython.core.display_trap.DisplayTrap', allow_none=True)
476 display_trap = Instance('IPython.core.display_trap.DisplayTrap', allow_none=True)
477 extension_manager = Instance('IPython.core.extensions.ExtensionManager', allow_none=True)
477 extension_manager = Instance('IPython.core.extensions.ExtensionManager', allow_none=True)
478 payload_manager = Instance('IPython.core.payload.PayloadManager', allow_none=True)
478 payload_manager = Instance('IPython.core.payload.PayloadManager', allow_none=True)
479 history_manager = Instance('IPython.core.history.HistoryAccessorBase', allow_none=True)
479 history_manager = Instance('IPython.core.history.HistoryAccessorBase', allow_none=True)
480 magics_manager = Instance('IPython.core.magic.MagicsManager', allow_none=True)
480 magics_manager = Instance('IPython.core.magic.MagicsManager', allow_none=True)
481
481
482 profile_dir = Instance('IPython.core.application.ProfileDir', allow_none=True)
482 profile_dir = Instance('IPython.core.application.ProfileDir', allow_none=True)
483 @property
483 @property
484 def profile(self):
484 def profile(self):
485 if self.profile_dir is not None:
485 if self.profile_dir is not None:
486 name = os.path.basename(self.profile_dir.location)
486 name = os.path.basename(self.profile_dir.location)
487 return name.replace('profile_','')
487 return name.replace('profile_','')
488
488
489
489
490 # Private interface
490 # Private interface
491 _post_execute = Dict()
491 _post_execute = Dict()
492
492
493 # Tracks any GUI loop loaded for pylab
493 # Tracks any GUI loop loaded for pylab
494 pylab_gui_select = None
494 pylab_gui_select = None
495
495
496 last_execution_succeeded = Bool(True, help='Did last executed command succeeded')
496 last_execution_succeeded = Bool(True, help='Did last executed command succeeded')
497
497
498 last_execution_result = Instance('IPython.core.interactiveshell.ExecutionResult', help='Result of executing the last command', allow_none=True)
498 last_execution_result = Instance('IPython.core.interactiveshell.ExecutionResult', help='Result of executing the last command', allow_none=True)
499
499
500 def __init__(self, ipython_dir=None, profile_dir=None,
500 def __init__(self, ipython_dir=None, profile_dir=None,
501 user_module=None, user_ns=None,
501 user_module=None, user_ns=None,
502 custom_exceptions=((), None), **kwargs):
502 custom_exceptions=((), None), **kwargs):
503
503
504 # This is where traits with a config_key argument are updated
504 # This is where traits with a config_key argument are updated
505 # from the values on config.
505 # from the values on config.
506 super(InteractiveShell, self).__init__(**kwargs)
506 super(InteractiveShell, self).__init__(**kwargs)
507 if 'PromptManager' in self.config:
507 if 'PromptManager' in self.config:
508 warn('As of IPython 5.0 `PromptManager` config will have no effect'
508 warn('As of IPython 5.0 `PromptManager` config will have no effect'
509 ' and has been replaced by TerminalInteractiveShell.prompts_class')
509 ' and has been replaced by TerminalInteractiveShell.prompts_class')
510 self.configurables = [self]
510 self.configurables = [self]
511
511
512 # These are relatively independent and stateless
512 # These are relatively independent and stateless
513 self.init_ipython_dir(ipython_dir)
513 self.init_ipython_dir(ipython_dir)
514 self.init_profile_dir(profile_dir)
514 self.init_profile_dir(profile_dir)
515 self.init_instance_attrs()
515 self.init_instance_attrs()
516 self.init_environment()
516 self.init_environment()
517
517
518 # Check if we're in a virtualenv, and set up sys.path.
518 # Check if we're in a virtualenv, and set up sys.path.
519 self.init_virtualenv()
519 self.init_virtualenv()
520
520
521 # Create namespaces (user_ns, user_global_ns, etc.)
521 # Create namespaces (user_ns, user_global_ns, etc.)
522 self.init_create_namespaces(user_module, user_ns)
522 self.init_create_namespaces(user_module, user_ns)
523 # This has to be done after init_create_namespaces because it uses
523 # This has to be done after init_create_namespaces because it uses
524 # something in self.user_ns, but before init_sys_modules, which
524 # something in self.user_ns, but before init_sys_modules, which
525 # is the first thing to modify sys.
525 # is the first thing to modify sys.
526 # TODO: When we override sys.stdout and sys.stderr before this class
526 # TODO: When we override sys.stdout and sys.stderr before this class
527 # is created, we are saving the overridden ones here. Not sure if this
527 # is created, we are saving the overridden ones here. Not sure if this
528 # is what we want to do.
528 # is what we want to do.
529 self.save_sys_module_state()
529 self.save_sys_module_state()
530 self.init_sys_modules()
530 self.init_sys_modules()
531
531
532 # While we're trying to have each part of the code directly access what
532 # While we're trying to have each part of the code directly access what
533 # it needs without keeping redundant references to objects, we have too
533 # it needs without keeping redundant references to objects, we have too
534 # much legacy code that expects ip.db to exist.
534 # much legacy code that expects ip.db to exist.
535 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
535 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
536
536
537 self.init_history()
537 self.init_history()
538 self.init_encoding()
538 self.init_encoding()
539 self.init_prefilter()
539 self.init_prefilter()
540
540
541 self.init_syntax_highlighting()
541 self.init_syntax_highlighting()
542 self.init_hooks()
542 self.init_hooks()
543 self.init_events()
543 self.init_events()
544 self.init_pushd_popd_magic()
544 self.init_pushd_popd_magic()
545 self.init_user_ns()
545 self.init_user_ns()
546 self.init_logger()
546 self.init_logger()
547 self.init_builtins()
547 self.init_builtins()
548
548
549 # The following was in post_config_initialization
549 # The following was in post_config_initialization
550 self.init_inspector()
550 self.init_inspector()
551 self.raw_input_original = input
551 self.raw_input_original = input
552 self.init_completer()
552 self.init_completer()
553 # TODO: init_io() needs to happen before init_traceback handlers
553 # TODO: init_io() needs to happen before init_traceback handlers
554 # because the traceback handlers hardcode the stdout/stderr streams.
554 # because the traceback handlers hardcode the stdout/stderr streams.
555 # This logic in in debugger.Pdb and should eventually be changed.
555 # This logic in in debugger.Pdb and should eventually be changed.
556 self.init_io()
556 self.init_io()
557 self.init_traceback_handlers(custom_exceptions)
557 self.init_traceback_handlers(custom_exceptions)
558 self.init_prompts()
558 self.init_prompts()
559 self.init_display_formatter()
559 self.init_display_formatter()
560 self.init_display_pub()
560 self.init_display_pub()
561 self.init_data_pub()
561 self.init_data_pub()
562 self.init_displayhook()
562 self.init_displayhook()
563 self.init_magics()
563 self.init_magics()
564 self.init_alias()
564 self.init_alias()
565 self.init_logstart()
565 self.init_logstart()
566 self.init_pdb()
566 self.init_pdb()
567 self.init_extension_manager()
567 self.init_extension_manager()
568 self.init_payload()
568 self.init_payload()
569 self.events.trigger('shell_initialized', self)
569 self.events.trigger('shell_initialized', self)
570 atexit.register(self.atexit_operations)
570 atexit.register(self.atexit_operations)
571
571
572 # The trio runner is used for running Trio in the foreground thread. It
572 # The trio runner is used for running Trio in the foreground thread. It
573 # is different from `_trio_runner(async_fn)` in `async_helpers.py`
573 # is different from `_trio_runner(async_fn)` in `async_helpers.py`
574 # which calls `trio.run()` for every cell. This runner runs all cells
574 # which calls `trio.run()` for every cell. This runner runs all cells
575 # inside a single Trio event loop. If used, it is set from
575 # inside a single Trio event loop. If used, it is set from
576 # `ipykernel.kernelapp`.
576 # `ipykernel.kernelapp`.
577 self.trio_runner = None
577 self.trio_runner = None
578
578
579 def get_ipython(self):
579 def get_ipython(self):
580 """Return the currently running IPython instance."""
580 """Return the currently running IPython instance."""
581 return self
581 return self
582
582
583 #-------------------------------------------------------------------------
583 #-------------------------------------------------------------------------
584 # Trait changed handlers
584 # Trait changed handlers
585 #-------------------------------------------------------------------------
585 #-------------------------------------------------------------------------
586 @observe('ipython_dir')
586 @observe('ipython_dir')
587 def _ipython_dir_changed(self, change):
587 def _ipython_dir_changed(self, change):
588 ensure_dir_exists(change['new'])
588 ensure_dir_exists(change['new'])
589
589
590 def set_autoindent(self,value=None):
590 def set_autoindent(self,value=None):
591 """Set the autoindent flag.
591 """Set the autoindent flag.
592
592
593 If called with no arguments, it acts as a toggle."""
593 If called with no arguments, it acts as a toggle."""
594 if value is None:
594 if value is None:
595 self.autoindent = not self.autoindent
595 self.autoindent = not self.autoindent
596 else:
596 else:
597 self.autoindent = value
597 self.autoindent = value
598
598
599 def set_trio_runner(self, tr):
599 def set_trio_runner(self, tr):
600 self.trio_runner = tr
600 self.trio_runner = tr
601
601
602 #-------------------------------------------------------------------------
602 #-------------------------------------------------------------------------
603 # init_* methods called by __init__
603 # init_* methods called by __init__
604 #-------------------------------------------------------------------------
604 #-------------------------------------------------------------------------
605
605
606 def init_ipython_dir(self, ipython_dir):
606 def init_ipython_dir(self, ipython_dir):
607 if ipython_dir is not None:
607 if ipython_dir is not None:
608 self.ipython_dir = ipython_dir
608 self.ipython_dir = ipython_dir
609 return
609 return
610
610
611 self.ipython_dir = get_ipython_dir()
611 self.ipython_dir = get_ipython_dir()
612
612
613 def init_profile_dir(self, profile_dir):
613 def init_profile_dir(self, profile_dir):
614 if profile_dir is not None:
614 if profile_dir is not None:
615 self.profile_dir = profile_dir
615 self.profile_dir = profile_dir
616 return
616 return
617 self.profile_dir = ProfileDir.create_profile_dir_by_name(
617 self.profile_dir = ProfileDir.create_profile_dir_by_name(
618 self.ipython_dir, "default"
618 self.ipython_dir, "default"
619 )
619 )
620
620
621 def init_instance_attrs(self):
621 def init_instance_attrs(self):
622 self.more = False
622 self.more = False
623
623
624 # command compiler
624 # command compiler
625 self.compile = self.compiler_class()
625 self.compile = self.compiler_class()
626
626
627 # Make an empty namespace, which extension writers can rely on both
627 # Make an empty namespace, which extension writers can rely on both
628 # existing and NEVER being used by ipython itself. This gives them a
628 # existing and NEVER being used by ipython itself. This gives them a
629 # convenient location for storing additional information and state
629 # convenient location for storing additional information and state
630 # their extensions may require, without fear of collisions with other
630 # their extensions may require, without fear of collisions with other
631 # ipython names that may develop later.
631 # ipython names that may develop later.
632 self.meta = Struct()
632 self.meta = Struct()
633
633
634 # Temporary files used for various purposes. Deleted at exit.
634 # Temporary files used for various purposes. Deleted at exit.
635 # The files here are stored with Path from Pathlib
635 # The files here are stored with Path from Pathlib
636 self.tempfiles = []
636 self.tempfiles = []
637 self.tempdirs = []
637 self.tempdirs = []
638
638
639 # keep track of where we started running (mainly for crash post-mortem)
639 # keep track of where we started running (mainly for crash post-mortem)
640 # This is not being used anywhere currently.
640 # This is not being used anywhere currently.
641 self.starting_dir = os.getcwd()
641 self.starting_dir = os.getcwd()
642
642
643 # Indentation management
643 # Indentation management
644 self.indent_current_nsp = 0
644 self.indent_current_nsp = 0
645
645
646 # Dict to track post-execution functions that have been registered
646 # Dict to track post-execution functions that have been registered
647 self._post_execute = {}
647 self._post_execute = {}
648
648
649 def init_environment(self):
649 def init_environment(self):
650 """Any changes we need to make to the user's environment."""
650 """Any changes we need to make to the user's environment."""
651 pass
651 pass
652
652
653 def init_encoding(self):
653 def init_encoding(self):
654 # Get system encoding at startup time. Certain terminals (like Emacs
654 # Get system encoding at startup time. Certain terminals (like Emacs
655 # under Win32 have it set to None, and we need to have a known valid
655 # under Win32 have it set to None, and we need to have a known valid
656 # encoding to use in the raw_input() method
656 # encoding to use in the raw_input() method
657 try:
657 try:
658 self.stdin_encoding = sys.stdin.encoding or 'ascii'
658 self.stdin_encoding = sys.stdin.encoding or 'ascii'
659 except AttributeError:
659 except AttributeError:
660 self.stdin_encoding = 'ascii'
660 self.stdin_encoding = 'ascii'
661
661
662
662
663 @observe('colors')
663 @observe('colors')
664 def init_syntax_highlighting(self, changes=None):
664 def init_syntax_highlighting(self, changes=None):
665 # Python source parser/formatter for syntax highlighting
665 # Python source parser/formatter for syntax highlighting
666 pyformat = PyColorize.Parser(style=self.colors, parent=self).format
666 pyformat = PyColorize.Parser(style=self.colors, parent=self).format
667 self.pycolorize = lambda src: pyformat(src,'str')
667 self.pycolorize = lambda src: pyformat(src,'str')
668
668
669 def refresh_style(self):
669 def refresh_style(self):
670 # No-op here, used in subclass
670 # No-op here, used in subclass
671 pass
671 pass
672
672
673 def init_pushd_popd_magic(self):
673 def init_pushd_popd_magic(self):
674 # for pushd/popd management
674 # for pushd/popd management
675 self.home_dir = get_home_dir()
675 self.home_dir = get_home_dir()
676
676
677 self.dir_stack = []
677 self.dir_stack = []
678
678
679 def init_logger(self):
679 def init_logger(self):
680 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
680 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
681 logmode='rotate')
681 logmode='rotate')
682
682
683 def init_logstart(self):
683 def init_logstart(self):
684 """Initialize logging in case it was requested at the command line.
684 """Initialize logging in case it was requested at the command line.
685 """
685 """
686 if self.logappend:
686 if self.logappend:
687 self.magic('logstart %s append' % self.logappend)
687 self.magic('logstart %s append' % self.logappend)
688 elif self.logfile:
688 elif self.logfile:
689 self.magic('logstart %s' % self.logfile)
689 self.magic('logstart %s' % self.logfile)
690 elif self.logstart:
690 elif self.logstart:
691 self.magic('logstart')
691 self.magic('logstart')
692
692
693
693
694 def init_builtins(self):
694 def init_builtins(self):
695 # A single, static flag that we set to True. Its presence indicates
695 # A single, static flag that we set to True. Its presence indicates
696 # that an IPython shell has been created, and we make no attempts at
696 # that an IPython shell has been created, and we make no attempts at
697 # removing on exit or representing the existence of more than one
697 # removing on exit or representing the existence of more than one
698 # IPython at a time.
698 # IPython at a time.
699 builtin_mod.__dict__['__IPYTHON__'] = True
699 builtin_mod.__dict__['__IPYTHON__'] = True
700 builtin_mod.__dict__['display'] = display
700 builtin_mod.__dict__['display'] = display
701
701
702 self.builtin_trap = BuiltinTrap(shell=self)
702 self.builtin_trap = BuiltinTrap(shell=self)
703
703
704 @observe('colors')
704 @observe('colors')
705 def init_inspector(self, changes=None):
705 def init_inspector(self, changes=None):
706 # Object inspector
706 # Object inspector
707 self.inspector = oinspect.Inspector(oinspect.InspectColors,
707 self.inspector = oinspect.Inspector(oinspect.InspectColors,
708 PyColorize.ANSICodeColors,
708 PyColorize.ANSICodeColors,
709 self.colors,
709 self.colors,
710 self.object_info_string_level)
710 self.object_info_string_level)
711
711
712 def init_io(self):
712 def init_io(self):
713 # implemented in subclasses, TerminalInteractiveShell does call
713 # implemented in subclasses, TerminalInteractiveShell does call
714 # colorama.init().
714 # colorama.init().
715 pass
715 pass
716
716
717 def init_prompts(self):
717 def init_prompts(self):
718 # Set system prompts, so that scripts can decide if they are running
718 # Set system prompts, so that scripts can decide if they are running
719 # interactively.
719 # interactively.
720 sys.ps1 = 'In : '
720 sys.ps1 = 'In : '
721 sys.ps2 = '...: '
721 sys.ps2 = '...: '
722 sys.ps3 = 'Out: '
722 sys.ps3 = 'Out: '
723
723
724 def init_display_formatter(self):
724 def init_display_formatter(self):
725 self.display_formatter = DisplayFormatter(parent=self)
725 self.display_formatter = DisplayFormatter(parent=self)
726 self.configurables.append(self.display_formatter)
726 self.configurables.append(self.display_formatter)
727
727
728 def init_display_pub(self):
728 def init_display_pub(self):
729 self.display_pub = self.display_pub_class(parent=self, shell=self)
729 self.display_pub = self.display_pub_class(parent=self, shell=self)
730 self.configurables.append(self.display_pub)
730 self.configurables.append(self.display_pub)
731
731
732 def init_data_pub(self):
732 def init_data_pub(self):
733 if not self.data_pub_class:
733 if not self.data_pub_class:
734 self.data_pub = None
734 self.data_pub = None
735 return
735 return
736 self.data_pub = self.data_pub_class(parent=self)
736 self.data_pub = self.data_pub_class(parent=self)
737 self.configurables.append(self.data_pub)
737 self.configurables.append(self.data_pub)
738
738
739 def init_displayhook(self):
739 def init_displayhook(self):
740 # Initialize displayhook, set in/out prompts and printing system
740 # Initialize displayhook, set in/out prompts and printing system
741 self.displayhook = self.displayhook_class(
741 self.displayhook = self.displayhook_class(
742 parent=self,
742 parent=self,
743 shell=self,
743 shell=self,
744 cache_size=self.cache_size,
744 cache_size=self.cache_size,
745 )
745 )
746 self.configurables.append(self.displayhook)
746 self.configurables.append(self.displayhook)
747 # This is a context manager that installs/revmoes the displayhook at
747 # This is a context manager that installs/revmoes the displayhook at
748 # the appropriate time.
748 # the appropriate time.
749 self.display_trap = DisplayTrap(hook=self.displayhook)
749 self.display_trap = DisplayTrap(hook=self.displayhook)
750
750
751 def init_virtualenv(self):
751 def init_virtualenv(self):
752 """Add the current virtualenv to sys.path so the user can import modules from it.
752 """Add the current virtualenv to sys.path so the user can import modules from it.
753 This isn't perfect: it doesn't use the Python interpreter with which the
753 This isn't perfect: it doesn't use the Python interpreter with which the
754 virtualenv was built, and it ignores the --no-site-packages option. A
754 virtualenv was built, and it ignores the --no-site-packages option. A
755 warning will appear suggesting the user installs IPython in the
755 warning will appear suggesting the user installs IPython in the
756 virtualenv, but for many cases, it probably works well enough.
756 virtualenv, but for many cases, it probably works well enough.
757
757
758 Adapted from code snippets online.
758 Adapted from code snippets online.
759
759
760 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
760 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
761 """
761 """
762 if 'VIRTUAL_ENV' not in os.environ:
762 if 'VIRTUAL_ENV' not in os.environ:
763 # Not in a virtualenv
763 # Not in a virtualenv
764 return
764 return
765 elif os.environ["VIRTUAL_ENV"] == "":
765 elif os.environ["VIRTUAL_ENV"] == "":
766 warn("Virtual env path set to '', please check if this is intended.")
766 warn("Virtual env path set to '', please check if this is intended.")
767 return
767 return
768
768
769 p = Path(sys.executable)
769 p = Path(sys.executable)
770 p_venv = Path(os.environ["VIRTUAL_ENV"])
770 p_venv = Path(os.environ["VIRTUAL_ENV"])
771
771
772 # fallback venv detection:
772 # fallback venv detection:
773 # stdlib venv may symlink sys.executable, so we can't use realpath.
773 # stdlib venv may symlink sys.executable, so we can't use realpath.
774 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
774 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
775 # So we just check every item in the symlink tree (generally <= 3)
775 # So we just check every item in the symlink tree (generally <= 3)
776 paths = [p]
776 paths = [p]
777 while p.is_symlink():
777 while p.is_symlink():
778 p = Path(os.readlink(p))
778 p = Path(os.readlink(p))
779 paths.append(p.resolve())
779 paths.append(p.resolve())
780
780
781 # In Cygwin paths like "c:\..." and '\cygdrive\c\...' are possible
781 # In Cygwin paths like "c:\..." and '\cygdrive\c\...' are possible
782 if p_venv.parts[1] == "cygdrive":
782 if p_venv.parts[1] == "cygdrive":
783 drive_name = p_venv.parts[2]
783 drive_name = p_venv.parts[2]
784 p_venv = (drive_name + ":/") / Path(*p_venv.parts[3:])
784 p_venv = (drive_name + ":/") / Path(*p_venv.parts[3:])
785
785
786 if any(p_venv == p.parents[1] for p in paths):
786 if any(p_venv == p.parents[1] for p in paths):
787 # Our exe is inside or has access to the virtualenv, don't need to do anything.
787 # Our exe is inside or has access to the virtualenv, don't need to do anything.
788 return
788 return
789
789
790 if sys.platform == "win32":
790 if sys.platform == "win32":
791 virtual_env = str(Path(os.environ["VIRTUAL_ENV"], "Lib", "site-packages"))
791 virtual_env = str(Path(os.environ["VIRTUAL_ENV"], "Lib", "site-packages"))
792 else:
792 else:
793 virtual_env_path = Path(
793 virtual_env_path = Path(
794 os.environ["VIRTUAL_ENV"], "lib", "python{}.{}", "site-packages"
794 os.environ["VIRTUAL_ENV"], "lib", "python{}.{}", "site-packages"
795 )
795 )
796 p_ver = sys.version_info[:2]
796 p_ver = sys.version_info[:2]
797
797
798 # Predict version from py[thon]-x.x in the $VIRTUAL_ENV
798 # Predict version from py[thon]-x.x in the $VIRTUAL_ENV
799 re_m = re.search(r"\bpy(?:thon)?([23])\.(\d+)\b", os.environ["VIRTUAL_ENV"])
799 re_m = re.search(r"\bpy(?:thon)?([23])\.(\d+)\b", os.environ["VIRTUAL_ENV"])
800 if re_m:
800 if re_m:
801 predicted_path = Path(str(virtual_env_path).format(*re_m.groups()))
801 predicted_path = Path(str(virtual_env_path).format(*re_m.groups()))
802 if predicted_path.exists():
802 if predicted_path.exists():
803 p_ver = re_m.groups()
803 p_ver = re_m.groups()
804
804
805 virtual_env = str(virtual_env_path).format(*p_ver)
805 virtual_env = str(virtual_env_path).format(*p_ver)
806
806
807 warn(
807 warn(
808 "Attempting to work in a virtualenv. If you encounter problems, "
808 "Attempting to work in a virtualenv. If you encounter problems, "
809 "please install IPython inside the virtualenv."
809 "please install IPython inside the virtualenv."
810 )
810 )
811 import site
811 import site
812 sys.path.insert(0, virtual_env)
812 sys.path.insert(0, virtual_env)
813 site.addsitedir(virtual_env)
813 site.addsitedir(virtual_env)
814
814
815 #-------------------------------------------------------------------------
815 #-------------------------------------------------------------------------
816 # Things related to injections into the sys module
816 # Things related to injections into the sys module
817 #-------------------------------------------------------------------------
817 #-------------------------------------------------------------------------
818
818
819 def save_sys_module_state(self):
819 def save_sys_module_state(self):
820 """Save the state of hooks in the sys module.
820 """Save the state of hooks in the sys module.
821
821
822 This has to be called after self.user_module is created.
822 This has to be called after self.user_module is created.
823 """
823 """
824 self._orig_sys_module_state = {'stdin': sys.stdin,
824 self._orig_sys_module_state = {'stdin': sys.stdin,
825 'stdout': sys.stdout,
825 'stdout': sys.stdout,
826 'stderr': sys.stderr,
826 'stderr': sys.stderr,
827 'excepthook': sys.excepthook}
827 'excepthook': sys.excepthook}
828 self._orig_sys_modules_main_name = self.user_module.__name__
828 self._orig_sys_modules_main_name = self.user_module.__name__
829 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
829 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
830
830
831 def restore_sys_module_state(self):
831 def restore_sys_module_state(self):
832 """Restore the state of the sys module."""
832 """Restore the state of the sys module."""
833 try:
833 try:
834 for k, v in self._orig_sys_module_state.items():
834 for k, v in self._orig_sys_module_state.items():
835 setattr(sys, k, v)
835 setattr(sys, k, v)
836 except AttributeError:
836 except AttributeError:
837 pass
837 pass
838 # Reset what what done in self.init_sys_modules
838 # Reset what what done in self.init_sys_modules
839 if self._orig_sys_modules_main_mod is not None:
839 if self._orig_sys_modules_main_mod is not None:
840 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
840 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
841
841
842 #-------------------------------------------------------------------------
842 #-------------------------------------------------------------------------
843 # Things related to the banner
843 # Things related to the banner
844 #-------------------------------------------------------------------------
844 #-------------------------------------------------------------------------
845
845
846 @property
846 @property
847 def banner(self):
847 def banner(self):
848 banner = self.banner1
848 banner = self.banner1
849 if self.profile and self.profile != 'default':
849 if self.profile and self.profile != 'default':
850 banner += '\nIPython profile: %s\n' % self.profile
850 banner += '\nIPython profile: %s\n' % self.profile
851 if self.banner2:
851 if self.banner2:
852 banner += '\n' + self.banner2
852 banner += '\n' + self.banner2
853 return banner
853 return banner
854
854
855 def show_banner(self, banner=None):
855 def show_banner(self, banner=None):
856 if banner is None:
856 if banner is None:
857 banner = self.banner
857 banner = self.banner
858 sys.stdout.write(banner)
858 sys.stdout.write(banner)
859
859
860 #-------------------------------------------------------------------------
860 #-------------------------------------------------------------------------
861 # Things related to hooks
861 # Things related to hooks
862 #-------------------------------------------------------------------------
862 #-------------------------------------------------------------------------
863
863
864 def init_hooks(self):
864 def init_hooks(self):
865 # hooks holds pointers used for user-side customizations
865 # hooks holds pointers used for user-side customizations
866 self.hooks = Struct()
866 self.hooks = Struct()
867
867
868 self.strdispatchers = {}
868 self.strdispatchers = {}
869
869
870 # Set all default hooks, defined in the IPython.hooks module.
870 # Set all default hooks, defined in the IPython.hooks module.
871 hooks = IPython.core.hooks
871 hooks = IPython.core.hooks
872 for hook_name in hooks.__all__:
872 for hook_name in hooks.__all__:
873 # default hooks have priority 100, i.e. low; user hooks should have
873 # default hooks have priority 100, i.e. low; user hooks should have
874 # 0-100 priority
874 # 0-100 priority
875 self.set_hook(hook_name, getattr(hooks, hook_name), 100)
875 self.set_hook(hook_name, getattr(hooks, hook_name), 100)
876
876
877 if self.display_page:
877 if self.display_page:
878 self.set_hook('show_in_pager', page.as_hook(page.display_page), 90)
878 self.set_hook('show_in_pager', page.as_hook(page.display_page), 90)
879
879
880 def set_hook(self, name, hook, priority=50, str_key=None, re_key=None):
880 def set_hook(self, name, hook, priority=50, str_key=None, re_key=None):
881 """set_hook(name,hook) -> sets an internal IPython hook.
881 """set_hook(name,hook) -> sets an internal IPython hook.
882
882
883 IPython exposes some of its internal API as user-modifiable hooks. By
883 IPython exposes some of its internal API as user-modifiable hooks. By
884 adding your function to one of these hooks, you can modify IPython's
884 adding your function to one of these hooks, you can modify IPython's
885 behavior to call at runtime your own routines."""
885 behavior to call at runtime your own routines."""
886
886
887 # At some point in the future, this should validate the hook before it
887 # At some point in the future, this should validate the hook before it
888 # accepts it. Probably at least check that the hook takes the number
888 # accepts it. Probably at least check that the hook takes the number
889 # of args it's supposed to.
889 # of args it's supposed to.
890
890
891 f = types.MethodType(hook,self)
891 f = types.MethodType(hook,self)
892
892
893 # check if the hook is for strdispatcher first
893 # check if the hook is for strdispatcher first
894 if str_key is not None:
894 if str_key is not None:
895 sdp = self.strdispatchers.get(name, StrDispatch())
895 sdp = self.strdispatchers.get(name, StrDispatch())
896 sdp.add_s(str_key, f, priority )
896 sdp.add_s(str_key, f, priority )
897 self.strdispatchers[name] = sdp
897 self.strdispatchers[name] = sdp
898 return
898 return
899 if re_key is not None:
899 if re_key is not None:
900 sdp = self.strdispatchers.get(name, StrDispatch())
900 sdp = self.strdispatchers.get(name, StrDispatch())
901 sdp.add_re(re.compile(re_key), f, priority )
901 sdp.add_re(re.compile(re_key), f, priority )
902 self.strdispatchers[name] = sdp
902 self.strdispatchers[name] = sdp
903 return
903 return
904
904
905 dp = getattr(self.hooks, name, None)
905 dp = getattr(self.hooks, name, None)
906 if name not in IPython.core.hooks.__all__:
906 if name not in IPython.core.hooks.__all__:
907 print("Warning! Hook '%s' is not one of %s" % \
907 print("Warning! Hook '%s' is not one of %s" % \
908 (name, IPython.core.hooks.__all__ ))
908 (name, IPython.core.hooks.__all__ ))
909
909
910 if name in IPython.core.hooks.deprecated:
910 if name in IPython.core.hooks.deprecated:
911 alternative = IPython.core.hooks.deprecated[name]
911 alternative = IPython.core.hooks.deprecated[name]
912 raise ValueError(
912 raise ValueError(
913 "Hook {} has been deprecated since IPython 5.0. Use {} instead.".format(
913 "Hook {} has been deprecated since IPython 5.0. Use {} instead.".format(
914 name, alternative
914 name, alternative
915 )
915 )
916 )
916 )
917
917
918 if not dp:
918 if not dp:
919 dp = IPython.core.hooks.CommandChainDispatcher()
919 dp = IPython.core.hooks.CommandChainDispatcher()
920
920
921 try:
921 try:
922 dp.add(f,priority)
922 dp.add(f,priority)
923 except AttributeError:
923 except AttributeError:
924 # it was not commandchain, plain old func - replace
924 # it was not commandchain, plain old func - replace
925 dp = f
925 dp = f
926
926
927 setattr(self.hooks,name, dp)
927 setattr(self.hooks,name, dp)
928
928
929 #-------------------------------------------------------------------------
929 #-------------------------------------------------------------------------
930 # Things related to events
930 # Things related to events
931 #-------------------------------------------------------------------------
931 #-------------------------------------------------------------------------
932
932
933 def init_events(self):
933 def init_events(self):
934 self.events = EventManager(self, available_events)
934 self.events = EventManager(self, available_events)
935
935
936 self.events.register("pre_execute", self._clear_warning_registry)
936 self.events.register("pre_execute", self._clear_warning_registry)
937
937
938 def register_post_execute(self, func):
938 def register_post_execute(self, func):
939 """DEPRECATED: Use ip.events.register('post_run_cell', func)
939 """DEPRECATED: Use ip.events.register('post_run_cell', func)
940
940
941 Register a function for calling after code execution.
941 Register a function for calling after code execution.
942 """
942 """
943 raise ValueError(
943 raise ValueError(
944 "ip.register_post_execute is deprecated since IPython 1.0, use "
944 "ip.register_post_execute is deprecated since IPython 1.0, use "
945 "ip.events.register('post_run_cell', func) instead."
945 "ip.events.register('post_run_cell', func) instead."
946 )
946 )
947
947
948 def _clear_warning_registry(self):
948 def _clear_warning_registry(self):
949 # clear the warning registry, so that different code blocks with
949 # clear the warning registry, so that different code blocks with
950 # overlapping line number ranges don't cause spurious suppression of
950 # overlapping line number ranges don't cause spurious suppression of
951 # warnings (see gh-6611 for details)
951 # warnings (see gh-6611 for details)
952 if "__warningregistry__" in self.user_global_ns:
952 if "__warningregistry__" in self.user_global_ns:
953 del self.user_global_ns["__warningregistry__"]
953 del self.user_global_ns["__warningregistry__"]
954
954
955 #-------------------------------------------------------------------------
955 #-------------------------------------------------------------------------
956 # Things related to the "main" module
956 # Things related to the "main" module
957 #-------------------------------------------------------------------------
957 #-------------------------------------------------------------------------
958
958
959 def new_main_mod(self, filename, modname):
959 def new_main_mod(self, filename, modname):
960 """Return a new 'main' module object for user code execution.
960 """Return a new 'main' module object for user code execution.
961
961
962 ``filename`` should be the path of the script which will be run in the
962 ``filename`` should be the path of the script which will be run in the
963 module. Requests with the same filename will get the same module, with
963 module. Requests with the same filename will get the same module, with
964 its namespace cleared.
964 its namespace cleared.
965
965
966 ``modname`` should be the module name - normally either '__main__' or
966 ``modname`` should be the module name - normally either '__main__' or
967 the basename of the file without the extension.
967 the basename of the file without the extension.
968
968
969 When scripts are executed via %run, we must keep a reference to their
969 When scripts are executed via %run, we must keep a reference to their
970 __main__ module around so that Python doesn't
970 __main__ module around so that Python doesn't
971 clear it, rendering references to module globals useless.
971 clear it, rendering references to module globals useless.
972
972
973 This method keeps said reference in a private dict, keyed by the
973 This method keeps said reference in a private dict, keyed by the
974 absolute path of the script. This way, for multiple executions of the
974 absolute path of the script. This way, for multiple executions of the
975 same script we only keep one copy of the namespace (the last one),
975 same script we only keep one copy of the namespace (the last one),
976 thus preventing memory leaks from old references while allowing the
976 thus preventing memory leaks from old references while allowing the
977 objects from the last execution to be accessible.
977 objects from the last execution to be accessible.
978 """
978 """
979 filename = os.path.abspath(filename)
979 filename = os.path.abspath(filename)
980 try:
980 try:
981 main_mod = self._main_mod_cache[filename]
981 main_mod = self._main_mod_cache[filename]
982 except KeyError:
982 except KeyError:
983 main_mod = self._main_mod_cache[filename] = types.ModuleType(
983 main_mod = self._main_mod_cache[filename] = types.ModuleType(
984 modname,
984 modname,
985 doc="Module created for script run in IPython")
985 doc="Module created for script run in IPython")
986 else:
986 else:
987 main_mod.__dict__.clear()
987 main_mod.__dict__.clear()
988 main_mod.__name__ = modname
988 main_mod.__name__ = modname
989
989
990 main_mod.__file__ = filename
990 main_mod.__file__ = filename
991 # It seems pydoc (and perhaps others) needs any module instance to
991 # It seems pydoc (and perhaps others) needs any module instance to
992 # implement a __nonzero__ method
992 # implement a __nonzero__ method
993 main_mod.__nonzero__ = lambda : True
993 main_mod.__nonzero__ = lambda : True
994
994
995 return main_mod
995 return main_mod
996
996
997 def clear_main_mod_cache(self):
997 def clear_main_mod_cache(self):
998 """Clear the cache of main modules.
998 """Clear the cache of main modules.
999
999
1000 Mainly for use by utilities like %reset.
1000 Mainly for use by utilities like %reset.
1001
1001
1002 Examples
1002 Examples
1003 --------
1003 --------
1004 In [15]: import IPython
1004 In [15]: import IPython
1005
1005
1006 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
1006 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
1007
1007
1008 In [17]: len(_ip._main_mod_cache) > 0
1008 In [17]: len(_ip._main_mod_cache) > 0
1009 Out[17]: True
1009 Out[17]: True
1010
1010
1011 In [18]: _ip.clear_main_mod_cache()
1011 In [18]: _ip.clear_main_mod_cache()
1012
1012
1013 In [19]: len(_ip._main_mod_cache) == 0
1013 In [19]: len(_ip._main_mod_cache) == 0
1014 Out[19]: True
1014 Out[19]: True
1015 """
1015 """
1016 self._main_mod_cache.clear()
1016 self._main_mod_cache.clear()
1017
1017
1018 #-------------------------------------------------------------------------
1018 #-------------------------------------------------------------------------
1019 # Things related to debugging
1019 # Things related to debugging
1020 #-------------------------------------------------------------------------
1020 #-------------------------------------------------------------------------
1021
1021
1022 def init_pdb(self):
1022 def init_pdb(self):
1023 # Set calling of pdb on exceptions
1023 # Set calling of pdb on exceptions
1024 # self.call_pdb is a property
1024 # self.call_pdb is a property
1025 self.call_pdb = self.pdb
1025 self.call_pdb = self.pdb
1026
1026
1027 def _get_call_pdb(self):
1027 def _get_call_pdb(self):
1028 return self._call_pdb
1028 return self._call_pdb
1029
1029
1030 def _set_call_pdb(self,val):
1030 def _set_call_pdb(self,val):
1031
1031
1032 if val not in (0,1,False,True):
1032 if val not in (0,1,False,True):
1033 raise ValueError('new call_pdb value must be boolean')
1033 raise ValueError('new call_pdb value must be boolean')
1034
1034
1035 # store value in instance
1035 # store value in instance
1036 self._call_pdb = val
1036 self._call_pdb = val
1037
1037
1038 # notify the actual exception handlers
1038 # notify the actual exception handlers
1039 self.InteractiveTB.call_pdb = val
1039 self.InteractiveTB.call_pdb = val
1040
1040
1041 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
1041 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
1042 'Control auto-activation of pdb at exceptions')
1042 'Control auto-activation of pdb at exceptions')
1043
1043
1044 def debugger(self,force=False):
1044 def debugger(self,force=False):
1045 """Call the pdb debugger.
1045 """Call the pdb debugger.
1046
1046
1047 Keywords:
1047 Keywords:
1048
1048
1049 - force(False): by default, this routine checks the instance call_pdb
1049 - force(False): by default, this routine checks the instance call_pdb
1050 flag and does not actually invoke the debugger if the flag is false.
1050 flag and does not actually invoke the debugger if the flag is false.
1051 The 'force' option forces the debugger to activate even if the flag
1051 The 'force' option forces the debugger to activate even if the flag
1052 is false.
1052 is false.
1053 """
1053 """
1054
1054
1055 if not (force or self.call_pdb):
1055 if not (force or self.call_pdb):
1056 return
1056 return
1057
1057
1058 if not hasattr(sys,'last_traceback'):
1058 if not hasattr(sys,'last_traceback'):
1059 error('No traceback has been produced, nothing to debug.')
1059 error('No traceback has been produced, nothing to debug.')
1060 return
1060 return
1061
1061
1062 self.InteractiveTB.debugger(force=True)
1062 self.InteractiveTB.debugger(force=True)
1063
1063
1064 #-------------------------------------------------------------------------
1064 #-------------------------------------------------------------------------
1065 # Things related to IPython's various namespaces
1065 # Things related to IPython's various namespaces
1066 #-------------------------------------------------------------------------
1066 #-------------------------------------------------------------------------
1067 default_user_namespaces = True
1067 default_user_namespaces = True
1068
1068
1069 def init_create_namespaces(self, user_module=None, user_ns=None):
1069 def init_create_namespaces(self, user_module=None, user_ns=None):
1070 # Create the namespace where the user will operate. user_ns is
1070 # Create the namespace where the user will operate. user_ns is
1071 # normally the only one used, and it is passed to the exec calls as
1071 # normally the only one used, and it is passed to the exec calls as
1072 # the locals argument. But we do carry a user_global_ns namespace
1072 # the locals argument. But we do carry a user_global_ns namespace
1073 # given as the exec 'globals' argument, This is useful in embedding
1073 # given as the exec 'globals' argument, This is useful in embedding
1074 # situations where the ipython shell opens in a context where the
1074 # situations where the ipython shell opens in a context where the
1075 # distinction between locals and globals is meaningful. For
1075 # distinction between locals and globals is meaningful. For
1076 # non-embedded contexts, it is just the same object as the user_ns dict.
1076 # non-embedded contexts, it is just the same object as the user_ns dict.
1077
1077
1078 # FIXME. For some strange reason, __builtins__ is showing up at user
1078 # FIXME. For some strange reason, __builtins__ is showing up at user
1079 # level as a dict instead of a module. This is a manual fix, but I
1079 # level as a dict instead of a module. This is a manual fix, but I
1080 # should really track down where the problem is coming from. Alex
1080 # should really track down where the problem is coming from. Alex
1081 # Schmolck reported this problem first.
1081 # Schmolck reported this problem first.
1082
1082
1083 # A useful post by Alex Martelli on this topic:
1083 # A useful post by Alex Martelli on this topic:
1084 # Re: inconsistent value from __builtins__
1084 # Re: inconsistent value from __builtins__
1085 # Von: Alex Martelli <aleaxit@yahoo.com>
1085 # Von: Alex Martelli <aleaxit@yahoo.com>
1086 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
1086 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
1087 # Gruppen: comp.lang.python
1087 # Gruppen: comp.lang.python
1088
1088
1089 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
1089 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
1090 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
1090 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
1091 # > <type 'dict'>
1091 # > <type 'dict'>
1092 # > >>> print type(__builtins__)
1092 # > >>> print type(__builtins__)
1093 # > <type 'module'>
1093 # > <type 'module'>
1094 # > Is this difference in return value intentional?
1094 # > Is this difference in return value intentional?
1095
1095
1096 # Well, it's documented that '__builtins__' can be either a dictionary
1096 # Well, it's documented that '__builtins__' can be either a dictionary
1097 # or a module, and it's been that way for a long time. Whether it's
1097 # or a module, and it's been that way for a long time. Whether it's
1098 # intentional (or sensible), I don't know. In any case, the idea is
1098 # intentional (or sensible), I don't know. In any case, the idea is
1099 # that if you need to access the built-in namespace directly, you
1099 # that if you need to access the built-in namespace directly, you
1100 # should start with "import __builtin__" (note, no 's') which will
1100 # should start with "import __builtin__" (note, no 's') which will
1101 # definitely give you a module. Yeah, it's somewhat confusing:-(.
1101 # definitely give you a module. Yeah, it's somewhat confusing:-(.
1102
1102
1103 # These routines return a properly built module and dict as needed by
1103 # These routines return a properly built module and dict as needed by
1104 # the rest of the code, and can also be used by extension writers to
1104 # the rest of the code, and can also be used by extension writers to
1105 # generate properly initialized namespaces.
1105 # generate properly initialized namespaces.
1106 if (user_ns is not None) or (user_module is not None):
1106 if (user_ns is not None) or (user_module is not None):
1107 self.default_user_namespaces = False
1107 self.default_user_namespaces = False
1108 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
1108 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
1109
1109
1110 # A record of hidden variables we have added to the user namespace, so
1110 # A record of hidden variables we have added to the user namespace, so
1111 # we can list later only variables defined in actual interactive use.
1111 # we can list later only variables defined in actual interactive use.
1112 self.user_ns_hidden = {}
1112 self.user_ns_hidden = {}
1113
1113
1114 # Now that FakeModule produces a real module, we've run into a nasty
1114 # Now that FakeModule produces a real module, we've run into a nasty
1115 # problem: after script execution (via %run), the module where the user
1115 # problem: after script execution (via %run), the module where the user
1116 # code ran is deleted. Now that this object is a true module (needed
1116 # code ran is deleted. Now that this object is a true module (needed
1117 # so doctest and other tools work correctly), the Python module
1117 # so doctest and other tools work correctly), the Python module
1118 # teardown mechanism runs over it, and sets to None every variable
1118 # teardown mechanism runs over it, and sets to None every variable
1119 # present in that module. Top-level references to objects from the
1119 # present in that module. Top-level references to objects from the
1120 # script survive, because the user_ns is updated with them. However,
1120 # script survive, because the user_ns is updated with them. However,
1121 # calling functions defined in the script that use other things from
1121 # calling functions defined in the script that use other things from
1122 # the script will fail, because the function's closure had references
1122 # the script will fail, because the function's closure had references
1123 # to the original objects, which are now all None. So we must protect
1123 # to the original objects, which are now all None. So we must protect
1124 # these modules from deletion by keeping a cache.
1124 # these modules from deletion by keeping a cache.
1125 #
1125 #
1126 # To avoid keeping stale modules around (we only need the one from the
1126 # To avoid keeping stale modules around (we only need the one from the
1127 # last run), we use a dict keyed with the full path to the script, so
1127 # last run), we use a dict keyed with the full path to the script, so
1128 # only the last version of the module is held in the cache. Note,
1128 # only the last version of the module is held in the cache. Note,
1129 # however, that we must cache the module *namespace contents* (their
1129 # however, that we must cache the module *namespace contents* (their
1130 # __dict__). Because if we try to cache the actual modules, old ones
1130 # __dict__). Because if we try to cache the actual modules, old ones
1131 # (uncached) could be destroyed while still holding references (such as
1131 # (uncached) could be destroyed while still holding references (such as
1132 # those held by GUI objects that tend to be long-lived)>
1132 # those held by GUI objects that tend to be long-lived)>
1133 #
1133 #
1134 # The %reset command will flush this cache. See the cache_main_mod()
1134 # The %reset command will flush this cache. See the cache_main_mod()
1135 # and clear_main_mod_cache() methods for details on use.
1135 # and clear_main_mod_cache() methods for details on use.
1136
1136
1137 # This is the cache used for 'main' namespaces
1137 # This is the cache used for 'main' namespaces
1138 self._main_mod_cache = {}
1138 self._main_mod_cache = {}
1139
1139
1140 # A table holding all the namespaces IPython deals with, so that
1140 # A table holding all the namespaces IPython deals with, so that
1141 # introspection facilities can search easily.
1141 # introspection facilities can search easily.
1142 self.ns_table = {'user_global':self.user_module.__dict__,
1142 self.ns_table = {'user_global':self.user_module.__dict__,
1143 'user_local':self.user_ns,
1143 'user_local':self.user_ns,
1144 'builtin':builtin_mod.__dict__
1144 'builtin':builtin_mod.__dict__
1145 }
1145 }
1146
1146
1147 @property
1147 @property
1148 def user_global_ns(self):
1148 def user_global_ns(self):
1149 return self.user_module.__dict__
1149 return self.user_module.__dict__
1150
1150
1151 def prepare_user_module(self, user_module=None, user_ns=None):
1151 def prepare_user_module(self, user_module=None, user_ns=None):
1152 """Prepare the module and namespace in which user code will be run.
1152 """Prepare the module and namespace in which user code will be run.
1153
1153
1154 When IPython is started normally, both parameters are None: a new module
1154 When IPython is started normally, both parameters are None: a new module
1155 is created automatically, and its __dict__ used as the namespace.
1155 is created automatically, and its __dict__ used as the namespace.
1156
1156
1157 If only user_module is provided, its __dict__ is used as the namespace.
1157 If only user_module is provided, its __dict__ is used as the namespace.
1158 If only user_ns is provided, a dummy module is created, and user_ns
1158 If only user_ns is provided, a dummy module is created, and user_ns
1159 becomes the global namespace. If both are provided (as they may be
1159 becomes the global namespace. If both are provided (as they may be
1160 when embedding), user_ns is the local namespace, and user_module
1160 when embedding), user_ns is the local namespace, and user_module
1161 provides the global namespace.
1161 provides the global namespace.
1162
1162
1163 Parameters
1163 Parameters
1164 ----------
1164 ----------
1165 user_module : module, optional
1165 user_module : module, optional
1166 The current user module in which IPython is being run. If None,
1166 The current user module in which IPython is being run. If None,
1167 a clean module will be created.
1167 a clean module will be created.
1168 user_ns : dict, optional
1168 user_ns : dict, optional
1169 A namespace in which to run interactive commands.
1169 A namespace in which to run interactive commands.
1170
1170
1171 Returns
1171 Returns
1172 -------
1172 -------
1173 A tuple of user_module and user_ns, each properly initialised.
1173 A tuple of user_module and user_ns, each properly initialised.
1174 """
1174 """
1175 if user_module is None and user_ns is not None:
1175 if user_module is None and user_ns is not None:
1176 user_ns.setdefault("__name__", "__main__")
1176 user_ns.setdefault("__name__", "__main__")
1177 user_module = DummyMod()
1177 user_module = DummyMod()
1178 user_module.__dict__ = user_ns
1178 user_module.__dict__ = user_ns
1179
1179
1180 if user_module is None:
1180 if user_module is None:
1181 user_module = types.ModuleType("__main__",
1181 user_module = types.ModuleType("__main__",
1182 doc="Automatically created module for IPython interactive environment")
1182 doc="Automatically created module for IPython interactive environment")
1183
1183
1184 # We must ensure that __builtin__ (without the final 's') is always
1184 # We must ensure that __builtin__ (without the final 's') is always
1185 # available and pointing to the __builtin__ *module*. For more details:
1185 # available and pointing to the __builtin__ *module*. For more details:
1186 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1186 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1187 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1187 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1188 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1188 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1189
1189
1190 if user_ns is None:
1190 if user_ns is None:
1191 user_ns = user_module.__dict__
1191 user_ns = user_module.__dict__
1192
1192
1193 return user_module, user_ns
1193 return user_module, user_ns
1194
1194
1195 def init_sys_modules(self):
1195 def init_sys_modules(self):
1196 # We need to insert into sys.modules something that looks like a
1196 # We need to insert into sys.modules something that looks like a
1197 # module but which accesses the IPython namespace, for shelve and
1197 # module but which accesses the IPython namespace, for shelve and
1198 # pickle to work interactively. Normally they rely on getting
1198 # pickle to work interactively. Normally they rely on getting
1199 # everything out of __main__, but for embedding purposes each IPython
1199 # everything out of __main__, but for embedding purposes each IPython
1200 # instance has its own private namespace, so we can't go shoving
1200 # instance has its own private namespace, so we can't go shoving
1201 # everything into __main__.
1201 # everything into __main__.
1202
1202
1203 # note, however, that we should only do this for non-embedded
1203 # note, however, that we should only do this for non-embedded
1204 # ipythons, which really mimic the __main__.__dict__ with their own
1204 # ipythons, which really mimic the __main__.__dict__ with their own
1205 # namespace. Embedded instances, on the other hand, should not do
1205 # namespace. Embedded instances, on the other hand, should not do
1206 # this because they need to manage the user local/global namespaces
1206 # this because they need to manage the user local/global namespaces
1207 # only, but they live within a 'normal' __main__ (meaning, they
1207 # only, but they live within a 'normal' __main__ (meaning, they
1208 # shouldn't overtake the execution environment of the script they're
1208 # shouldn't overtake the execution environment of the script they're
1209 # embedded in).
1209 # embedded in).
1210
1210
1211 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1211 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1212 main_name = self.user_module.__name__
1212 main_name = self.user_module.__name__
1213 sys.modules[main_name] = self.user_module
1213 sys.modules[main_name] = self.user_module
1214
1214
1215 def init_user_ns(self):
1215 def init_user_ns(self):
1216 """Initialize all user-visible namespaces to their minimum defaults.
1216 """Initialize all user-visible namespaces to their minimum defaults.
1217
1217
1218 Certain history lists are also initialized here, as they effectively
1218 Certain history lists are also initialized here, as they effectively
1219 act as user namespaces.
1219 act as user namespaces.
1220
1220
1221 Notes
1221 Notes
1222 -----
1222 -----
1223 All data structures here are only filled in, they are NOT reset by this
1223 All data structures here are only filled in, they are NOT reset by this
1224 method. If they were not empty before, data will simply be added to
1224 method. If they were not empty before, data will simply be added to
1225 them.
1225 them.
1226 """
1226 """
1227 # This function works in two parts: first we put a few things in
1227 # This function works in two parts: first we put a few things in
1228 # user_ns, and we sync that contents into user_ns_hidden so that these
1228 # user_ns, and we sync that contents into user_ns_hidden so that these
1229 # initial variables aren't shown by %who. After the sync, we add the
1229 # initial variables aren't shown by %who. After the sync, we add the
1230 # rest of what we *do* want the user to see with %who even on a new
1230 # rest of what we *do* want the user to see with %who even on a new
1231 # session (probably nothing, so they really only see their own stuff)
1231 # session (probably nothing, so they really only see their own stuff)
1232
1232
1233 # The user dict must *always* have a __builtin__ reference to the
1233 # The user dict must *always* have a __builtin__ reference to the
1234 # Python standard __builtin__ namespace, which must be imported.
1234 # Python standard __builtin__ namespace, which must be imported.
1235 # This is so that certain operations in prompt evaluation can be
1235 # This is so that certain operations in prompt evaluation can be
1236 # reliably executed with builtins. Note that we can NOT use
1236 # reliably executed with builtins. Note that we can NOT use
1237 # __builtins__ (note the 's'), because that can either be a dict or a
1237 # __builtins__ (note the 's'), because that can either be a dict or a
1238 # module, and can even mutate at runtime, depending on the context
1238 # module, and can even mutate at runtime, depending on the context
1239 # (Python makes no guarantees on it). In contrast, __builtin__ is
1239 # (Python makes no guarantees on it). In contrast, __builtin__ is
1240 # always a module object, though it must be explicitly imported.
1240 # always a module object, though it must be explicitly imported.
1241
1241
1242 # For more details:
1242 # For more details:
1243 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1243 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1244 ns = {}
1244 ns = {}
1245
1245
1246 # make global variables for user access to the histories
1246 # make global variables for user access to the histories
1247 ns['_ih'] = self.history_manager.input_hist_parsed
1247 ns['_ih'] = self.history_manager.input_hist_parsed
1248 ns['_oh'] = self.history_manager.output_hist
1248 ns['_oh'] = self.history_manager.output_hist
1249 ns['_dh'] = self.history_manager.dir_hist
1249 ns['_dh'] = self.history_manager.dir_hist
1250
1250
1251 # user aliases to input and output histories. These shouldn't show up
1251 # user aliases to input and output histories. These shouldn't show up
1252 # in %who, as they can have very large reprs.
1252 # in %who, as they can have very large reprs.
1253 ns['In'] = self.history_manager.input_hist_parsed
1253 ns['In'] = self.history_manager.input_hist_parsed
1254 ns['Out'] = self.history_manager.output_hist
1254 ns['Out'] = self.history_manager.output_hist
1255
1255
1256 # Store myself as the public api!!!
1256 # Store myself as the public api!!!
1257 ns['get_ipython'] = self.get_ipython
1257 ns['get_ipython'] = self.get_ipython
1258
1258
1259 ns['exit'] = self.exiter
1259 ns['exit'] = self.exiter
1260 ns['quit'] = self.exiter
1260 ns['quit'] = self.exiter
1261
1261
1262 # Sync what we've added so far to user_ns_hidden so these aren't seen
1262 # Sync what we've added so far to user_ns_hidden so these aren't seen
1263 # by %who
1263 # by %who
1264 self.user_ns_hidden.update(ns)
1264 self.user_ns_hidden.update(ns)
1265
1265
1266 # Anything put into ns now would show up in %who. Think twice before
1266 # Anything put into ns now would show up in %who. Think twice before
1267 # putting anything here, as we really want %who to show the user their
1267 # putting anything here, as we really want %who to show the user their
1268 # stuff, not our variables.
1268 # stuff, not our variables.
1269
1269
1270 # Finally, update the real user's namespace
1270 # Finally, update the real user's namespace
1271 self.user_ns.update(ns)
1271 self.user_ns.update(ns)
1272
1272
1273 @property
1273 @property
1274 def all_ns_refs(self):
1274 def all_ns_refs(self):
1275 """Get a list of references to all the namespace dictionaries in which
1275 """Get a list of references to all the namespace dictionaries in which
1276 IPython might store a user-created object.
1276 IPython might store a user-created object.
1277
1277
1278 Note that this does not include the displayhook, which also caches
1278 Note that this does not include the displayhook, which also caches
1279 objects from the output."""
1279 objects from the output."""
1280 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1280 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1281 [m.__dict__ for m in self._main_mod_cache.values()]
1281 [m.__dict__ for m in self._main_mod_cache.values()]
1282
1282
1283 def reset(self, new_session=True, aggressive=False):
1283 def reset(self, new_session=True, aggressive=False):
1284 """Clear all internal namespaces, and attempt to release references to
1284 """Clear all internal namespaces, and attempt to release references to
1285 user objects.
1285 user objects.
1286
1286
1287 If new_session is True, a new history session will be opened.
1287 If new_session is True, a new history session will be opened.
1288 """
1288 """
1289 # Clear histories
1289 # Clear histories
1290 self.history_manager.reset(new_session)
1290 self.history_manager.reset(new_session)
1291 # Reset counter used to index all histories
1291 # Reset counter used to index all histories
1292 if new_session:
1292 if new_session:
1293 self.execution_count = 1
1293 self.execution_count = 1
1294
1294
1295 # Reset last execution result
1295 # Reset last execution result
1296 self.last_execution_succeeded = True
1296 self.last_execution_succeeded = True
1297 self.last_execution_result = None
1297 self.last_execution_result = None
1298
1298
1299 # Flush cached output items
1299 # Flush cached output items
1300 if self.displayhook.do_full_cache:
1300 if self.displayhook.do_full_cache:
1301 self.displayhook.flush()
1301 self.displayhook.flush()
1302
1302
1303 # The main execution namespaces must be cleared very carefully,
1303 # The main execution namespaces must be cleared very carefully,
1304 # skipping the deletion of the builtin-related keys, because doing so
1304 # skipping the deletion of the builtin-related keys, because doing so
1305 # would cause errors in many object's __del__ methods.
1305 # would cause errors in many object's __del__ methods.
1306 if self.user_ns is not self.user_global_ns:
1306 if self.user_ns is not self.user_global_ns:
1307 self.user_ns.clear()
1307 self.user_ns.clear()
1308 ns = self.user_global_ns
1308 ns = self.user_global_ns
1309 drop_keys = set(ns.keys())
1309 drop_keys = set(ns.keys())
1310 drop_keys.discard('__builtin__')
1310 drop_keys.discard('__builtin__')
1311 drop_keys.discard('__builtins__')
1311 drop_keys.discard('__builtins__')
1312 drop_keys.discard('__name__')
1312 drop_keys.discard('__name__')
1313 for k in drop_keys:
1313 for k in drop_keys:
1314 del ns[k]
1314 del ns[k]
1315
1315
1316 self.user_ns_hidden.clear()
1316 self.user_ns_hidden.clear()
1317
1317
1318 # Restore the user namespaces to minimal usability
1318 # Restore the user namespaces to minimal usability
1319 self.init_user_ns()
1319 self.init_user_ns()
1320 if aggressive and not hasattr(self, "_sys_modules_keys"):
1320 if aggressive and not hasattr(self, "_sys_modules_keys"):
1321 print("Cannot restore sys.module, no snapshot")
1321 print("Cannot restore sys.module, no snapshot")
1322 elif aggressive:
1322 elif aggressive:
1323 print("culling sys module...")
1323 print("culling sys module...")
1324 current_keys = set(sys.modules.keys())
1324 current_keys = set(sys.modules.keys())
1325 for k in current_keys - self._sys_modules_keys:
1325 for k in current_keys - self._sys_modules_keys:
1326 if k.startswith("multiprocessing"):
1326 if k.startswith("multiprocessing"):
1327 continue
1327 continue
1328 del sys.modules[k]
1328 del sys.modules[k]
1329
1329
1330 # Restore the default and user aliases
1330 # Restore the default and user aliases
1331 self.alias_manager.clear_aliases()
1331 self.alias_manager.clear_aliases()
1332 self.alias_manager.init_aliases()
1332 self.alias_manager.init_aliases()
1333
1333
1334 # Now define aliases that only make sense on the terminal, because they
1334 # Now define aliases that only make sense on the terminal, because they
1335 # need direct access to the console in a way that we can't emulate in
1335 # need direct access to the console in a way that we can't emulate in
1336 # GUI or web frontend
1336 # GUI or web frontend
1337 if os.name == 'posix':
1337 if os.name == 'posix':
1338 for cmd in ('clear', 'more', 'less', 'man'):
1338 for cmd in ('clear', 'more', 'less', 'man'):
1339 if cmd not in self.magics_manager.magics['line']:
1339 if cmd not in self.magics_manager.magics['line']:
1340 self.alias_manager.soft_define_alias(cmd, cmd)
1340 self.alias_manager.soft_define_alias(cmd, cmd)
1341
1341
1342 # Flush the private list of module references kept for script
1342 # Flush the private list of module references kept for script
1343 # execution protection
1343 # execution protection
1344 self.clear_main_mod_cache()
1344 self.clear_main_mod_cache()
1345
1345
1346 def del_var(self, varname, by_name=False):
1346 def del_var(self, varname, by_name=False):
1347 """Delete a variable from the various namespaces, so that, as
1347 """Delete a variable from the various namespaces, so that, as
1348 far as possible, we're not keeping any hidden references to it.
1348 far as possible, we're not keeping any hidden references to it.
1349
1349
1350 Parameters
1350 Parameters
1351 ----------
1351 ----------
1352 varname : str
1352 varname : str
1353 The name of the variable to delete.
1353 The name of the variable to delete.
1354 by_name : bool
1354 by_name : bool
1355 If True, delete variables with the given name in each
1355 If True, delete variables with the given name in each
1356 namespace. If False (default), find the variable in the user
1356 namespace. If False (default), find the variable in the user
1357 namespace, and delete references to it.
1357 namespace, and delete references to it.
1358 """
1358 """
1359 if varname in ('__builtin__', '__builtins__'):
1359 if varname in ('__builtin__', '__builtins__'):
1360 raise ValueError("Refusing to delete %s" % varname)
1360 raise ValueError("Refusing to delete %s" % varname)
1361
1361
1362 ns_refs = self.all_ns_refs
1362 ns_refs = self.all_ns_refs
1363
1363
1364 if by_name: # Delete by name
1364 if by_name: # Delete by name
1365 for ns in ns_refs:
1365 for ns in ns_refs:
1366 try:
1366 try:
1367 del ns[varname]
1367 del ns[varname]
1368 except KeyError:
1368 except KeyError:
1369 pass
1369 pass
1370 else: # Delete by object
1370 else: # Delete by object
1371 try:
1371 try:
1372 obj = self.user_ns[varname]
1372 obj = self.user_ns[varname]
1373 except KeyError as e:
1373 except KeyError as e:
1374 raise NameError("name '%s' is not defined" % varname) from e
1374 raise NameError("name '%s' is not defined" % varname) from e
1375 # Also check in output history
1375 # Also check in output history
1376 ns_refs.append(self.history_manager.output_hist)
1376 ns_refs.append(self.history_manager.output_hist)
1377 for ns in ns_refs:
1377 for ns in ns_refs:
1378 to_delete = [n for n, o in ns.items() if o is obj]
1378 to_delete = [n for n, o in ns.items() if o is obj]
1379 for name in to_delete:
1379 for name in to_delete:
1380 del ns[name]
1380 del ns[name]
1381
1381
1382 # Ensure it is removed from the last execution result
1382 # Ensure it is removed from the last execution result
1383 if self.last_execution_result.result is obj:
1383 if self.last_execution_result.result is obj:
1384 self.last_execution_result = None
1384 self.last_execution_result = None
1385
1385
1386 # displayhook keeps extra references, but not in a dictionary
1386 # displayhook keeps extra references, but not in a dictionary
1387 for name in ('_', '__', '___'):
1387 for name in ('_', '__', '___'):
1388 if getattr(self.displayhook, name) is obj:
1388 if getattr(self.displayhook, name) is obj:
1389 setattr(self.displayhook, name, None)
1389 setattr(self.displayhook, name, None)
1390
1390
1391 def reset_selective(self, regex=None):
1391 def reset_selective(self, regex=None):
1392 """Clear selective variables from internal namespaces based on a
1392 """Clear selective variables from internal namespaces based on a
1393 specified regular expression.
1393 specified regular expression.
1394
1394
1395 Parameters
1395 Parameters
1396 ----------
1396 ----------
1397 regex : string or compiled pattern, optional
1397 regex : string or compiled pattern, optional
1398 A regular expression pattern that will be used in searching
1398 A regular expression pattern that will be used in searching
1399 variable names in the users namespaces.
1399 variable names in the users namespaces.
1400 """
1400 """
1401 if regex is not None:
1401 if regex is not None:
1402 try:
1402 try:
1403 m = re.compile(regex)
1403 m = re.compile(regex)
1404 except TypeError as e:
1404 except TypeError as e:
1405 raise TypeError('regex must be a string or compiled pattern') from e
1405 raise TypeError('regex must be a string or compiled pattern') from e
1406 # Search for keys in each namespace that match the given regex
1406 # Search for keys in each namespace that match the given regex
1407 # If a match is found, delete the key/value pair.
1407 # If a match is found, delete the key/value pair.
1408 for ns in self.all_ns_refs:
1408 for ns in self.all_ns_refs:
1409 for var in ns:
1409 for var in ns:
1410 if m.search(var):
1410 if m.search(var):
1411 del ns[var]
1411 del ns[var]
1412
1412
1413 def push(self, variables, interactive=True):
1413 def push(self, variables, interactive=True):
1414 """Inject a group of variables into the IPython user namespace.
1414 """Inject a group of variables into the IPython user namespace.
1415
1415
1416 Parameters
1416 Parameters
1417 ----------
1417 ----------
1418 variables : dict, str or list/tuple of str
1418 variables : dict, str or list/tuple of str
1419 The variables to inject into the user's namespace. If a dict, a
1419 The variables to inject into the user's namespace. If a dict, a
1420 simple update is done. If a str, the string is assumed to have
1420 simple update is done. If a str, the string is assumed to have
1421 variable names separated by spaces. A list/tuple of str can also
1421 variable names separated by spaces. A list/tuple of str can also
1422 be used to give the variable names. If just the variable names are
1422 be used to give the variable names. If just the variable names are
1423 give (list/tuple/str) then the variable values looked up in the
1423 give (list/tuple/str) then the variable values looked up in the
1424 callers frame.
1424 callers frame.
1425 interactive : bool
1425 interactive : bool
1426 If True (default), the variables will be listed with the ``who``
1426 If True (default), the variables will be listed with the ``who``
1427 magic.
1427 magic.
1428 """
1428 """
1429 vdict = None
1429 vdict = None
1430
1430
1431 # We need a dict of name/value pairs to do namespace updates.
1431 # We need a dict of name/value pairs to do namespace updates.
1432 if isinstance(variables, dict):
1432 if isinstance(variables, dict):
1433 vdict = variables
1433 vdict = variables
1434 elif isinstance(variables, (str, list, tuple)):
1434 elif isinstance(variables, (str, list, tuple)):
1435 if isinstance(variables, str):
1435 if isinstance(variables, str):
1436 vlist = variables.split()
1436 vlist = variables.split()
1437 else:
1437 else:
1438 vlist = variables
1438 vlist = variables
1439 vdict = {}
1439 vdict = {}
1440 cf = sys._getframe(1)
1440 cf = sys._getframe(1)
1441 for name in vlist:
1441 for name in vlist:
1442 try:
1442 try:
1443 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1443 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1444 except:
1444 except:
1445 print('Could not get variable %s from %s' %
1445 print('Could not get variable %s from %s' %
1446 (name,cf.f_code.co_name))
1446 (name,cf.f_code.co_name))
1447 else:
1447 else:
1448 raise ValueError('variables must be a dict/str/list/tuple')
1448 raise ValueError('variables must be a dict/str/list/tuple')
1449
1449
1450 # Propagate variables to user namespace
1450 # Propagate variables to user namespace
1451 self.user_ns.update(vdict)
1451 self.user_ns.update(vdict)
1452
1452
1453 # And configure interactive visibility
1453 # And configure interactive visibility
1454 user_ns_hidden = self.user_ns_hidden
1454 user_ns_hidden = self.user_ns_hidden
1455 if interactive:
1455 if interactive:
1456 for name in vdict:
1456 for name in vdict:
1457 user_ns_hidden.pop(name, None)
1457 user_ns_hidden.pop(name, None)
1458 else:
1458 else:
1459 user_ns_hidden.update(vdict)
1459 user_ns_hidden.update(vdict)
1460
1460
1461 def drop_by_id(self, variables):
1461 def drop_by_id(self, variables):
1462 """Remove a dict of variables from the user namespace, if they are the
1462 """Remove a dict of variables from the user namespace, if they are the
1463 same as the values in the dictionary.
1463 same as the values in the dictionary.
1464
1464
1465 This is intended for use by extensions: variables that they've added can
1465 This is intended for use by extensions: variables that they've added can
1466 be taken back out if they are unloaded, without removing any that the
1466 be taken back out if they are unloaded, without removing any that the
1467 user has overwritten.
1467 user has overwritten.
1468
1468
1469 Parameters
1469 Parameters
1470 ----------
1470 ----------
1471 variables : dict
1471 variables : dict
1472 A dictionary mapping object names (as strings) to the objects.
1472 A dictionary mapping object names (as strings) to the objects.
1473 """
1473 """
1474 for name, obj in variables.items():
1474 for name, obj in variables.items():
1475 if name in self.user_ns and self.user_ns[name] is obj:
1475 if name in self.user_ns and self.user_ns[name] is obj:
1476 del self.user_ns[name]
1476 del self.user_ns[name]
1477 self.user_ns_hidden.pop(name, None)
1477 self.user_ns_hidden.pop(name, None)
1478
1478
1479 #-------------------------------------------------------------------------
1479 #-------------------------------------------------------------------------
1480 # Things related to object introspection
1480 # Things related to object introspection
1481 #-------------------------------------------------------------------------
1481 #-------------------------------------------------------------------------
1482
1482
1483 def _ofind(self, oname, namespaces=None):
1483 def _ofind(self, oname, namespaces=None):
1484 """Find an object in the available namespaces.
1484 """Find an object in the available namespaces.
1485
1485
1486 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1486 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1487
1487
1488 Has special code to detect magic functions.
1488 Has special code to detect magic functions.
1489 """
1489 """
1490 oname = oname.strip()
1490 oname = oname.strip()
1491 if not oname.startswith(ESC_MAGIC) and \
1491 if not oname.startswith(ESC_MAGIC) and \
1492 not oname.startswith(ESC_MAGIC2) and \
1492 not oname.startswith(ESC_MAGIC2) and \
1493 not all(a.isidentifier() for a in oname.split(".")):
1493 not all(a.isidentifier() for a in oname.split(".")):
1494 return {'found': False}
1494 return {'found': False}
1495
1495
1496 if namespaces is None:
1496 if namespaces is None:
1497 # Namespaces to search in:
1497 # Namespaces to search in:
1498 # Put them in a list. The order is important so that we
1498 # Put them in a list. The order is important so that we
1499 # find things in the same order that Python finds them.
1499 # find things in the same order that Python finds them.
1500 namespaces = [ ('Interactive', self.user_ns),
1500 namespaces = [ ('Interactive', self.user_ns),
1501 ('Interactive (global)', self.user_global_ns),
1501 ('Interactive (global)', self.user_global_ns),
1502 ('Python builtin', builtin_mod.__dict__),
1502 ('Python builtin', builtin_mod.__dict__),
1503 ]
1503 ]
1504
1504
1505 ismagic = False
1505 ismagic = False
1506 isalias = False
1506 isalias = False
1507 found = False
1507 found = False
1508 ospace = None
1508 ospace = None
1509 parent = None
1509 parent = None
1510 obj = None
1510 obj = None
1511
1511
1512
1512
1513 # Look for the given name by splitting it in parts. If the head is
1513 # Look for the given name by splitting it in parts. If the head is
1514 # found, then we look for all the remaining parts as members, and only
1514 # found, then we look for all the remaining parts as members, and only
1515 # declare success if we can find them all.
1515 # declare success if we can find them all.
1516 oname_parts = oname.split('.')
1516 oname_parts = oname.split('.')
1517 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1517 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1518 for nsname,ns in namespaces:
1518 for nsname,ns in namespaces:
1519 try:
1519 try:
1520 obj = ns[oname_head]
1520 obj = ns[oname_head]
1521 except KeyError:
1521 except KeyError:
1522 continue
1522 continue
1523 else:
1523 else:
1524 for idx, part in enumerate(oname_rest):
1524 for idx, part in enumerate(oname_rest):
1525 try:
1525 try:
1526 parent = obj
1526 parent = obj
1527 # The last part is looked up in a special way to avoid
1527 # The last part is looked up in a special way to avoid
1528 # descriptor invocation as it may raise or have side
1528 # descriptor invocation as it may raise or have side
1529 # effects.
1529 # effects.
1530 if idx == len(oname_rest) - 1:
1530 if idx == len(oname_rest) - 1:
1531 obj = self._getattr_property(obj, part)
1531 obj = self._getattr_property(obj, part)
1532 else:
1532 else:
1533 obj = getattr(obj, part)
1533 obj = getattr(obj, part)
1534 except:
1534 except:
1535 # Blanket except b/c some badly implemented objects
1535 # Blanket except b/c some badly implemented objects
1536 # allow __getattr__ to raise exceptions other than
1536 # allow __getattr__ to raise exceptions other than
1537 # AttributeError, which then crashes IPython.
1537 # AttributeError, which then crashes IPython.
1538 break
1538 break
1539 else:
1539 else:
1540 # If we finish the for loop (no break), we got all members
1540 # If we finish the for loop (no break), we got all members
1541 found = True
1541 found = True
1542 ospace = nsname
1542 ospace = nsname
1543 break # namespace loop
1543 break # namespace loop
1544
1544
1545 # Try to see if it's magic
1545 # Try to see if it's magic
1546 if not found:
1546 if not found:
1547 obj = None
1547 obj = None
1548 if oname.startswith(ESC_MAGIC2):
1548 if oname.startswith(ESC_MAGIC2):
1549 oname = oname.lstrip(ESC_MAGIC2)
1549 oname = oname.lstrip(ESC_MAGIC2)
1550 obj = self.find_cell_magic(oname)
1550 obj = self.find_cell_magic(oname)
1551 elif oname.startswith(ESC_MAGIC):
1551 elif oname.startswith(ESC_MAGIC):
1552 oname = oname.lstrip(ESC_MAGIC)
1552 oname = oname.lstrip(ESC_MAGIC)
1553 obj = self.find_line_magic(oname)
1553 obj = self.find_line_magic(oname)
1554 else:
1554 else:
1555 # search without prefix, so run? will find %run?
1555 # search without prefix, so run? will find %run?
1556 obj = self.find_line_magic(oname)
1556 obj = self.find_line_magic(oname)
1557 if obj is None:
1557 if obj is None:
1558 obj = self.find_cell_magic(oname)
1558 obj = self.find_cell_magic(oname)
1559 if obj is not None:
1559 if obj is not None:
1560 found = True
1560 found = True
1561 ospace = 'IPython internal'
1561 ospace = 'IPython internal'
1562 ismagic = True
1562 ismagic = True
1563 isalias = isinstance(obj, Alias)
1563 isalias = isinstance(obj, Alias)
1564
1564
1565 # Last try: special-case some literals like '', [], {}, etc:
1565 # Last try: special-case some literals like '', [], {}, etc:
1566 if not found and oname_head in ["''",'""','[]','{}','()']:
1566 if not found and oname_head in ["''",'""','[]','{}','()']:
1567 obj = eval(oname_head)
1567 obj = eval(oname_head)
1568 found = True
1568 found = True
1569 ospace = 'Interactive'
1569 ospace = 'Interactive'
1570
1570
1571 return {
1571 return {
1572 'obj':obj,
1572 'obj':obj,
1573 'found':found,
1573 'found':found,
1574 'parent':parent,
1574 'parent':parent,
1575 'ismagic':ismagic,
1575 'ismagic':ismagic,
1576 'isalias':isalias,
1576 'isalias':isalias,
1577 'namespace':ospace
1577 'namespace':ospace
1578 }
1578 }
1579
1579
1580 @staticmethod
1580 @staticmethod
1581 def _getattr_property(obj, attrname):
1581 def _getattr_property(obj, attrname):
1582 """Property-aware getattr to use in object finding.
1582 """Property-aware getattr to use in object finding.
1583
1583
1584 If attrname represents a property, return it unevaluated (in case it has
1584 If attrname represents a property, return it unevaluated (in case it has
1585 side effects or raises an error.
1585 side effects or raises an error.
1586
1586
1587 """
1587 """
1588 if not isinstance(obj, type):
1588 if not isinstance(obj, type):
1589 try:
1589 try:
1590 # `getattr(type(obj), attrname)` is not guaranteed to return
1590 # `getattr(type(obj), attrname)` is not guaranteed to return
1591 # `obj`, but does so for property:
1591 # `obj`, but does so for property:
1592 #
1592 #
1593 # property.__get__(self, None, cls) -> self
1593 # property.__get__(self, None, cls) -> self
1594 #
1594 #
1595 # The universal alternative is to traverse the mro manually
1595 # The universal alternative is to traverse the mro manually
1596 # searching for attrname in class dicts.
1596 # searching for attrname in class dicts.
1597 attr = getattr(type(obj), attrname)
1597 attr = getattr(type(obj), attrname)
1598 except AttributeError:
1598 except AttributeError:
1599 pass
1599 pass
1600 else:
1600 else:
1601 # This relies on the fact that data descriptors (with both
1601 # This relies on the fact that data descriptors (with both
1602 # __get__ & __set__ magic methods) take precedence over
1602 # __get__ & __set__ magic methods) take precedence over
1603 # instance-level attributes:
1603 # instance-level attributes:
1604 #
1604 #
1605 # class A(object):
1605 # class A(object):
1606 # @property
1606 # @property
1607 # def foobar(self): return 123
1607 # def foobar(self): return 123
1608 # a = A()
1608 # a = A()
1609 # a.__dict__['foobar'] = 345
1609 # a.__dict__['foobar'] = 345
1610 # a.foobar # == 123
1610 # a.foobar # == 123
1611 #
1611 #
1612 # So, a property may be returned right away.
1612 # So, a property may be returned right away.
1613 if isinstance(attr, property):
1613 if isinstance(attr, property):
1614 return attr
1614 return attr
1615
1615
1616 # Nothing helped, fall back.
1616 # Nothing helped, fall back.
1617 return getattr(obj, attrname)
1617 return getattr(obj, attrname)
1618
1618
1619 def _object_find(self, oname, namespaces=None):
1619 def _object_find(self, oname, namespaces=None):
1620 """Find an object and return a struct with info about it."""
1620 """Find an object and return a struct with info about it."""
1621 return Struct(self._ofind(oname, namespaces))
1621 return Struct(self._ofind(oname, namespaces))
1622
1622
1623 def _inspect(self, meth, oname, namespaces=None, **kw):
1623 def _inspect(self, meth, oname, namespaces=None, **kw):
1624 """Generic interface to the inspector system.
1624 """Generic interface to the inspector system.
1625
1625
1626 This function is meant to be called by pdef, pdoc & friends.
1626 This function is meant to be called by pdef, pdoc & friends.
1627 """
1627 """
1628 info = self._object_find(oname, namespaces)
1628 info = self._object_find(oname, namespaces)
1629 docformat = (
1629 docformat = (
1630 sphinxify(self.object_inspect(oname)) if self.sphinxify_docstring else None
1630 sphinxify(self.object_inspect(oname)) if self.sphinxify_docstring else None
1631 )
1631 )
1632 if info.found:
1632 if info.found:
1633 pmethod = getattr(self.inspector, meth)
1633 pmethod = getattr(self.inspector, meth)
1634 # TODO: only apply format_screen to the plain/text repr of the mime
1634 # TODO: only apply format_screen to the plain/text repr of the mime
1635 # bundle.
1635 # bundle.
1636 formatter = format_screen if info.ismagic else docformat
1636 formatter = format_screen if info.ismagic else docformat
1637 if meth == 'pdoc':
1637 if meth == 'pdoc':
1638 pmethod(info.obj, oname, formatter)
1638 pmethod(info.obj, oname, formatter)
1639 elif meth == 'pinfo':
1639 elif meth == 'pinfo':
1640 pmethod(
1640 pmethod(
1641 info.obj,
1641 info.obj,
1642 oname,
1642 oname,
1643 formatter,
1643 formatter,
1644 info,
1644 info,
1645 enable_html_pager=self.enable_html_pager,
1645 enable_html_pager=self.enable_html_pager,
1646 **kw
1646 **kw
1647 )
1647 )
1648 else:
1648 else:
1649 pmethod(info.obj, oname)
1649 pmethod(info.obj, oname)
1650 else:
1650 else:
1651 print('Object `%s` not found.' % oname)
1651 print('Object `%s` not found.' % oname)
1652 return 'not found' # so callers can take other action
1652 return 'not found' # so callers can take other action
1653
1653
1654 def object_inspect(self, oname, detail_level=0):
1654 def object_inspect(self, oname, detail_level=0):
1655 """Get object info about oname"""
1655 """Get object info about oname"""
1656 with self.builtin_trap:
1656 with self.builtin_trap:
1657 info = self._object_find(oname)
1657 info = self._object_find(oname)
1658 if info.found:
1658 if info.found:
1659 return self.inspector.info(info.obj, oname, info=info,
1659 return self.inspector.info(info.obj, oname, info=info,
1660 detail_level=detail_level
1660 detail_level=detail_level
1661 )
1661 )
1662 else:
1662 else:
1663 return oinspect.object_info(name=oname, found=False)
1663 return oinspect.object_info(name=oname, found=False)
1664
1664
1665 def object_inspect_text(self, oname, detail_level=0):
1665 def object_inspect_text(self, oname, detail_level=0):
1666 """Get object info as formatted text"""
1666 """Get object info as formatted text"""
1667 return self.object_inspect_mime(oname, detail_level)['text/plain']
1667 return self.object_inspect_mime(oname, detail_level)['text/plain']
1668
1668
1669 def object_inspect_mime(self, oname, detail_level=0, omit_sections=()):
1669 def object_inspect_mime(self, oname, detail_level=0, omit_sections=()):
1670 """Get object info as a mimebundle of formatted representations.
1670 """Get object info as a mimebundle of formatted representations.
1671
1671
1672 A mimebundle is a dictionary, keyed by mime-type.
1672 A mimebundle is a dictionary, keyed by mime-type.
1673 It must always have the key `'text/plain'`.
1673 It must always have the key `'text/plain'`.
1674 """
1674 """
1675 with self.builtin_trap:
1675 with self.builtin_trap:
1676 info = self._object_find(oname)
1676 info = self._object_find(oname)
1677 if info.found:
1677 if info.found:
1678 docformat = (
1678 docformat = (
1679 sphinxify(self.object_inspect(oname))
1679 sphinxify(self.object_inspect(oname))
1680 if self.sphinxify_docstring
1680 if self.sphinxify_docstring
1681 else None
1681 else None
1682 )
1682 )
1683 return self.inspector._get_info(
1683 return self.inspector._get_info(
1684 info.obj,
1684 info.obj,
1685 oname,
1685 oname,
1686 info=info,
1686 info=info,
1687 detail_level=detail_level,
1687 detail_level=detail_level,
1688 formatter=docformat,
1688 formatter=docformat,
1689 omit_sections=omit_sections,
1689 omit_sections=omit_sections,
1690 )
1690 )
1691 else:
1691 else:
1692 raise KeyError(oname)
1692 raise KeyError(oname)
1693
1693
1694 #-------------------------------------------------------------------------
1694 #-------------------------------------------------------------------------
1695 # Things related to history management
1695 # Things related to history management
1696 #-------------------------------------------------------------------------
1696 #-------------------------------------------------------------------------
1697
1697
1698 def init_history(self):
1698 def init_history(self):
1699 """Sets up the command history, and starts regular autosaves."""
1699 """Sets up the command history, and starts regular autosaves."""
1700 self.history_manager = HistoryManager(shell=self, parent=self)
1700 self.history_manager = HistoryManager(shell=self, parent=self)
1701 self.configurables.append(self.history_manager)
1701 self.configurables.append(self.history_manager)
1702
1702
1703 #-------------------------------------------------------------------------
1703 #-------------------------------------------------------------------------
1704 # Things related to exception handling and tracebacks (not debugging)
1704 # Things related to exception handling and tracebacks (not debugging)
1705 #-------------------------------------------------------------------------
1705 #-------------------------------------------------------------------------
1706
1706
1707 debugger_cls = InterruptiblePdb
1707 debugger_cls = InterruptiblePdb
1708
1708
1709 def init_traceback_handlers(self, custom_exceptions):
1709 def init_traceback_handlers(self, custom_exceptions):
1710 # Syntax error handler.
1710 # Syntax error handler.
1711 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor', parent=self)
1711 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor', parent=self)
1712
1712
1713 # The interactive one is initialized with an offset, meaning we always
1713 # The interactive one is initialized with an offset, meaning we always
1714 # want to remove the topmost item in the traceback, which is our own
1714 # want to remove the topmost item in the traceback, which is our own
1715 # internal code. Valid modes: ['Plain','Context','Verbose','Minimal']
1715 # internal code. Valid modes: ['Plain','Context','Verbose','Minimal']
1716 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1716 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1717 color_scheme='NoColor',
1717 color_scheme='NoColor',
1718 tb_offset = 1,
1718 tb_offset = 1,
1719 check_cache=check_linecache_ipython,
1719 check_cache=check_linecache_ipython,
1720 debugger_cls=self.debugger_cls, parent=self)
1720 debugger_cls=self.debugger_cls, parent=self)
1721
1721
1722 # The instance will store a pointer to the system-wide exception hook,
1722 # The instance will store a pointer to the system-wide exception hook,
1723 # so that runtime code (such as magics) can access it. This is because
1723 # so that runtime code (such as magics) can access it. This is because
1724 # during the read-eval loop, it may get temporarily overwritten.
1724 # during the read-eval loop, it may get temporarily overwritten.
1725 self.sys_excepthook = sys.excepthook
1725 self.sys_excepthook = sys.excepthook
1726
1726
1727 # and add any custom exception handlers the user may have specified
1727 # and add any custom exception handlers the user may have specified
1728 self.set_custom_exc(*custom_exceptions)
1728 self.set_custom_exc(*custom_exceptions)
1729
1729
1730 # Set the exception mode
1730 # Set the exception mode
1731 self.InteractiveTB.set_mode(mode=self.xmode)
1731 self.InteractiveTB.set_mode(mode=self.xmode)
1732
1732
1733 def set_custom_exc(self, exc_tuple, handler):
1733 def set_custom_exc(self, exc_tuple, handler):
1734 """set_custom_exc(exc_tuple, handler)
1734 """set_custom_exc(exc_tuple, handler)
1735
1735
1736 Set a custom exception handler, which will be called if any of the
1736 Set a custom exception handler, which will be called if any of the
1737 exceptions in exc_tuple occur in the mainloop (specifically, in the
1737 exceptions in exc_tuple occur in the mainloop (specifically, in the
1738 run_code() method).
1738 run_code() method).
1739
1739
1740 Parameters
1740 Parameters
1741 ----------
1741 ----------
1742 exc_tuple : tuple of exception classes
1742 exc_tuple : tuple of exception classes
1743 A *tuple* of exception classes, for which to call the defined
1743 A *tuple* of exception classes, for which to call the defined
1744 handler. It is very important that you use a tuple, and NOT A
1744 handler. It is very important that you use a tuple, and NOT A
1745 LIST here, because of the way Python's except statement works. If
1745 LIST here, because of the way Python's except statement works. If
1746 you only want to trap a single exception, use a singleton tuple::
1746 you only want to trap a single exception, use a singleton tuple::
1747
1747
1748 exc_tuple == (MyCustomException,)
1748 exc_tuple == (MyCustomException,)
1749
1749
1750 handler : callable
1750 handler : callable
1751 handler must have the following signature::
1751 handler must have the following signature::
1752
1752
1753 def my_handler(self, etype, value, tb, tb_offset=None):
1753 def my_handler(self, etype, value, tb, tb_offset=None):
1754 ...
1754 ...
1755 return structured_traceback
1755 return structured_traceback
1756
1756
1757 Your handler must return a structured traceback (a list of strings),
1757 Your handler must return a structured traceback (a list of strings),
1758 or None.
1758 or None.
1759
1759
1760 This will be made into an instance method (via types.MethodType)
1760 This will be made into an instance method (via types.MethodType)
1761 of IPython itself, and it will be called if any of the exceptions
1761 of IPython itself, and it will be called if any of the exceptions
1762 listed in the exc_tuple are caught. If the handler is None, an
1762 listed in the exc_tuple are caught. If the handler is None, an
1763 internal basic one is used, which just prints basic info.
1763 internal basic one is used, which just prints basic info.
1764
1764
1765 To protect IPython from crashes, if your handler ever raises an
1765 To protect IPython from crashes, if your handler ever raises an
1766 exception or returns an invalid result, it will be immediately
1766 exception or returns an invalid result, it will be immediately
1767 disabled.
1767 disabled.
1768
1768
1769 Notes
1769 Notes
1770 -----
1770 -----
1771 WARNING: by putting in your own exception handler into IPython's main
1771 WARNING: by putting in your own exception handler into IPython's main
1772 execution loop, you run a very good chance of nasty crashes. This
1772 execution loop, you run a very good chance of nasty crashes. This
1773 facility should only be used if you really know what you are doing.
1773 facility should only be used if you really know what you are doing.
1774 """
1774 """
1775
1775
1776 if not isinstance(exc_tuple, tuple):
1776 if not isinstance(exc_tuple, tuple):
1777 raise TypeError("The custom exceptions must be given as a tuple.")
1777 raise TypeError("The custom exceptions must be given as a tuple.")
1778
1778
1779 def dummy_handler(self, etype, value, tb, tb_offset=None):
1779 def dummy_handler(self, etype, value, tb, tb_offset=None):
1780 print('*** Simple custom exception handler ***')
1780 print('*** Simple custom exception handler ***')
1781 print('Exception type :', etype)
1781 print('Exception type :', etype)
1782 print('Exception value:', value)
1782 print('Exception value:', value)
1783 print('Traceback :', tb)
1783 print('Traceback :', tb)
1784
1784
1785 def validate_stb(stb):
1785 def validate_stb(stb):
1786 """validate structured traceback return type
1786 """validate structured traceback return type
1787
1787
1788 return type of CustomTB *should* be a list of strings, but allow
1788 return type of CustomTB *should* be a list of strings, but allow
1789 single strings or None, which are harmless.
1789 single strings or None, which are harmless.
1790
1790
1791 This function will *always* return a list of strings,
1791 This function will *always* return a list of strings,
1792 and will raise a TypeError if stb is inappropriate.
1792 and will raise a TypeError if stb is inappropriate.
1793 """
1793 """
1794 msg = "CustomTB must return list of strings, not %r" % stb
1794 msg = "CustomTB must return list of strings, not %r" % stb
1795 if stb is None:
1795 if stb is None:
1796 return []
1796 return []
1797 elif isinstance(stb, str):
1797 elif isinstance(stb, str):
1798 return [stb]
1798 return [stb]
1799 elif not isinstance(stb, list):
1799 elif not isinstance(stb, list):
1800 raise TypeError(msg)
1800 raise TypeError(msg)
1801 # it's a list
1801 # it's a list
1802 for line in stb:
1802 for line in stb:
1803 # check every element
1803 # check every element
1804 if not isinstance(line, str):
1804 if not isinstance(line, str):
1805 raise TypeError(msg)
1805 raise TypeError(msg)
1806 return stb
1806 return stb
1807
1807
1808 if handler is None:
1808 if handler is None:
1809 wrapped = dummy_handler
1809 wrapped = dummy_handler
1810 else:
1810 else:
1811 def wrapped(self,etype,value,tb,tb_offset=None):
1811 def wrapped(self,etype,value,tb,tb_offset=None):
1812 """wrap CustomTB handler, to protect IPython from user code
1812 """wrap CustomTB handler, to protect IPython from user code
1813
1813
1814 This makes it harder (but not impossible) for custom exception
1814 This makes it harder (but not impossible) for custom exception
1815 handlers to crash IPython.
1815 handlers to crash IPython.
1816 """
1816 """
1817 try:
1817 try:
1818 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1818 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1819 return validate_stb(stb)
1819 return validate_stb(stb)
1820 except:
1820 except:
1821 # clear custom handler immediately
1821 # clear custom handler immediately
1822 self.set_custom_exc((), None)
1822 self.set_custom_exc((), None)
1823 print("Custom TB Handler failed, unregistering", file=sys.stderr)
1823 print("Custom TB Handler failed, unregistering", file=sys.stderr)
1824 # show the exception in handler first
1824 # show the exception in handler first
1825 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1825 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1826 print(self.InteractiveTB.stb2text(stb))
1826 print(self.InteractiveTB.stb2text(stb))
1827 print("The original exception:")
1827 print("The original exception:")
1828 stb = self.InteractiveTB.structured_traceback(
1828 stb = self.InteractiveTB.structured_traceback(
1829 (etype,value,tb), tb_offset=tb_offset
1829 (etype,value,tb), tb_offset=tb_offset
1830 )
1830 )
1831 return stb
1831 return stb
1832
1832
1833 self.CustomTB = types.MethodType(wrapped,self)
1833 self.CustomTB = types.MethodType(wrapped,self)
1834 self.custom_exceptions = exc_tuple
1834 self.custom_exceptions = exc_tuple
1835
1835
1836 def excepthook(self, etype, value, tb):
1836 def excepthook(self, etype, value, tb):
1837 """One more defense for GUI apps that call sys.excepthook.
1837 """One more defense for GUI apps that call sys.excepthook.
1838
1838
1839 GUI frameworks like wxPython trap exceptions and call
1839 GUI frameworks like wxPython trap exceptions and call
1840 sys.excepthook themselves. I guess this is a feature that
1840 sys.excepthook themselves. I guess this is a feature that
1841 enables them to keep running after exceptions that would
1841 enables them to keep running after exceptions that would
1842 otherwise kill their mainloop. This is a bother for IPython
1842 otherwise kill their mainloop. This is a bother for IPython
1843 which expects to catch all of the program exceptions with a try:
1843 which expects to catch all of the program exceptions with a try:
1844 except: statement.
1844 except: statement.
1845
1845
1846 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1846 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1847 any app directly invokes sys.excepthook, it will look to the user like
1847 any app directly invokes sys.excepthook, it will look to the user like
1848 IPython crashed. In order to work around this, we can disable the
1848 IPython crashed. In order to work around this, we can disable the
1849 CrashHandler and replace it with this excepthook instead, which prints a
1849 CrashHandler and replace it with this excepthook instead, which prints a
1850 regular traceback using our InteractiveTB. In this fashion, apps which
1850 regular traceback using our InteractiveTB. In this fashion, apps which
1851 call sys.excepthook will generate a regular-looking exception from
1851 call sys.excepthook will generate a regular-looking exception from
1852 IPython, and the CrashHandler will only be triggered by real IPython
1852 IPython, and the CrashHandler will only be triggered by real IPython
1853 crashes.
1853 crashes.
1854
1854
1855 This hook should be used sparingly, only in places which are not likely
1855 This hook should be used sparingly, only in places which are not likely
1856 to be true IPython errors.
1856 to be true IPython errors.
1857 """
1857 """
1858 self.showtraceback((etype, value, tb), tb_offset=0)
1858 self.showtraceback((etype, value, tb), tb_offset=0)
1859
1859
1860 def _get_exc_info(self, exc_tuple=None):
1860 def _get_exc_info(self, exc_tuple=None):
1861 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1861 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1862
1862
1863 Ensures sys.last_type,value,traceback hold the exc_info we found,
1863 Ensures sys.last_type,value,traceback hold the exc_info we found,
1864 from whichever source.
1864 from whichever source.
1865
1865
1866 raises ValueError if none of these contain any information
1866 raises ValueError if none of these contain any information
1867 """
1867 """
1868 if exc_tuple is None:
1868 if exc_tuple is None:
1869 etype, value, tb = sys.exc_info()
1869 etype, value, tb = sys.exc_info()
1870 else:
1870 else:
1871 etype, value, tb = exc_tuple
1871 etype, value, tb = exc_tuple
1872
1872
1873 if etype is None:
1873 if etype is None:
1874 if hasattr(sys, 'last_type'):
1874 if hasattr(sys, 'last_type'):
1875 etype, value, tb = sys.last_type, sys.last_value, \
1875 etype, value, tb = sys.last_type, sys.last_value, \
1876 sys.last_traceback
1876 sys.last_traceback
1877
1877
1878 if etype is None:
1878 if etype is None:
1879 raise ValueError("No exception to find")
1879 raise ValueError("No exception to find")
1880
1880
1881 # Now store the exception info in sys.last_type etc.
1881 # Now store the exception info in sys.last_type etc.
1882 # WARNING: these variables are somewhat deprecated and not
1882 # WARNING: these variables are somewhat deprecated and not
1883 # necessarily safe to use in a threaded environment, but tools
1883 # necessarily safe to use in a threaded environment, but tools
1884 # like pdb depend on their existence, so let's set them. If we
1884 # like pdb depend on their existence, so let's set them. If we
1885 # find problems in the field, we'll need to revisit their use.
1885 # find problems in the field, we'll need to revisit their use.
1886 sys.last_type = etype
1886 sys.last_type = etype
1887 sys.last_value = value
1887 sys.last_value = value
1888 sys.last_traceback = tb
1888 sys.last_traceback = tb
1889
1889
1890 return etype, value, tb
1890 return etype, value, tb
1891
1891
1892 def show_usage_error(self, exc):
1892 def show_usage_error(self, exc):
1893 """Show a short message for UsageErrors
1893 """Show a short message for UsageErrors
1894
1894
1895 These are special exceptions that shouldn't show a traceback.
1895 These are special exceptions that shouldn't show a traceback.
1896 """
1896 """
1897 print("UsageError: %s" % exc, file=sys.stderr)
1897 print("UsageError: %s" % exc, file=sys.stderr)
1898
1898
1899 def get_exception_only(self, exc_tuple=None):
1899 def get_exception_only(self, exc_tuple=None):
1900 """
1900 """
1901 Return as a string (ending with a newline) the exception that
1901 Return as a string (ending with a newline) the exception that
1902 just occurred, without any traceback.
1902 just occurred, without any traceback.
1903 """
1903 """
1904 etype, value, tb = self._get_exc_info(exc_tuple)
1904 etype, value, tb = self._get_exc_info(exc_tuple)
1905 msg = traceback.format_exception_only(etype, value)
1905 msg = traceback.format_exception_only(etype, value)
1906 return ''.join(msg)
1906 return ''.join(msg)
1907
1907
1908 def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None,
1908 def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None,
1909 exception_only=False, running_compiled_code=False):
1909 exception_only=False, running_compiled_code=False):
1910 """Display the exception that just occurred.
1910 """Display the exception that just occurred.
1911
1911
1912 If nothing is known about the exception, this is the method which
1912 If nothing is known about the exception, this is the method which
1913 should be used throughout the code for presenting user tracebacks,
1913 should be used throughout the code for presenting user tracebacks,
1914 rather than directly invoking the InteractiveTB object.
1914 rather than directly invoking the InteractiveTB object.
1915
1915
1916 A specific showsyntaxerror() also exists, but this method can take
1916 A specific showsyntaxerror() also exists, but this method can take
1917 care of calling it if needed, so unless you are explicitly catching a
1917 care of calling it if needed, so unless you are explicitly catching a
1918 SyntaxError exception, don't try to analyze the stack manually and
1918 SyntaxError exception, don't try to analyze the stack manually and
1919 simply call this method."""
1919 simply call this method."""
1920
1920
1921 try:
1921 try:
1922 try:
1922 try:
1923 etype, value, tb = self._get_exc_info(exc_tuple)
1923 etype, value, tb = self._get_exc_info(exc_tuple)
1924 except ValueError:
1924 except ValueError:
1925 print('No traceback available to show.', file=sys.stderr)
1925 print('No traceback available to show.', file=sys.stderr)
1926 return
1926 return
1927
1927
1928 if issubclass(etype, SyntaxError):
1928 if issubclass(etype, SyntaxError):
1929 # Though this won't be called by syntax errors in the input
1929 # Though this won't be called by syntax errors in the input
1930 # line, there may be SyntaxError cases with imported code.
1930 # line, there may be SyntaxError cases with imported code.
1931 self.showsyntaxerror(filename, running_compiled_code)
1931 self.showsyntaxerror(filename, running_compiled_code)
1932 elif etype is UsageError:
1932 elif etype is UsageError:
1933 self.show_usage_error(value)
1933 self.show_usage_error(value)
1934 else:
1934 else:
1935 if exception_only:
1935 if exception_only:
1936 stb = ['An exception has occurred, use %tb to see '
1936 stb = ['An exception has occurred, use %tb to see '
1937 'the full traceback.\n']
1937 'the full traceback.\n']
1938 stb.extend(self.InteractiveTB.get_exception_only(etype,
1938 stb.extend(self.InteractiveTB.get_exception_only(etype,
1939 value))
1939 value))
1940 else:
1940 else:
1941 try:
1941 try:
1942 # Exception classes can customise their traceback - we
1942 # Exception classes can customise their traceback - we
1943 # use this in IPython.parallel for exceptions occurring
1943 # use this in IPython.parallel for exceptions occurring
1944 # in the engines. This should return a list of strings.
1944 # in the engines. This should return a list of strings.
1945 stb = value._render_traceback_()
1945 stb = value._render_traceback_()
1946 except Exception:
1946 except Exception:
1947 stb = self.InteractiveTB.structured_traceback(etype,
1947 stb = self.InteractiveTB.structured_traceback(etype,
1948 value, tb, tb_offset=tb_offset)
1948 value, tb, tb_offset=tb_offset)
1949
1949
1950 self._showtraceback(etype, value, stb)
1950 self._showtraceback(etype, value, stb)
1951 if self.call_pdb:
1951 if self.call_pdb:
1952 # drop into debugger
1952 # drop into debugger
1953 self.debugger(force=True)
1953 self.debugger(force=True)
1954 return
1954 return
1955
1955
1956 # Actually show the traceback
1956 # Actually show the traceback
1957 self._showtraceback(etype, value, stb)
1957 self._showtraceback(etype, value, stb)
1958
1958
1959 except KeyboardInterrupt:
1959 except KeyboardInterrupt:
1960 print('\n' + self.get_exception_only(), file=sys.stderr)
1960 print('\n' + self.get_exception_only(), file=sys.stderr)
1961
1961
1962 def _showtraceback(self, etype, evalue, stb: str):
1962 def _showtraceback(self, etype, evalue, stb: str):
1963 """Actually show a traceback.
1963 """Actually show a traceback.
1964
1964
1965 Subclasses may override this method to put the traceback on a different
1965 Subclasses may override this method to put the traceback on a different
1966 place, like a side channel.
1966 place, like a side channel.
1967 """
1967 """
1968 val = self.InteractiveTB.stb2text(stb)
1968 val = self.InteractiveTB.stb2text(stb)
1969 try:
1969 try:
1970 print(val)
1970 print(val)
1971 except UnicodeEncodeError:
1971 except UnicodeEncodeError:
1972 print(val.encode("utf-8", "backslashreplace").decode())
1972 print(val.encode("utf-8", "backslashreplace").decode())
1973
1973
1974 def showsyntaxerror(self, filename=None, running_compiled_code=False):
1974 def showsyntaxerror(self, filename=None, running_compiled_code=False):
1975 """Display the syntax error that just occurred.
1975 """Display the syntax error that just occurred.
1976
1976
1977 This doesn't display a stack trace because there isn't one.
1977 This doesn't display a stack trace because there isn't one.
1978
1978
1979 If a filename is given, it is stuffed in the exception instead
1979 If a filename is given, it is stuffed in the exception instead
1980 of what was there before (because Python's parser always uses
1980 of what was there before (because Python's parser always uses
1981 "<string>" when reading from a string).
1981 "<string>" when reading from a string).
1982
1982
1983 If the syntax error occurred when running a compiled code (i.e. running_compile_code=True),
1983 If the syntax error occurred when running a compiled code (i.e. running_compile_code=True),
1984 longer stack trace will be displayed.
1984 longer stack trace will be displayed.
1985 """
1985 """
1986 etype, value, last_traceback = self._get_exc_info()
1986 etype, value, last_traceback = self._get_exc_info()
1987
1987
1988 if filename and issubclass(etype, SyntaxError):
1988 if filename and issubclass(etype, SyntaxError):
1989 try:
1989 try:
1990 value.filename = filename
1990 value.filename = filename
1991 except:
1991 except:
1992 # Not the format we expect; leave it alone
1992 # Not the format we expect; leave it alone
1993 pass
1993 pass
1994
1994
1995 # If the error occurred when executing compiled code, we should provide full stacktrace.
1995 # If the error occurred when executing compiled code, we should provide full stacktrace.
1996 elist = traceback.extract_tb(last_traceback) if running_compiled_code else []
1996 elist = traceback.extract_tb(last_traceback) if running_compiled_code else []
1997 stb = self.SyntaxTB.structured_traceback(etype, value, elist)
1997 stb = self.SyntaxTB.structured_traceback(etype, value, elist)
1998 self._showtraceback(etype, value, stb)
1998 self._showtraceback(etype, value, stb)
1999
1999
2000 # This is overridden in TerminalInteractiveShell to show a message about
2000 # This is overridden in TerminalInteractiveShell to show a message about
2001 # the %paste magic.
2001 # the %paste magic.
2002 def showindentationerror(self):
2002 def showindentationerror(self):
2003 """Called by _run_cell when there's an IndentationError in code entered
2003 """Called by _run_cell when there's an IndentationError in code entered
2004 at the prompt.
2004 at the prompt.
2005
2005
2006 This is overridden in TerminalInteractiveShell to show a message about
2006 This is overridden in TerminalInteractiveShell to show a message about
2007 the %paste magic."""
2007 the %paste magic."""
2008 self.showsyntaxerror()
2008 self.showsyntaxerror()
2009
2009
2010 @skip_doctest
2010 @skip_doctest
2011 def set_next_input(self, s, replace=False):
2011 def set_next_input(self, s, replace=False):
2012 """ Sets the 'default' input string for the next command line.
2012 """ Sets the 'default' input string for the next command line.
2013
2013
2014 Example::
2014 Example::
2015
2015
2016 In [1]: _ip.set_next_input("Hello Word")
2016 In [1]: _ip.set_next_input("Hello Word")
2017 In [2]: Hello Word_ # cursor is here
2017 In [2]: Hello Word_ # cursor is here
2018 """
2018 """
2019 self.rl_next_input = s
2019 self.rl_next_input = s
2020
2020
2021 def _indent_current_str(self):
2021 def _indent_current_str(self):
2022 """return the current level of indentation as a string"""
2022 """return the current level of indentation as a string"""
2023 return self.input_splitter.get_indent_spaces() * ' '
2023 return self.input_splitter.get_indent_spaces() * ' '
2024
2024
2025 #-------------------------------------------------------------------------
2025 #-------------------------------------------------------------------------
2026 # Things related to text completion
2026 # Things related to text completion
2027 #-------------------------------------------------------------------------
2027 #-------------------------------------------------------------------------
2028
2028
2029 def init_completer(self):
2029 def init_completer(self):
2030 """Initialize the completion machinery.
2030 """Initialize the completion machinery.
2031
2031
2032 This creates completion machinery that can be used by client code,
2032 This creates completion machinery that can be used by client code,
2033 either interactively in-process (typically triggered by the readline
2033 either interactively in-process (typically triggered by the readline
2034 library), programmatically (such as in test suites) or out-of-process
2034 library), programmatically (such as in test suites) or out-of-process
2035 (typically over the network by remote frontends).
2035 (typically over the network by remote frontends).
2036 """
2036 """
2037 from IPython.core.completer import IPCompleter
2037 from IPython.core.completer import IPCompleter
2038 from IPython.core.completerlib import (module_completer,
2038 from IPython.core.completerlib import (module_completer,
2039 magic_run_completer, cd_completer, reset_completer)
2039 magic_run_completer, cd_completer, reset_completer)
2040
2040
2041 self.Completer = IPCompleter(shell=self,
2041 self.Completer = IPCompleter(shell=self,
2042 namespace=self.user_ns,
2042 namespace=self.user_ns,
2043 global_namespace=self.user_global_ns,
2043 global_namespace=self.user_global_ns,
2044 parent=self,
2044 parent=self,
2045 )
2045 )
2046 self.configurables.append(self.Completer)
2046 self.configurables.append(self.Completer)
2047
2047
2048 # Add custom completers to the basic ones built into IPCompleter
2048 # Add custom completers to the basic ones built into IPCompleter
2049 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
2049 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
2050 self.strdispatchers['complete_command'] = sdisp
2050 self.strdispatchers['complete_command'] = sdisp
2051 self.Completer.custom_completers = sdisp
2051 self.Completer.custom_completers = sdisp
2052
2052
2053 self.set_hook('complete_command', module_completer, str_key = 'import')
2053 self.set_hook('complete_command', module_completer, str_key = 'import')
2054 self.set_hook('complete_command', module_completer, str_key = 'from')
2054 self.set_hook('complete_command', module_completer, str_key = 'from')
2055 self.set_hook('complete_command', module_completer, str_key = '%aimport')
2055 self.set_hook('complete_command', module_completer, str_key = '%aimport')
2056 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
2056 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
2057 self.set_hook('complete_command', cd_completer, str_key = '%cd')
2057 self.set_hook('complete_command', cd_completer, str_key = '%cd')
2058 self.set_hook('complete_command', reset_completer, str_key = '%reset')
2058 self.set_hook('complete_command', reset_completer, str_key = '%reset')
2059
2059
2060 @skip_doctest
2060 @skip_doctest
2061 def complete(self, text, line=None, cursor_pos=None):
2061 def complete(self, text, line=None, cursor_pos=None):
2062 """Return the completed text and a list of completions.
2062 """Return the completed text and a list of completions.
2063
2063
2064 Parameters
2064 Parameters
2065 ----------
2065 ----------
2066 text : string
2066 text : string
2067 A string of text to be completed on. It can be given as empty and
2067 A string of text to be completed on. It can be given as empty and
2068 instead a line/position pair are given. In this case, the
2068 instead a line/position pair are given. In this case, the
2069 completer itself will split the line like readline does.
2069 completer itself will split the line like readline does.
2070 line : string, optional
2070 line : string, optional
2071 The complete line that text is part of.
2071 The complete line that text is part of.
2072 cursor_pos : int, optional
2072 cursor_pos : int, optional
2073 The position of the cursor on the input line.
2073 The position of the cursor on the input line.
2074
2074
2075 Returns
2075 Returns
2076 -------
2076 -------
2077 text : string
2077 text : string
2078 The actual text that was completed.
2078 The actual text that was completed.
2079 matches : list
2079 matches : list
2080 A sorted list with all possible completions.
2080 A sorted list with all possible completions.
2081
2081
2082 Notes
2082 Notes
2083 -----
2083 -----
2084 The optional arguments allow the completion to take more context into
2084 The optional arguments allow the completion to take more context into
2085 account, and are part of the low-level completion API.
2085 account, and are part of the low-level completion API.
2086
2086
2087 This is a wrapper around the completion mechanism, similar to what
2087 This is a wrapper around the completion mechanism, similar to what
2088 readline does at the command line when the TAB key is hit. By
2088 readline does at the command line when the TAB key is hit. By
2089 exposing it as a method, it can be used by other non-readline
2089 exposing it as a method, it can be used by other non-readline
2090 environments (such as GUIs) for text completion.
2090 environments (such as GUIs) for text completion.
2091
2091
2092 Examples
2092 Examples
2093 --------
2093 --------
2094 In [1]: x = 'hello'
2094 In [1]: x = 'hello'
2095
2095
2096 In [2]: _ip.complete('x.l')
2096 In [2]: _ip.complete('x.l')
2097 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2097 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2098 """
2098 """
2099
2099
2100 # Inject names into __builtin__ so we can complete on the added names.
2100 # Inject names into __builtin__ so we can complete on the added names.
2101 with self.builtin_trap:
2101 with self.builtin_trap:
2102 return self.Completer.complete(text, line, cursor_pos)
2102 return self.Completer.complete(text, line, cursor_pos)
2103
2103
2104 def set_custom_completer(self, completer, pos=0) -> None:
2104 def set_custom_completer(self, completer, pos=0) -> None:
2105 """Adds a new custom completer function.
2105 """Adds a new custom completer function.
2106
2106
2107 The position argument (defaults to 0) is the index in the completers
2107 The position argument (defaults to 0) is the index in the completers
2108 list where you want the completer to be inserted.
2108 list where you want the completer to be inserted.
2109
2109
2110 `completer` should have the following signature::
2110 `completer` should have the following signature::
2111
2111
2112 def completion(self: Completer, text: string) -> List[str]:
2112 def completion(self: Completer, text: string) -> List[str]:
2113 raise NotImplementedError
2113 raise NotImplementedError
2114
2114
2115 It will be bound to the current Completer instance and pass some text
2115 It will be bound to the current Completer instance and pass some text
2116 and return a list with current completions to suggest to the user.
2116 and return a list with current completions to suggest to the user.
2117 """
2117 """
2118
2118
2119 newcomp = types.MethodType(completer, self.Completer)
2119 newcomp = types.MethodType(completer, self.Completer)
2120 self.Completer.custom_matchers.insert(pos,newcomp)
2120 self.Completer.custom_matchers.insert(pos,newcomp)
2121
2121
2122 def set_completer_frame(self, frame=None):
2122 def set_completer_frame(self, frame=None):
2123 """Set the frame of the completer."""
2123 """Set the frame of the completer."""
2124 if frame:
2124 if frame:
2125 self.Completer.namespace = frame.f_locals
2125 self.Completer.namespace = frame.f_locals
2126 self.Completer.global_namespace = frame.f_globals
2126 self.Completer.global_namespace = frame.f_globals
2127 else:
2127 else:
2128 self.Completer.namespace = self.user_ns
2128 self.Completer.namespace = self.user_ns
2129 self.Completer.global_namespace = self.user_global_ns
2129 self.Completer.global_namespace = self.user_global_ns
2130
2130
2131 #-------------------------------------------------------------------------
2131 #-------------------------------------------------------------------------
2132 # Things related to magics
2132 # Things related to magics
2133 #-------------------------------------------------------------------------
2133 #-------------------------------------------------------------------------
2134
2134
2135 def init_magics(self):
2135 def init_magics(self):
2136 from IPython.core import magics as m
2136 from IPython.core import magics as m
2137 self.magics_manager = magic.MagicsManager(shell=self,
2137 self.magics_manager = magic.MagicsManager(shell=self,
2138 parent=self,
2138 parent=self,
2139 user_magics=m.UserMagics(self))
2139 user_magics=m.UserMagics(self))
2140 self.configurables.append(self.magics_manager)
2140 self.configurables.append(self.magics_manager)
2141
2141
2142 # Expose as public API from the magics manager
2142 # Expose as public API from the magics manager
2143 self.register_magics = self.magics_manager.register
2143 self.register_magics = self.magics_manager.register
2144
2144
2145 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2145 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2146 m.ConfigMagics, m.DisplayMagics, m.ExecutionMagics,
2146 m.ConfigMagics, m.DisplayMagics, m.ExecutionMagics,
2147 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2147 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2148 m.NamespaceMagics, m.OSMagics, m.PackagingMagics,
2148 m.NamespaceMagics, m.OSMagics, m.PackagingMagics,
2149 m.PylabMagics, m.ScriptMagics,
2149 m.PylabMagics, m.ScriptMagics,
2150 )
2150 )
2151 self.register_magics(m.AsyncMagics)
2151 self.register_magics(m.AsyncMagics)
2152
2152
2153 # Register Magic Aliases
2153 # Register Magic Aliases
2154 mman = self.magics_manager
2154 mman = self.magics_manager
2155 # FIXME: magic aliases should be defined by the Magics classes
2155 # FIXME: magic aliases should be defined by the Magics classes
2156 # or in MagicsManager, not here
2156 # or in MagicsManager, not here
2157 mman.register_alias('ed', 'edit')
2157 mman.register_alias('ed', 'edit')
2158 mman.register_alias('hist', 'history')
2158 mman.register_alias('hist', 'history')
2159 mman.register_alias('rep', 'recall')
2159 mman.register_alias('rep', 'recall')
2160 mman.register_alias('SVG', 'svg', 'cell')
2160 mman.register_alias('SVG', 'svg', 'cell')
2161 mman.register_alias('HTML', 'html', 'cell')
2161 mman.register_alias('HTML', 'html', 'cell')
2162 mman.register_alias('file', 'writefile', 'cell')
2162 mman.register_alias('file', 'writefile', 'cell')
2163
2163
2164 # FIXME: Move the color initialization to the DisplayHook, which
2164 # FIXME: Move the color initialization to the DisplayHook, which
2165 # should be split into a prompt manager and displayhook. We probably
2165 # should be split into a prompt manager and displayhook. We probably
2166 # even need a centralize colors management object.
2166 # even need a centralize colors management object.
2167 self.run_line_magic('colors', self.colors)
2167 self.run_line_magic('colors', self.colors)
2168
2168
2169 # Defined here so that it's included in the documentation
2169 # Defined here so that it's included in the documentation
2170 @functools.wraps(magic.MagicsManager.register_function)
2170 @functools.wraps(magic.MagicsManager.register_function)
2171 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2171 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2172 self.magics_manager.register_function(
2172 self.magics_manager.register_function(
2173 func, magic_kind=magic_kind, magic_name=magic_name
2173 func, magic_kind=magic_kind, magic_name=magic_name
2174 )
2174 )
2175
2175
2176 def run_line_magic(self, magic_name, line, _stack_depth=1):
2176 def run_line_magic(self, magic_name, line, _stack_depth=1):
2177 """Execute the given line magic.
2177 """Execute the given line magic.
2178
2178
2179 Parameters
2179 Parameters
2180 ----------
2180 ----------
2181 magic_name : str
2181 magic_name : str
2182 Name of the desired magic function, without '%' prefix.
2182 Name of the desired magic function, without '%' prefix.
2183 line : str
2183 line : str
2184 The rest of the input line as a single string.
2184 The rest of the input line as a single string.
2185 _stack_depth : int
2185 _stack_depth : int
2186 If run_line_magic() is called from magic() then _stack_depth=2.
2186 If run_line_magic() is called from magic() then _stack_depth=2.
2187 This is added to ensure backward compatibility for use of 'get_ipython().magic()'
2187 This is added to ensure backward compatibility for use of 'get_ipython().magic()'
2188 """
2188 """
2189 fn = self.find_line_magic(magic_name)
2189 fn = self.find_line_magic(magic_name)
2190 if fn is None:
2190 if fn is None:
2191 cm = self.find_cell_magic(magic_name)
2191 cm = self.find_cell_magic(magic_name)
2192 etpl = "Line magic function `%%%s` not found%s."
2192 etpl = "Line magic function `%%%s` not found%s."
2193 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2193 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2194 'did you mean that instead?)' % magic_name )
2194 'did you mean that instead?)' % magic_name )
2195 raise UsageError(etpl % (magic_name, extra))
2195 raise UsageError(etpl % (magic_name, extra))
2196 else:
2196 else:
2197 # Note: this is the distance in the stack to the user's frame.
2197 # Note: this is the distance in the stack to the user's frame.
2198 # This will need to be updated if the internal calling logic gets
2198 # This will need to be updated if the internal calling logic gets
2199 # refactored, or else we'll be expanding the wrong variables.
2199 # refactored, or else we'll be expanding the wrong variables.
2200
2200
2201 # Determine stack_depth depending on where run_line_magic() has been called
2201 # Determine stack_depth depending on where run_line_magic() has been called
2202 stack_depth = _stack_depth
2202 stack_depth = _stack_depth
2203 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2203 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2204 # magic has opted out of var_expand
2204 # magic has opted out of var_expand
2205 magic_arg_s = line
2205 magic_arg_s = line
2206 else:
2206 else:
2207 magic_arg_s = self.var_expand(line, stack_depth)
2207 magic_arg_s = self.var_expand(line, stack_depth)
2208 # Put magic args in a list so we can call with f(*a) syntax
2208 # Put magic args in a list so we can call with f(*a) syntax
2209 args = [magic_arg_s]
2209 args = [magic_arg_s]
2210 kwargs = {}
2210 kwargs = {}
2211 # Grab local namespace if we need it:
2211 # Grab local namespace if we need it:
2212 if getattr(fn, "needs_local_scope", False):
2212 if getattr(fn, "needs_local_scope", False):
2213 kwargs['local_ns'] = self.get_local_scope(stack_depth)
2213 kwargs['local_ns'] = self.get_local_scope(stack_depth)
2214 with self.builtin_trap:
2214 with self.builtin_trap:
2215 result = fn(*args, **kwargs)
2215 result = fn(*args, **kwargs)
2216 return result
2216 return result
2217
2217
2218 def get_local_scope(self, stack_depth):
2218 def get_local_scope(self, stack_depth):
2219 """Get local scope at given stack depth.
2219 """Get local scope at given stack depth.
2220
2220
2221 Parameters
2221 Parameters
2222 ----------
2222 ----------
2223 stack_depth : int
2223 stack_depth : int
2224 Depth relative to calling frame
2224 Depth relative to calling frame
2225 """
2225 """
2226 return sys._getframe(stack_depth + 1).f_locals
2226 return sys._getframe(stack_depth + 1).f_locals
2227
2227
2228 def run_cell_magic(self, magic_name, line, cell):
2228 def run_cell_magic(self, magic_name, line, cell):
2229 """Execute the given cell magic.
2229 """Execute the given cell magic.
2230
2230
2231 Parameters
2231 Parameters
2232 ----------
2232 ----------
2233 magic_name : str
2233 magic_name : str
2234 Name of the desired magic function, without '%' prefix.
2234 Name of the desired magic function, without '%' prefix.
2235 line : str
2235 line : str
2236 The rest of the first input line as a single string.
2236 The rest of the first input line as a single string.
2237 cell : str
2237 cell : str
2238 The body of the cell as a (possibly multiline) string.
2238 The body of the cell as a (possibly multiline) string.
2239 """
2239 """
2240 fn = self.find_cell_magic(magic_name)
2240 fn = self.find_cell_magic(magic_name)
2241 if fn is None:
2241 if fn is None:
2242 lm = self.find_line_magic(magic_name)
2242 lm = self.find_line_magic(magic_name)
2243 etpl = "Cell magic `%%{0}` not found{1}."
2243 etpl = "Cell magic `%%{0}` not found{1}."
2244 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2244 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2245 'did you mean that instead?)'.format(magic_name))
2245 'did you mean that instead?)'.format(magic_name))
2246 raise UsageError(etpl.format(magic_name, extra))
2246 raise UsageError(etpl.format(magic_name, extra))
2247 elif cell == '':
2247 elif cell == '':
2248 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2248 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2249 if self.find_line_magic(magic_name) is not None:
2249 if self.find_line_magic(magic_name) is not None:
2250 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2250 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2251 raise UsageError(message)
2251 raise UsageError(message)
2252 else:
2252 else:
2253 # Note: this is the distance in the stack to the user's frame.
2253 # Note: this is the distance in the stack to the user's frame.
2254 # This will need to be updated if the internal calling logic gets
2254 # This will need to be updated if the internal calling logic gets
2255 # refactored, or else we'll be expanding the wrong variables.
2255 # refactored, or else we'll be expanding the wrong variables.
2256 stack_depth = 2
2256 stack_depth = 2
2257 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2257 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2258 # magic has opted out of var_expand
2258 # magic has opted out of var_expand
2259 magic_arg_s = line
2259 magic_arg_s = line
2260 else:
2260 else:
2261 magic_arg_s = self.var_expand(line, stack_depth)
2261 magic_arg_s = self.var_expand(line, stack_depth)
2262 kwargs = {}
2262 kwargs = {}
2263 if getattr(fn, "needs_local_scope", False):
2263 if getattr(fn, "needs_local_scope", False):
2264 kwargs['local_ns'] = self.user_ns
2264 kwargs['local_ns'] = self.user_ns
2265
2265
2266 with self.builtin_trap:
2266 with self.builtin_trap:
2267 args = (magic_arg_s, cell)
2267 args = (magic_arg_s, cell)
2268 result = fn(*args, **kwargs)
2268 result = fn(*args, **kwargs)
2269 return result
2269 return result
2270
2270
2271 def find_line_magic(self, magic_name):
2271 def find_line_magic(self, magic_name):
2272 """Find and return a line magic by name.
2272 """Find and return a line magic by name.
2273
2273
2274 Returns None if the magic isn't found."""
2274 Returns None if the magic isn't found."""
2275 return self.magics_manager.magics['line'].get(magic_name)
2275 return self.magics_manager.magics['line'].get(magic_name)
2276
2276
2277 def find_cell_magic(self, magic_name):
2277 def find_cell_magic(self, magic_name):
2278 """Find and return a cell magic by name.
2278 """Find and return a cell magic by name.
2279
2279
2280 Returns None if the magic isn't found."""
2280 Returns None if the magic isn't found."""
2281 return self.magics_manager.magics['cell'].get(magic_name)
2281 return self.magics_manager.magics['cell'].get(magic_name)
2282
2282
2283 def find_magic(self, magic_name, magic_kind='line'):
2283 def find_magic(self, magic_name, magic_kind='line'):
2284 """Find and return a magic of the given type by name.
2284 """Find and return a magic of the given type by name.
2285
2285
2286 Returns None if the magic isn't found."""
2286 Returns None if the magic isn't found."""
2287 return self.magics_manager.magics[magic_kind].get(magic_name)
2287 return self.magics_manager.magics[magic_kind].get(magic_name)
2288
2288
2289 def magic(self, arg_s):
2289 def magic(self, arg_s):
2290 """DEPRECATED. Use run_line_magic() instead.
2290 """DEPRECATED. Use run_line_magic() instead.
2291
2291
2292 Call a magic function by name.
2292 Call a magic function by name.
2293
2293
2294 Input: a string containing the name of the magic function to call and
2294 Input: a string containing the name of the magic function to call and
2295 any additional arguments to be passed to the magic.
2295 any additional arguments to be passed to the magic.
2296
2296
2297 magic('name -opt foo bar') is equivalent to typing at the ipython
2297 magic('name -opt foo bar') is equivalent to typing at the ipython
2298 prompt:
2298 prompt:
2299
2299
2300 In[1]: %name -opt foo bar
2300 In[1]: %name -opt foo bar
2301
2301
2302 To call a magic without arguments, simply use magic('name').
2302 To call a magic without arguments, simply use magic('name').
2303
2303
2304 This provides a proper Python function to call IPython's magics in any
2304 This provides a proper Python function to call IPython's magics in any
2305 valid Python code you can type at the interpreter, including loops and
2305 valid Python code you can type at the interpreter, including loops and
2306 compound statements.
2306 compound statements.
2307 """
2307 """
2308 # TODO: should we issue a loud deprecation warning here?
2308 # TODO: should we issue a loud deprecation warning here?
2309 magic_name, _, magic_arg_s = arg_s.partition(' ')
2309 magic_name, _, magic_arg_s = arg_s.partition(' ')
2310 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2310 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2311 return self.run_line_magic(magic_name, magic_arg_s, _stack_depth=2)
2311 return self.run_line_magic(magic_name, magic_arg_s, _stack_depth=2)
2312
2312
2313 #-------------------------------------------------------------------------
2313 #-------------------------------------------------------------------------
2314 # Things related to macros
2314 # Things related to macros
2315 #-------------------------------------------------------------------------
2315 #-------------------------------------------------------------------------
2316
2316
2317 def define_macro(self, name, themacro):
2317 def define_macro(self, name, themacro):
2318 """Define a new macro
2318 """Define a new macro
2319
2319
2320 Parameters
2320 Parameters
2321 ----------
2321 ----------
2322 name : str
2322 name : str
2323 The name of the macro.
2323 The name of the macro.
2324 themacro : str or Macro
2324 themacro : str or Macro
2325 The action to do upon invoking the macro. If a string, a new
2325 The action to do upon invoking the macro. If a string, a new
2326 Macro object is created by passing the string to it.
2326 Macro object is created by passing the string to it.
2327 """
2327 """
2328
2328
2329 from IPython.core import macro
2329 from IPython.core import macro
2330
2330
2331 if isinstance(themacro, str):
2331 if isinstance(themacro, str):
2332 themacro = macro.Macro(themacro)
2332 themacro = macro.Macro(themacro)
2333 if not isinstance(themacro, macro.Macro):
2333 if not isinstance(themacro, macro.Macro):
2334 raise ValueError('A macro must be a string or a Macro instance.')
2334 raise ValueError('A macro must be a string or a Macro instance.')
2335 self.user_ns[name] = themacro
2335 self.user_ns[name] = themacro
2336
2336
2337 #-------------------------------------------------------------------------
2337 #-------------------------------------------------------------------------
2338 # Things related to the running of system commands
2338 # Things related to the running of system commands
2339 #-------------------------------------------------------------------------
2339 #-------------------------------------------------------------------------
2340
2340
2341 def system_piped(self, cmd):
2341 def system_piped(self, cmd):
2342 """Call the given cmd in a subprocess, piping stdout/err
2342 """Call the given cmd in a subprocess, piping stdout/err
2343
2343
2344 Parameters
2344 Parameters
2345 ----------
2345 ----------
2346 cmd : str
2346 cmd : str
2347 Command to execute (can not end in '&', as background processes are
2347 Command to execute (can not end in '&', as background processes are
2348 not supported. Should not be a command that expects input
2348 not supported. Should not be a command that expects input
2349 other than simple text.
2349 other than simple text.
2350 """
2350 """
2351 if cmd.rstrip().endswith('&'):
2351 if cmd.rstrip().endswith('&'):
2352 # this is *far* from a rigorous test
2352 # this is *far* from a rigorous test
2353 # We do not support backgrounding processes because we either use
2353 # We do not support backgrounding processes because we either use
2354 # pexpect or pipes to read from. Users can always just call
2354 # pexpect or pipes to read from. Users can always just call
2355 # os.system() or use ip.system=ip.system_raw
2355 # os.system() or use ip.system=ip.system_raw
2356 # if they really want a background process.
2356 # if they really want a background process.
2357 raise OSError("Background processes not supported.")
2357 raise OSError("Background processes not supported.")
2358
2358
2359 # we explicitly do NOT return the subprocess status code, because
2359 # we explicitly do NOT return the subprocess status code, because
2360 # a non-None value would trigger :func:`sys.displayhook` calls.
2360 # a non-None value would trigger :func:`sys.displayhook` calls.
2361 # Instead, we store the exit_code in user_ns.
2361 # Instead, we store the exit_code in user_ns.
2362 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2362 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2363
2363
2364 def system_raw(self, cmd):
2364 def system_raw(self, cmd):
2365 """Call the given cmd in a subprocess using os.system on Windows or
2365 """Call the given cmd in a subprocess using os.system on Windows or
2366 subprocess.call using the system shell on other platforms.
2366 subprocess.call using the system shell on other platforms.
2367
2367
2368 Parameters
2368 Parameters
2369 ----------
2369 ----------
2370 cmd : str
2370 cmd : str
2371 Command to execute.
2371 Command to execute.
2372 """
2372 """
2373 cmd = self.var_expand(cmd, depth=1)
2373 cmd = self.var_expand(cmd, depth=1)
2374 # warn if there is an IPython magic alternative.
2374 # warn if there is an IPython magic alternative.
2375 main_cmd = cmd.split()[0]
2375 main_cmd = cmd.split()[0]
2376 has_magic_alternatives = ("pip", "conda", "cd", "ls")
2376 has_magic_alternatives = ("pip", "conda", "cd", "ls")
2377
2377
2378 # had to check if the command was an alias expanded because of `ls`
2378 # had to check if the command was an alias expanded because of `ls`
2379 is_alias_expanded = self.alias_manager.is_alias(main_cmd) and (
2379 is_alias_expanded = self.alias_manager.is_alias(main_cmd) and (
2380 self.alias_manager.retrieve_alias(main_cmd).strip() == cmd.strip()
2380 self.alias_manager.retrieve_alias(main_cmd).strip() == cmd.strip()
2381 )
2381 )
2382
2382
2383 if main_cmd in has_magic_alternatives and not is_alias_expanded:
2383 if main_cmd in has_magic_alternatives and not is_alias_expanded:
2384 warnings.warn(
2384 warnings.warn(
2385 (
2385 (
2386 "You executed the system command !{0} which may not work "
2386 "You executed the system command !{0} which may not work "
2387 "as expected. Try the IPython magic %{0} instead."
2387 "as expected. Try the IPython magic %{0} instead."
2388 ).format(main_cmd)
2388 ).format(main_cmd)
2389 )
2389 )
2390
2390
2391 # protect os.system from UNC paths on Windows, which it can't handle:
2391 # protect os.system from UNC paths on Windows, which it can't handle:
2392 if sys.platform == 'win32':
2392 if sys.platform == 'win32':
2393 from IPython.utils._process_win32 import AvoidUNCPath
2393 from IPython.utils._process_win32 import AvoidUNCPath
2394 with AvoidUNCPath() as path:
2394 with AvoidUNCPath() as path:
2395 if path is not None:
2395 if path is not None:
2396 cmd = '"pushd %s &&"%s' % (path, cmd)
2396 cmd = '"pushd %s &&"%s' % (path, cmd)
2397 try:
2397 try:
2398 ec = os.system(cmd)
2398 ec = os.system(cmd)
2399 except KeyboardInterrupt:
2399 except KeyboardInterrupt:
2400 print('\n' + self.get_exception_only(), file=sys.stderr)
2400 print('\n' + self.get_exception_only(), file=sys.stderr)
2401 ec = -2
2401 ec = -2
2402 else:
2402 else:
2403 # For posix the result of the subprocess.call() below is an exit
2403 # For posix the result of the subprocess.call() below is an exit
2404 # code, which by convention is zero for success, positive for
2404 # code, which by convention is zero for success, positive for
2405 # program failure. Exit codes above 128 are reserved for signals,
2405 # program failure. Exit codes above 128 are reserved for signals,
2406 # and the formula for converting a signal to an exit code is usually
2406 # and the formula for converting a signal to an exit code is usually
2407 # signal_number+128. To more easily differentiate between exit
2407 # signal_number+128. To more easily differentiate between exit
2408 # codes and signals, ipython uses negative numbers. For instance
2408 # codes and signals, ipython uses negative numbers. For instance
2409 # since control-c is signal 2 but exit code 130, ipython's
2409 # since control-c is signal 2 but exit code 130, ipython's
2410 # _exit_code variable will read -2. Note that some shells like
2410 # _exit_code variable will read -2. Note that some shells like
2411 # csh and fish don't follow sh/bash conventions for exit codes.
2411 # csh and fish don't follow sh/bash conventions for exit codes.
2412 executable = os.environ.get('SHELL', None)
2412 executable = os.environ.get('SHELL', None)
2413 try:
2413 try:
2414 # Use env shell instead of default /bin/sh
2414 # Use env shell instead of default /bin/sh
2415 ec = subprocess.call(cmd, shell=True, executable=executable)
2415 ec = subprocess.call(cmd, shell=True, executable=executable)
2416 except KeyboardInterrupt:
2416 except KeyboardInterrupt:
2417 # intercept control-C; a long traceback is not useful here
2417 # intercept control-C; a long traceback is not useful here
2418 print('\n' + self.get_exception_only(), file=sys.stderr)
2418 print('\n' + self.get_exception_only(), file=sys.stderr)
2419 ec = 130
2419 ec = 130
2420 if ec > 128:
2420 if ec > 128:
2421 ec = -(ec - 128)
2421 ec = -(ec - 128)
2422
2422
2423 # We explicitly do NOT return the subprocess status code, because
2423 # We explicitly do NOT return the subprocess status code, because
2424 # a non-None value would trigger :func:`sys.displayhook` calls.
2424 # a non-None value would trigger :func:`sys.displayhook` calls.
2425 # Instead, we store the exit_code in user_ns. Note the semantics
2425 # Instead, we store the exit_code in user_ns. Note the semantics
2426 # of _exit_code: for control-c, _exit_code == -signal.SIGNIT,
2426 # of _exit_code: for control-c, _exit_code == -signal.SIGNIT,
2427 # but raising SystemExit(_exit_code) will give status 254!
2427 # but raising SystemExit(_exit_code) will give status 254!
2428 self.user_ns['_exit_code'] = ec
2428 self.user_ns['_exit_code'] = ec
2429
2429
2430 # use piped system by default, because it is better behaved
2430 # use piped system by default, because it is better behaved
2431 system = system_piped
2431 system = system_piped
2432
2432
2433 def getoutput(self, cmd, split=True, depth=0):
2433 def getoutput(self, cmd, split=True, depth=0):
2434 """Get output (possibly including stderr) from a subprocess.
2434 """Get output (possibly including stderr) from a subprocess.
2435
2435
2436 Parameters
2436 Parameters
2437 ----------
2437 ----------
2438 cmd : str
2438 cmd : str
2439 Command to execute (can not end in '&', as background processes are
2439 Command to execute (can not end in '&', as background processes are
2440 not supported.
2440 not supported.
2441 split : bool, optional
2441 split : bool, optional
2442 If True, split the output into an IPython SList. Otherwise, an
2442 If True, split the output into an IPython SList. Otherwise, an
2443 IPython LSString is returned. These are objects similar to normal
2443 IPython LSString is returned. These are objects similar to normal
2444 lists and strings, with a few convenience attributes for easier
2444 lists and strings, with a few convenience attributes for easier
2445 manipulation of line-based output. You can use '?' on them for
2445 manipulation of line-based output. You can use '?' on them for
2446 details.
2446 details.
2447 depth : int, optional
2447 depth : int, optional
2448 How many frames above the caller are the local variables which should
2448 How many frames above the caller are the local variables which should
2449 be expanded in the command string? The default (0) assumes that the
2449 be expanded in the command string? The default (0) assumes that the
2450 expansion variables are in the stack frame calling this function.
2450 expansion variables are in the stack frame calling this function.
2451 """
2451 """
2452 if cmd.rstrip().endswith('&'):
2452 if cmd.rstrip().endswith('&'):
2453 # this is *far* from a rigorous test
2453 # this is *far* from a rigorous test
2454 raise OSError("Background processes not supported.")
2454 raise OSError("Background processes not supported.")
2455 out = getoutput(self.var_expand(cmd, depth=depth+1))
2455 out = getoutput(self.var_expand(cmd, depth=depth+1))
2456 if split:
2456 if split:
2457 out = SList(out.splitlines())
2457 out = SList(out.splitlines())
2458 else:
2458 else:
2459 out = LSString(out)
2459 out = LSString(out)
2460 return out
2460 return out
2461
2461
2462 #-------------------------------------------------------------------------
2462 #-------------------------------------------------------------------------
2463 # Things related to aliases
2463 # Things related to aliases
2464 #-------------------------------------------------------------------------
2464 #-------------------------------------------------------------------------
2465
2465
2466 def init_alias(self):
2466 def init_alias(self):
2467 self.alias_manager = AliasManager(shell=self, parent=self)
2467 self.alias_manager = AliasManager(shell=self, parent=self)
2468 self.configurables.append(self.alias_manager)
2468 self.configurables.append(self.alias_manager)
2469
2469
2470 #-------------------------------------------------------------------------
2470 #-------------------------------------------------------------------------
2471 # Things related to extensions
2471 # Things related to extensions
2472 #-------------------------------------------------------------------------
2472 #-------------------------------------------------------------------------
2473
2473
2474 def init_extension_manager(self):
2474 def init_extension_manager(self):
2475 self.extension_manager = ExtensionManager(shell=self, parent=self)
2475 self.extension_manager = ExtensionManager(shell=self, parent=self)
2476 self.configurables.append(self.extension_manager)
2476 self.configurables.append(self.extension_manager)
2477
2477
2478 #-------------------------------------------------------------------------
2478 #-------------------------------------------------------------------------
2479 # Things related to payloads
2479 # Things related to payloads
2480 #-------------------------------------------------------------------------
2480 #-------------------------------------------------------------------------
2481
2481
2482 def init_payload(self):
2482 def init_payload(self):
2483 self.payload_manager = PayloadManager(parent=self)
2483 self.payload_manager = PayloadManager(parent=self)
2484 self.configurables.append(self.payload_manager)
2484 self.configurables.append(self.payload_manager)
2485
2485
2486 #-------------------------------------------------------------------------
2486 #-------------------------------------------------------------------------
2487 # Things related to the prefilter
2487 # Things related to the prefilter
2488 #-------------------------------------------------------------------------
2488 #-------------------------------------------------------------------------
2489
2489
2490 def init_prefilter(self):
2490 def init_prefilter(self):
2491 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2491 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2492 self.configurables.append(self.prefilter_manager)
2492 self.configurables.append(self.prefilter_manager)
2493 # Ultimately this will be refactored in the new interpreter code, but
2493 # Ultimately this will be refactored in the new interpreter code, but
2494 # for now, we should expose the main prefilter method (there's legacy
2494 # for now, we should expose the main prefilter method (there's legacy
2495 # code out there that may rely on this).
2495 # code out there that may rely on this).
2496 self.prefilter = self.prefilter_manager.prefilter_lines
2496 self.prefilter = self.prefilter_manager.prefilter_lines
2497
2497
2498 def auto_rewrite_input(self, cmd):
2498 def auto_rewrite_input(self, cmd):
2499 """Print to the screen the rewritten form of the user's command.
2499 """Print to the screen the rewritten form of the user's command.
2500
2500
2501 This shows visual feedback by rewriting input lines that cause
2501 This shows visual feedback by rewriting input lines that cause
2502 automatic calling to kick in, like::
2502 automatic calling to kick in, like::
2503
2503
2504 /f x
2504 /f x
2505
2505
2506 into::
2506 into::
2507
2507
2508 ------> f(x)
2508 ------> f(x)
2509
2509
2510 after the user's input prompt. This helps the user understand that the
2510 after the user's input prompt. This helps the user understand that the
2511 input line was transformed automatically by IPython.
2511 input line was transformed automatically by IPython.
2512 """
2512 """
2513 if not self.show_rewritten_input:
2513 if not self.show_rewritten_input:
2514 return
2514 return
2515
2515
2516 # This is overridden in TerminalInteractiveShell to use fancy prompts
2516 # This is overridden in TerminalInteractiveShell to use fancy prompts
2517 print("------> " + cmd)
2517 print("------> " + cmd)
2518
2518
2519 #-------------------------------------------------------------------------
2519 #-------------------------------------------------------------------------
2520 # Things related to extracting values/expressions from kernel and user_ns
2520 # Things related to extracting values/expressions from kernel and user_ns
2521 #-------------------------------------------------------------------------
2521 #-------------------------------------------------------------------------
2522
2522
2523 def _user_obj_error(self):
2523 def _user_obj_error(self):
2524 """return simple exception dict
2524 """return simple exception dict
2525
2525
2526 for use in user_expressions
2526 for use in user_expressions
2527 """
2527 """
2528
2528
2529 etype, evalue, tb = self._get_exc_info()
2529 etype, evalue, tb = self._get_exc_info()
2530 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2530 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2531
2531
2532 exc_info = {
2532 exc_info = {
2533 "status": "error",
2533 "status": "error",
2534 "traceback": stb,
2534 "traceback": stb,
2535 "ename": etype.__name__,
2535 "ename": etype.__name__,
2536 "evalue": py3compat.safe_unicode(evalue),
2536 "evalue": py3compat.safe_unicode(evalue),
2537 }
2537 }
2538
2538
2539 return exc_info
2539 return exc_info
2540
2540
2541 def _format_user_obj(self, obj):
2541 def _format_user_obj(self, obj):
2542 """format a user object to display dict
2542 """format a user object to display dict
2543
2543
2544 for use in user_expressions
2544 for use in user_expressions
2545 """
2545 """
2546
2546
2547 data, md = self.display_formatter.format(obj)
2547 data, md = self.display_formatter.format(obj)
2548 value = {
2548 value = {
2549 'status' : 'ok',
2549 'status' : 'ok',
2550 'data' : data,
2550 'data' : data,
2551 'metadata' : md,
2551 'metadata' : md,
2552 }
2552 }
2553 return value
2553 return value
2554
2554
2555 def user_expressions(self, expressions):
2555 def user_expressions(self, expressions):
2556 """Evaluate a dict of expressions in the user's namespace.
2556 """Evaluate a dict of expressions in the user's namespace.
2557
2557
2558 Parameters
2558 Parameters
2559 ----------
2559 ----------
2560 expressions : dict
2560 expressions : dict
2561 A dict with string keys and string values. The expression values
2561 A dict with string keys and string values. The expression values
2562 should be valid Python expressions, each of which will be evaluated
2562 should be valid Python expressions, each of which will be evaluated
2563 in the user namespace.
2563 in the user namespace.
2564
2564
2565 Returns
2565 Returns
2566 -------
2566 -------
2567 A dict, keyed like the input expressions dict, with the rich mime-typed
2567 A dict, keyed like the input expressions dict, with the rich mime-typed
2568 display_data of each value.
2568 display_data of each value.
2569 """
2569 """
2570 out = {}
2570 out = {}
2571 user_ns = self.user_ns
2571 user_ns = self.user_ns
2572 global_ns = self.user_global_ns
2572 global_ns = self.user_global_ns
2573
2573
2574 for key, expr in expressions.items():
2574 for key, expr in expressions.items():
2575 try:
2575 try:
2576 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2576 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2577 except:
2577 except:
2578 value = self._user_obj_error()
2578 value = self._user_obj_error()
2579 out[key] = value
2579 out[key] = value
2580 return out
2580 return out
2581
2581
2582 #-------------------------------------------------------------------------
2582 #-------------------------------------------------------------------------
2583 # Things related to the running of code
2583 # Things related to the running of code
2584 #-------------------------------------------------------------------------
2584 #-------------------------------------------------------------------------
2585
2585
2586 def ex(self, cmd):
2586 def ex(self, cmd):
2587 """Execute a normal python statement in user namespace."""
2587 """Execute a normal python statement in user namespace."""
2588 with self.builtin_trap:
2588 with self.builtin_trap:
2589 exec(cmd, self.user_global_ns, self.user_ns)
2589 exec(cmd, self.user_global_ns, self.user_ns)
2590
2590
2591 def ev(self, expr):
2591 def ev(self, expr):
2592 """Evaluate python expression expr in user namespace.
2592 """Evaluate python expression expr in user namespace.
2593
2593
2594 Returns the result of evaluation
2594 Returns the result of evaluation
2595 """
2595 """
2596 with self.builtin_trap:
2596 with self.builtin_trap:
2597 return eval(expr, self.user_global_ns, self.user_ns)
2597 return eval(expr, self.user_global_ns, self.user_ns)
2598
2598
2599 def safe_execfile(self, fname, *where, exit_ignore=False, raise_exceptions=False, shell_futures=False):
2599 def safe_execfile(self, fname, *where, exit_ignore=False, raise_exceptions=False, shell_futures=False):
2600 """A safe version of the builtin execfile().
2600 """A safe version of the builtin execfile().
2601
2601
2602 This version will never throw an exception, but instead print
2602 This version will never throw an exception, but instead print
2603 helpful error messages to the screen. This only works on pure
2603 helpful error messages to the screen. This only works on pure
2604 Python files with the .py extension.
2604 Python files with the .py extension.
2605
2605
2606 Parameters
2606 Parameters
2607 ----------
2607 ----------
2608 fname : string
2608 fname : string
2609 The name of the file to be executed.
2609 The name of the file to be executed.
2610 *where : tuple
2610 *where : tuple
2611 One or two namespaces, passed to execfile() as (globals,locals).
2611 One or two namespaces, passed to execfile() as (globals,locals).
2612 If only one is given, it is passed as both.
2612 If only one is given, it is passed as both.
2613 exit_ignore : bool (False)
2613 exit_ignore : bool (False)
2614 If True, then silence SystemExit for non-zero status (it is always
2614 If True, then silence SystemExit for non-zero status (it is always
2615 silenced for zero status, as it is so common).
2615 silenced for zero status, as it is so common).
2616 raise_exceptions : bool (False)
2616 raise_exceptions : bool (False)
2617 If True raise exceptions everywhere. Meant for testing.
2617 If True raise exceptions everywhere. Meant for testing.
2618 shell_futures : bool (False)
2618 shell_futures : bool (False)
2619 If True, the code will share future statements with the interactive
2619 If True, the code will share future statements with the interactive
2620 shell. It will both be affected by previous __future__ imports, and
2620 shell. It will both be affected by previous __future__ imports, and
2621 any __future__ imports in the code will affect the shell. If False,
2621 any __future__ imports in the code will affect the shell. If False,
2622 __future__ imports are not shared in either direction.
2622 __future__ imports are not shared in either direction.
2623
2623
2624 """
2624 """
2625 fname = Path(fname).expanduser().resolve()
2625 fname = Path(fname).expanduser().resolve()
2626
2626
2627 # Make sure we can open the file
2627 # Make sure we can open the file
2628 try:
2628 try:
2629 with fname.open('rb'):
2629 with fname.open("rb"):
2630 pass
2630 pass
2631 except:
2631 except:
2632 warn('Could not open file <%s> for safe execution.' % fname)
2632 warn('Could not open file <%s> for safe execution.' % fname)
2633 return
2633 return
2634
2634
2635 # Find things also in current directory. This is needed to mimic the
2635 # Find things also in current directory. This is needed to mimic the
2636 # behavior of running a script from the system command line, where
2636 # behavior of running a script from the system command line, where
2637 # Python inserts the script's directory into sys.path
2637 # Python inserts the script's directory into sys.path
2638 dname = str(fname.parent)
2638 dname = str(fname.parent)
2639
2639
2640 with prepended_to_syspath(dname), self.builtin_trap:
2640 with prepended_to_syspath(dname), self.builtin_trap:
2641 try:
2641 try:
2642 glob, loc = (where + (None, ))[:2]
2642 glob, loc = (where + (None, ))[:2]
2643 py3compat.execfile(
2643 py3compat.execfile(
2644 fname, glob, loc,
2644 fname, glob, loc,
2645 self.compile if shell_futures else None)
2645 self.compile if shell_futures else None)
2646 except SystemExit as status:
2646 except SystemExit as status:
2647 # If the call was made with 0 or None exit status (sys.exit(0)
2647 # If the call was made with 0 or None exit status (sys.exit(0)
2648 # or sys.exit() ), don't bother showing a traceback, as both of
2648 # or sys.exit() ), don't bother showing a traceback, as both of
2649 # these are considered normal by the OS:
2649 # these are considered normal by the OS:
2650 # > python -c'import sys;sys.exit(0)'; echo $?
2650 # > python -c'import sys;sys.exit(0)'; echo $?
2651 # 0
2651 # 0
2652 # > python -c'import sys;sys.exit()'; echo $?
2652 # > python -c'import sys;sys.exit()'; echo $?
2653 # 0
2653 # 0
2654 # For other exit status, we show the exception unless
2654 # For other exit status, we show the exception unless
2655 # explicitly silenced, but only in short form.
2655 # explicitly silenced, but only in short form.
2656 if status.code:
2656 if status.code:
2657 if raise_exceptions:
2657 if raise_exceptions:
2658 raise
2658 raise
2659 if not exit_ignore:
2659 if not exit_ignore:
2660 self.showtraceback(exception_only=True)
2660 self.showtraceback(exception_only=True)
2661 except:
2661 except:
2662 if raise_exceptions:
2662 if raise_exceptions:
2663 raise
2663 raise
2664 # tb offset is 2 because we wrap execfile
2664 # tb offset is 2 because we wrap execfile
2665 self.showtraceback(tb_offset=2)
2665 self.showtraceback(tb_offset=2)
2666
2666
2667 def safe_execfile_ipy(self, fname, shell_futures=False, raise_exceptions=False):
2667 def safe_execfile_ipy(self, fname, shell_futures=False, raise_exceptions=False):
2668 """Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
2668 """Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
2669
2669
2670 Parameters
2670 Parameters
2671 ----------
2671 ----------
2672 fname : str
2672 fname : str
2673 The name of the file to execute. The filename must have a
2673 The name of the file to execute. The filename must have a
2674 .ipy or .ipynb extension.
2674 .ipy or .ipynb extension.
2675 shell_futures : bool (False)
2675 shell_futures : bool (False)
2676 If True, the code will share future statements with the interactive
2676 If True, the code will share future statements with the interactive
2677 shell. It will both be affected by previous __future__ imports, and
2677 shell. It will both be affected by previous __future__ imports, and
2678 any __future__ imports in the code will affect the shell. If False,
2678 any __future__ imports in the code will affect the shell. If False,
2679 __future__ imports are not shared in either direction.
2679 __future__ imports are not shared in either direction.
2680 raise_exceptions : bool (False)
2680 raise_exceptions : bool (False)
2681 If True raise exceptions everywhere. Meant for testing.
2681 If True raise exceptions everywhere. Meant for testing.
2682 """
2682 """
2683 fname = Path(fname).expanduser().resolve()
2683 fname = Path(fname).expanduser().resolve()
2684
2684
2685 # Make sure we can open the file
2685 # Make sure we can open the file
2686 try:
2686 try:
2687 with fname.open('rb'):
2687 with fname.open("rb"):
2688 pass
2688 pass
2689 except:
2689 except:
2690 warn('Could not open file <%s> for safe execution.' % fname)
2690 warn('Could not open file <%s> for safe execution.' % fname)
2691 return
2691 return
2692
2692
2693 # Find things also in current directory. This is needed to mimic the
2693 # Find things also in current directory. This is needed to mimic the
2694 # behavior of running a script from the system command line, where
2694 # behavior of running a script from the system command line, where
2695 # Python inserts the script's directory into sys.path
2695 # Python inserts the script's directory into sys.path
2696 dname = str(fname.parent)
2696 dname = str(fname.parent)
2697
2697
2698 def get_cells():
2698 def get_cells():
2699 """generator for sequence of code blocks to run"""
2699 """generator for sequence of code blocks to run"""
2700 if fname.suffix == ".ipynb":
2700 if fname.suffix == ".ipynb":
2701 from nbformat import read
2701 from nbformat import read
2702 nb = read(fname, as_version=4)
2702 nb = read(fname, as_version=4)
2703 if not nb.cells:
2703 if not nb.cells:
2704 return
2704 return
2705 for cell in nb.cells:
2705 for cell in nb.cells:
2706 if cell.cell_type == 'code':
2706 if cell.cell_type == 'code':
2707 yield cell.source
2707 yield cell.source
2708 else:
2708 else:
2709 yield fname.read_text(encoding='utf-8')
2709 yield fname.read_text(encoding="utf-8")
2710
2710
2711 with prepended_to_syspath(dname):
2711 with prepended_to_syspath(dname):
2712 try:
2712 try:
2713 for cell in get_cells():
2713 for cell in get_cells():
2714 result = self.run_cell(cell, silent=True, shell_futures=shell_futures)
2714 result = self.run_cell(cell, silent=True, shell_futures=shell_futures)
2715 if raise_exceptions:
2715 if raise_exceptions:
2716 result.raise_error()
2716 result.raise_error()
2717 elif not result.success:
2717 elif not result.success:
2718 break
2718 break
2719 except:
2719 except:
2720 if raise_exceptions:
2720 if raise_exceptions:
2721 raise
2721 raise
2722 self.showtraceback()
2722 self.showtraceback()
2723 warn('Unknown failure executing file: <%s>' % fname)
2723 warn('Unknown failure executing file: <%s>' % fname)
2724
2724
2725 def safe_run_module(self, mod_name, where):
2725 def safe_run_module(self, mod_name, where):
2726 """A safe version of runpy.run_module().
2726 """A safe version of runpy.run_module().
2727
2727
2728 This version will never throw an exception, but instead print
2728 This version will never throw an exception, but instead print
2729 helpful error messages to the screen.
2729 helpful error messages to the screen.
2730
2730
2731 `SystemExit` exceptions with status code 0 or None are ignored.
2731 `SystemExit` exceptions with status code 0 or None are ignored.
2732
2732
2733 Parameters
2733 Parameters
2734 ----------
2734 ----------
2735 mod_name : string
2735 mod_name : string
2736 The name of the module to be executed.
2736 The name of the module to be executed.
2737 where : dict
2737 where : dict
2738 The globals namespace.
2738 The globals namespace.
2739 """
2739 """
2740 try:
2740 try:
2741 try:
2741 try:
2742 where.update(
2742 where.update(
2743 runpy.run_module(str(mod_name), run_name="__main__",
2743 runpy.run_module(str(mod_name), run_name="__main__",
2744 alter_sys=True)
2744 alter_sys=True)
2745 )
2745 )
2746 except SystemExit as status:
2746 except SystemExit as status:
2747 if status.code:
2747 if status.code:
2748 raise
2748 raise
2749 except:
2749 except:
2750 self.showtraceback()
2750 self.showtraceback()
2751 warn('Unknown failure executing module: <%s>' % mod_name)
2751 warn('Unknown failure executing module: <%s>' % mod_name)
2752
2752
2753 def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=True):
2753 def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=True):
2754 """Run a complete IPython cell.
2754 """Run a complete IPython cell.
2755
2755
2756 Parameters
2756 Parameters
2757 ----------
2757 ----------
2758 raw_cell : str
2758 raw_cell : str
2759 The code (including IPython code such as %magic functions) to run.
2759 The code (including IPython code such as %magic functions) to run.
2760 store_history : bool
2760 store_history : bool
2761 If True, the raw and translated cell will be stored in IPython's
2761 If True, the raw and translated cell will be stored in IPython's
2762 history. For user code calling back into IPython's machinery, this
2762 history. For user code calling back into IPython's machinery, this
2763 should be set to False.
2763 should be set to False.
2764 silent : bool
2764 silent : bool
2765 If True, avoid side-effects, such as implicit displayhooks and
2765 If True, avoid side-effects, such as implicit displayhooks and
2766 and logging. silent=True forces store_history=False.
2766 and logging. silent=True forces store_history=False.
2767 shell_futures : bool
2767 shell_futures : bool
2768 If True, the code will share future statements with the interactive
2768 If True, the code will share future statements with the interactive
2769 shell. It will both be affected by previous __future__ imports, and
2769 shell. It will both be affected by previous __future__ imports, and
2770 any __future__ imports in the code will affect the shell. If False,
2770 any __future__ imports in the code will affect the shell. If False,
2771 __future__ imports are not shared in either direction.
2771 __future__ imports are not shared in either direction.
2772
2772
2773 Returns
2773 Returns
2774 -------
2774 -------
2775 result : :class:`ExecutionResult`
2775 result : :class:`ExecutionResult`
2776 """
2776 """
2777 result = None
2777 result = None
2778 try:
2778 try:
2779 result = self._run_cell(
2779 result = self._run_cell(
2780 raw_cell, store_history, silent, shell_futures)
2780 raw_cell, store_history, silent, shell_futures)
2781 finally:
2781 finally:
2782 self.events.trigger('post_execute')
2782 self.events.trigger('post_execute')
2783 if not silent:
2783 if not silent:
2784 self.events.trigger('post_run_cell', result)
2784 self.events.trigger('post_run_cell', result)
2785 return result
2785 return result
2786
2786
2787 def _run_cell(self, raw_cell:str, store_history:bool, silent:bool, shell_futures:bool) -> ExecutionResult:
2787 def _run_cell(self, raw_cell:str, store_history:bool, silent:bool, shell_futures:bool) -> ExecutionResult:
2788 """Internal method to run a complete IPython cell."""
2788 """Internal method to run a complete IPython cell."""
2789
2789
2790 # we need to avoid calling self.transform_cell multiple time on the same thing
2790 # we need to avoid calling self.transform_cell multiple time on the same thing
2791 # so we need to store some results:
2791 # so we need to store some results:
2792 preprocessing_exc_tuple = None
2792 preprocessing_exc_tuple = None
2793 try:
2793 try:
2794 transformed_cell = self.transform_cell(raw_cell)
2794 transformed_cell = self.transform_cell(raw_cell)
2795 except Exception:
2795 except Exception:
2796 transformed_cell = raw_cell
2796 transformed_cell = raw_cell
2797 preprocessing_exc_tuple = sys.exc_info()
2797 preprocessing_exc_tuple = sys.exc_info()
2798
2798
2799 assert transformed_cell is not None
2799 assert transformed_cell is not None
2800 coro = self.run_cell_async(
2800 coro = self.run_cell_async(
2801 raw_cell,
2801 raw_cell,
2802 store_history=store_history,
2802 store_history=store_history,
2803 silent=silent,
2803 silent=silent,
2804 shell_futures=shell_futures,
2804 shell_futures=shell_futures,
2805 transformed_cell=transformed_cell,
2805 transformed_cell=transformed_cell,
2806 preprocessing_exc_tuple=preprocessing_exc_tuple,
2806 preprocessing_exc_tuple=preprocessing_exc_tuple,
2807 )
2807 )
2808
2808
2809 # run_cell_async is async, but may not actually need an eventloop.
2809 # run_cell_async is async, but may not actually need an eventloop.
2810 # when this is the case, we want to run it using the pseudo_sync_runner
2810 # when this is the case, we want to run it using the pseudo_sync_runner
2811 # so that code can invoke eventloops (for example via the %run , and
2811 # so that code can invoke eventloops (for example via the %run , and
2812 # `%paste` magic.
2812 # `%paste` magic.
2813 if self.trio_runner:
2813 if self.trio_runner:
2814 runner = self.trio_runner
2814 runner = self.trio_runner
2815 elif self.should_run_async(
2815 elif self.should_run_async(
2816 raw_cell,
2816 raw_cell,
2817 transformed_cell=transformed_cell,
2817 transformed_cell=transformed_cell,
2818 preprocessing_exc_tuple=preprocessing_exc_tuple,
2818 preprocessing_exc_tuple=preprocessing_exc_tuple,
2819 ):
2819 ):
2820 runner = self.loop_runner
2820 runner = self.loop_runner
2821 else:
2821 else:
2822 runner = _pseudo_sync_runner
2822 runner = _pseudo_sync_runner
2823
2823
2824 try:
2824 try:
2825 return runner(coro)
2825 return runner(coro)
2826 except BaseException as e:
2826 except BaseException as e:
2827 info = ExecutionInfo(raw_cell, store_history, silent, shell_futures)
2827 info = ExecutionInfo(raw_cell, store_history, silent, shell_futures)
2828 result = ExecutionResult(info)
2828 result = ExecutionResult(info)
2829 result.error_in_exec = e
2829 result.error_in_exec = e
2830 self.showtraceback(running_compiled_code=True)
2830 self.showtraceback(running_compiled_code=True)
2831 return result
2831 return result
2832
2832
2833 def should_run_async(
2833 def should_run_async(
2834 self, raw_cell: str, *, transformed_cell=None, preprocessing_exc_tuple=None
2834 self, raw_cell: str, *, transformed_cell=None, preprocessing_exc_tuple=None
2835 ) -> bool:
2835 ) -> bool:
2836 """Return whether a cell should be run asynchronously via a coroutine runner
2836 """Return whether a cell should be run asynchronously via a coroutine runner
2837
2837
2838 Parameters
2838 Parameters
2839 ----------
2839 ----------
2840 raw_cell : str
2840 raw_cell : str
2841 The code to be executed
2841 The code to be executed
2842
2842
2843 Returns
2843 Returns
2844 -------
2844 -------
2845 result: bool
2845 result: bool
2846 Whether the code needs to be run with a coroutine runner or not
2846 Whether the code needs to be run with a coroutine runner or not
2847 .. versionadded:: 7.0
2847 .. versionadded:: 7.0
2848 """
2848 """
2849 if not self.autoawait:
2849 if not self.autoawait:
2850 return False
2850 return False
2851 if preprocessing_exc_tuple is not None:
2851 if preprocessing_exc_tuple is not None:
2852 return False
2852 return False
2853 assert preprocessing_exc_tuple is None
2853 assert preprocessing_exc_tuple is None
2854 if transformed_cell is None:
2854 if transformed_cell is None:
2855 warnings.warn(
2855 warnings.warn(
2856 "`should_run_async` will not call `transform_cell`"
2856 "`should_run_async` will not call `transform_cell`"
2857 " automatically in the future. Please pass the result to"
2857 " automatically in the future. Please pass the result to"
2858 " `transformed_cell` argument and any exception that happen"
2858 " `transformed_cell` argument and any exception that happen"
2859 " during the"
2859 " during the"
2860 "transform in `preprocessing_exc_tuple` in"
2860 "transform in `preprocessing_exc_tuple` in"
2861 " IPython 7.17 and above.",
2861 " IPython 7.17 and above.",
2862 DeprecationWarning,
2862 DeprecationWarning,
2863 stacklevel=2,
2863 stacklevel=2,
2864 )
2864 )
2865 try:
2865 try:
2866 cell = self.transform_cell(raw_cell)
2866 cell = self.transform_cell(raw_cell)
2867 except Exception:
2867 except Exception:
2868 # any exception during transform will be raised
2868 # any exception during transform will be raised
2869 # prior to execution
2869 # prior to execution
2870 return False
2870 return False
2871 else:
2871 else:
2872 cell = transformed_cell
2872 cell = transformed_cell
2873 return _should_be_async(cell)
2873 return _should_be_async(cell)
2874
2874
2875 async def run_cell_async(
2875 async def run_cell_async(
2876 self,
2876 self,
2877 raw_cell: str,
2877 raw_cell: str,
2878 store_history=False,
2878 store_history=False,
2879 silent=False,
2879 silent=False,
2880 shell_futures=True,
2880 shell_futures=True,
2881 *,
2881 *,
2882 transformed_cell: Optional[str] = None,
2882 transformed_cell: Optional[str] = None,
2883 preprocessing_exc_tuple: Optional[Any] = None
2883 preprocessing_exc_tuple: Optional[Any] = None
2884 ) -> ExecutionResult:
2884 ) -> ExecutionResult:
2885 """Run a complete IPython cell asynchronously.
2885 """Run a complete IPython cell asynchronously.
2886
2886
2887 Parameters
2887 Parameters
2888 ----------
2888 ----------
2889 raw_cell : str
2889 raw_cell : str
2890 The code (including IPython code such as %magic functions) to run.
2890 The code (including IPython code such as %magic functions) to run.
2891 store_history : bool
2891 store_history : bool
2892 If True, the raw and translated cell will be stored in IPython's
2892 If True, the raw and translated cell will be stored in IPython's
2893 history. For user code calling back into IPython's machinery, this
2893 history. For user code calling back into IPython's machinery, this
2894 should be set to False.
2894 should be set to False.
2895 silent : bool
2895 silent : bool
2896 If True, avoid side-effects, such as implicit displayhooks and
2896 If True, avoid side-effects, such as implicit displayhooks and
2897 and logging. silent=True forces store_history=False.
2897 and logging. silent=True forces store_history=False.
2898 shell_futures : bool
2898 shell_futures : bool
2899 If True, the code will share future statements with the interactive
2899 If True, the code will share future statements with the interactive
2900 shell. It will both be affected by previous __future__ imports, and
2900 shell. It will both be affected by previous __future__ imports, and
2901 any __future__ imports in the code will affect the shell. If False,
2901 any __future__ imports in the code will affect the shell. If False,
2902 __future__ imports are not shared in either direction.
2902 __future__ imports are not shared in either direction.
2903 transformed_cell: str
2903 transformed_cell: str
2904 cell that was passed through transformers
2904 cell that was passed through transformers
2905 preprocessing_exc_tuple:
2905 preprocessing_exc_tuple:
2906 trace if the transformation failed.
2906 trace if the transformation failed.
2907
2907
2908 Returns
2908 Returns
2909 -------
2909 -------
2910 result : :class:`ExecutionResult`
2910 result : :class:`ExecutionResult`
2911
2911
2912 .. versionadded:: 7.0
2912 .. versionadded:: 7.0
2913 """
2913 """
2914 info = ExecutionInfo(
2914 info = ExecutionInfo(
2915 raw_cell, store_history, silent, shell_futures)
2915 raw_cell, store_history, silent, shell_futures)
2916 result = ExecutionResult(info)
2916 result = ExecutionResult(info)
2917
2917
2918 if (not raw_cell) or raw_cell.isspace():
2918 if (not raw_cell) or raw_cell.isspace():
2919 self.last_execution_succeeded = True
2919 self.last_execution_succeeded = True
2920 self.last_execution_result = result
2920 self.last_execution_result = result
2921 return result
2921 return result
2922
2922
2923 if silent:
2923 if silent:
2924 store_history = False
2924 store_history = False
2925
2925
2926 if store_history:
2926 if store_history:
2927 result.execution_count = self.execution_count
2927 result.execution_count = self.execution_count
2928
2928
2929 def error_before_exec(value):
2929 def error_before_exec(value):
2930 if store_history:
2930 if store_history:
2931 self.execution_count += 1
2931 self.execution_count += 1
2932 result.error_before_exec = value
2932 result.error_before_exec = value
2933 self.last_execution_succeeded = False
2933 self.last_execution_succeeded = False
2934 self.last_execution_result = result
2934 self.last_execution_result = result
2935 return result
2935 return result
2936
2936
2937 self.events.trigger('pre_execute')
2937 self.events.trigger('pre_execute')
2938 if not silent:
2938 if not silent:
2939 self.events.trigger('pre_run_cell', info)
2939 self.events.trigger('pre_run_cell', info)
2940
2940
2941 if transformed_cell is None:
2941 if transformed_cell is None:
2942 warnings.warn(
2942 warnings.warn(
2943 "`run_cell_async` will not call `transform_cell`"
2943 "`run_cell_async` will not call `transform_cell`"
2944 " automatically in the future. Please pass the result to"
2944 " automatically in the future. Please pass the result to"
2945 " `transformed_cell` argument and any exception that happen"
2945 " `transformed_cell` argument and any exception that happen"
2946 " during the"
2946 " during the"
2947 "transform in `preprocessing_exc_tuple` in"
2947 "transform in `preprocessing_exc_tuple` in"
2948 " IPython 7.17 and above.",
2948 " IPython 7.17 and above.",
2949 DeprecationWarning,
2949 DeprecationWarning,
2950 stacklevel=2,
2950 stacklevel=2,
2951 )
2951 )
2952 # If any of our input transformation (input_transformer_manager or
2952 # If any of our input transformation (input_transformer_manager or
2953 # prefilter_manager) raises an exception, we store it in this variable
2953 # prefilter_manager) raises an exception, we store it in this variable
2954 # so that we can display the error after logging the input and storing
2954 # so that we can display the error after logging the input and storing
2955 # it in the history.
2955 # it in the history.
2956 try:
2956 try:
2957 cell = self.transform_cell(raw_cell)
2957 cell = self.transform_cell(raw_cell)
2958 except Exception:
2958 except Exception:
2959 preprocessing_exc_tuple = sys.exc_info()
2959 preprocessing_exc_tuple = sys.exc_info()
2960 cell = raw_cell # cell has to exist so it can be stored/logged
2960 cell = raw_cell # cell has to exist so it can be stored/logged
2961 else:
2961 else:
2962 preprocessing_exc_tuple = None
2962 preprocessing_exc_tuple = None
2963 else:
2963 else:
2964 if preprocessing_exc_tuple is None:
2964 if preprocessing_exc_tuple is None:
2965 cell = transformed_cell
2965 cell = transformed_cell
2966 else:
2966 else:
2967 cell = raw_cell
2967 cell = raw_cell
2968
2968
2969 # Store raw and processed history
2969 # Store raw and processed history
2970 if store_history:
2970 if store_history:
2971 self.history_manager.store_inputs(self.execution_count,
2971 self.history_manager.store_inputs(self.execution_count,
2972 cell, raw_cell)
2972 cell, raw_cell)
2973 if not silent:
2973 if not silent:
2974 self.logger.log(cell, raw_cell)
2974 self.logger.log(cell, raw_cell)
2975
2975
2976 # Display the exception if input processing failed.
2976 # Display the exception if input processing failed.
2977 if preprocessing_exc_tuple is not None:
2977 if preprocessing_exc_tuple is not None:
2978 self.showtraceback(preprocessing_exc_tuple)
2978 self.showtraceback(preprocessing_exc_tuple)
2979 if store_history:
2979 if store_history:
2980 self.execution_count += 1
2980 self.execution_count += 1
2981 return error_before_exec(preprocessing_exc_tuple[1])
2981 return error_before_exec(preprocessing_exc_tuple[1])
2982
2982
2983 # Our own compiler remembers the __future__ environment. If we want to
2983 # Our own compiler remembers the __future__ environment. If we want to
2984 # run code with a separate __future__ environment, use the default
2984 # run code with a separate __future__ environment, use the default
2985 # compiler
2985 # compiler
2986 compiler = self.compile if shell_futures else self.compiler_class()
2986 compiler = self.compile if shell_futures else self.compiler_class()
2987
2987
2988 _run_async = False
2988 _run_async = False
2989
2989
2990 with self.builtin_trap:
2990 with self.builtin_trap:
2991 cell_name = compiler.cache(cell, self.execution_count, raw_code=raw_cell)
2991 cell_name = compiler.cache(cell, self.execution_count, raw_code=raw_cell)
2992
2992
2993 with self.display_trap:
2993 with self.display_trap:
2994 # Compile to bytecode
2994 # Compile to bytecode
2995 try:
2995 try:
2996 code_ast = compiler.ast_parse(cell, filename=cell_name)
2996 code_ast = compiler.ast_parse(cell, filename=cell_name)
2997 except self.custom_exceptions as e:
2997 except self.custom_exceptions as e:
2998 etype, value, tb = sys.exc_info()
2998 etype, value, tb = sys.exc_info()
2999 self.CustomTB(etype, value, tb)
2999 self.CustomTB(etype, value, tb)
3000 return error_before_exec(e)
3000 return error_before_exec(e)
3001 except IndentationError as e:
3001 except IndentationError as e:
3002 self.showindentationerror()
3002 self.showindentationerror()
3003 return error_before_exec(e)
3003 return error_before_exec(e)
3004 except (OverflowError, SyntaxError, ValueError, TypeError,
3004 except (OverflowError, SyntaxError, ValueError, TypeError,
3005 MemoryError) as e:
3005 MemoryError) as e:
3006 self.showsyntaxerror()
3006 self.showsyntaxerror()
3007 return error_before_exec(e)
3007 return error_before_exec(e)
3008
3008
3009 # Apply AST transformations
3009 # Apply AST transformations
3010 try:
3010 try:
3011 code_ast = self.transform_ast(code_ast)
3011 code_ast = self.transform_ast(code_ast)
3012 except InputRejected as e:
3012 except InputRejected as e:
3013 self.showtraceback()
3013 self.showtraceback()
3014 return error_before_exec(e)
3014 return error_before_exec(e)
3015
3015
3016 # Give the displayhook a reference to our ExecutionResult so it
3016 # Give the displayhook a reference to our ExecutionResult so it
3017 # can fill in the output value.
3017 # can fill in the output value.
3018 self.displayhook.exec_result = result
3018 self.displayhook.exec_result = result
3019
3019
3020 # Execute the user code
3020 # Execute the user code
3021 interactivity = "none" if silent else self.ast_node_interactivity
3021 interactivity = "none" if silent else self.ast_node_interactivity
3022
3022
3023 has_raised = await self.run_ast_nodes(code_ast.body, cell_name,
3023 has_raised = await self.run_ast_nodes(code_ast.body, cell_name,
3024 interactivity=interactivity, compiler=compiler, result=result)
3024 interactivity=interactivity, compiler=compiler, result=result)
3025
3025
3026 self.last_execution_succeeded = not has_raised
3026 self.last_execution_succeeded = not has_raised
3027 self.last_execution_result = result
3027 self.last_execution_result = result
3028
3028
3029 # Reset this so later displayed values do not modify the
3029 # Reset this so later displayed values do not modify the
3030 # ExecutionResult
3030 # ExecutionResult
3031 self.displayhook.exec_result = None
3031 self.displayhook.exec_result = None
3032
3032
3033 if store_history:
3033 if store_history:
3034 # Write output to the database. Does nothing unless
3034 # Write output to the database. Does nothing unless
3035 # history output logging is enabled.
3035 # history output logging is enabled.
3036 self.history_manager.store_output(self.execution_count)
3036 self.history_manager.store_output(self.execution_count)
3037 # Each cell is a *single* input, regardless of how many lines it has
3037 # Each cell is a *single* input, regardless of how many lines it has
3038 self.execution_count += 1
3038 self.execution_count += 1
3039
3039
3040 return result
3040 return result
3041
3041
3042 def transform_cell(self, raw_cell):
3042 def transform_cell(self, raw_cell):
3043 """Transform an input cell before parsing it.
3043 """Transform an input cell before parsing it.
3044
3044
3045 Static transformations, implemented in IPython.core.inputtransformer2,
3045 Static transformations, implemented in IPython.core.inputtransformer2,
3046 deal with things like ``%magic`` and ``!system`` commands.
3046 deal with things like ``%magic`` and ``!system`` commands.
3047 These run on all input.
3047 These run on all input.
3048 Dynamic transformations, for things like unescaped magics and the exit
3048 Dynamic transformations, for things like unescaped magics and the exit
3049 autocall, depend on the state of the interpreter.
3049 autocall, depend on the state of the interpreter.
3050 These only apply to single line inputs.
3050 These only apply to single line inputs.
3051
3051
3052 These string-based transformations are followed by AST transformations;
3052 These string-based transformations are followed by AST transformations;
3053 see :meth:`transform_ast`.
3053 see :meth:`transform_ast`.
3054 """
3054 """
3055 # Static input transformations
3055 # Static input transformations
3056 cell = self.input_transformer_manager.transform_cell(raw_cell)
3056 cell = self.input_transformer_manager.transform_cell(raw_cell)
3057
3057
3058 if len(cell.splitlines()) == 1:
3058 if len(cell.splitlines()) == 1:
3059 # Dynamic transformations - only applied for single line commands
3059 # Dynamic transformations - only applied for single line commands
3060 with self.builtin_trap:
3060 with self.builtin_trap:
3061 # use prefilter_lines to handle trailing newlines
3061 # use prefilter_lines to handle trailing newlines
3062 # restore trailing newline for ast.parse
3062 # restore trailing newline for ast.parse
3063 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
3063 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
3064
3064
3065 lines = cell.splitlines(keepends=True)
3065 lines = cell.splitlines(keepends=True)
3066 for transform in self.input_transformers_post:
3066 for transform in self.input_transformers_post:
3067 lines = transform(lines)
3067 lines = transform(lines)
3068 cell = ''.join(lines)
3068 cell = ''.join(lines)
3069
3069
3070 return cell
3070 return cell
3071
3071
3072 def transform_ast(self, node):
3072 def transform_ast(self, node):
3073 """Apply the AST transformations from self.ast_transformers
3073 """Apply the AST transformations from self.ast_transformers
3074
3074
3075 Parameters
3075 Parameters
3076 ----------
3076 ----------
3077 node : ast.Node
3077 node : ast.Node
3078 The root node to be transformed. Typically called with the ast.Module
3078 The root node to be transformed. Typically called with the ast.Module
3079 produced by parsing user input.
3079 produced by parsing user input.
3080
3080
3081 Returns
3081 Returns
3082 -------
3082 -------
3083 An ast.Node corresponding to the node it was called with. Note that it
3083 An ast.Node corresponding to the node it was called with. Note that it
3084 may also modify the passed object, so don't rely on references to the
3084 may also modify the passed object, so don't rely on references to the
3085 original AST.
3085 original AST.
3086 """
3086 """
3087 for transformer in self.ast_transformers:
3087 for transformer in self.ast_transformers:
3088 try:
3088 try:
3089 node = transformer.visit(node)
3089 node = transformer.visit(node)
3090 except InputRejected:
3090 except InputRejected:
3091 # User-supplied AST transformers can reject an input by raising
3091 # User-supplied AST transformers can reject an input by raising
3092 # an InputRejected. Short-circuit in this case so that we
3092 # an InputRejected. Short-circuit in this case so that we
3093 # don't unregister the transform.
3093 # don't unregister the transform.
3094 raise
3094 raise
3095 except Exception:
3095 except Exception:
3096 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
3096 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
3097 self.ast_transformers.remove(transformer)
3097 self.ast_transformers.remove(transformer)
3098
3098
3099 if self.ast_transformers:
3099 if self.ast_transformers:
3100 ast.fix_missing_locations(node)
3100 ast.fix_missing_locations(node)
3101 return node
3101 return node
3102
3102
3103 async def run_ast_nodes(
3103 async def run_ast_nodes(
3104 self,
3104 self,
3105 nodelist: ListType[stmt],
3105 nodelist: ListType[stmt],
3106 cell_name: str,
3106 cell_name: str,
3107 interactivity="last_expr",
3107 interactivity="last_expr",
3108 compiler=compile,
3108 compiler=compile,
3109 result=None,
3109 result=None,
3110 ):
3110 ):
3111 """Run a sequence of AST nodes. The execution mode depends on the
3111 """Run a sequence of AST nodes. The execution mode depends on the
3112 interactivity parameter.
3112 interactivity parameter.
3113
3113
3114 Parameters
3114 Parameters
3115 ----------
3115 ----------
3116 nodelist : list
3116 nodelist : list
3117 A sequence of AST nodes to run.
3117 A sequence of AST nodes to run.
3118 cell_name : str
3118 cell_name : str
3119 Will be passed to the compiler as the filename of the cell. Typically
3119 Will be passed to the compiler as the filename of the cell. Typically
3120 the value returned by ip.compile.cache(cell).
3120 the value returned by ip.compile.cache(cell).
3121 interactivity : str
3121 interactivity : str
3122 'all', 'last', 'last_expr' , 'last_expr_or_assign' or 'none',
3122 'all', 'last', 'last_expr' , 'last_expr_or_assign' or 'none',
3123 specifying which nodes should be run interactively (displaying output
3123 specifying which nodes should be run interactively (displaying output
3124 from expressions). 'last_expr' will run the last node interactively
3124 from expressions). 'last_expr' will run the last node interactively
3125 only if it is an expression (i.e. expressions in loops or other blocks
3125 only if it is an expression (i.e. expressions in loops or other blocks
3126 are not displayed) 'last_expr_or_assign' will run the last expression
3126 are not displayed) 'last_expr_or_assign' will run the last expression
3127 or the last assignment. Other values for this parameter will raise a
3127 or the last assignment. Other values for this parameter will raise a
3128 ValueError.
3128 ValueError.
3129
3129
3130 compiler : callable
3130 compiler : callable
3131 A function with the same interface as the built-in compile(), to turn
3131 A function with the same interface as the built-in compile(), to turn
3132 the AST nodes into code objects. Default is the built-in compile().
3132 the AST nodes into code objects. Default is the built-in compile().
3133 result : ExecutionResult, optional
3133 result : ExecutionResult, optional
3134 An object to store exceptions that occur during execution.
3134 An object to store exceptions that occur during execution.
3135
3135
3136 Returns
3136 Returns
3137 -------
3137 -------
3138 True if an exception occurred while running code, False if it finished
3138 True if an exception occurred while running code, False if it finished
3139 running.
3139 running.
3140 """
3140 """
3141 if not nodelist:
3141 if not nodelist:
3142 return
3142 return
3143
3143
3144
3144
3145 if interactivity == 'last_expr_or_assign':
3145 if interactivity == 'last_expr_or_assign':
3146 if isinstance(nodelist[-1], _assign_nodes):
3146 if isinstance(nodelist[-1], _assign_nodes):
3147 asg = nodelist[-1]
3147 asg = nodelist[-1]
3148 if isinstance(asg, ast.Assign) and len(asg.targets) == 1:
3148 if isinstance(asg, ast.Assign) and len(asg.targets) == 1:
3149 target = asg.targets[0]
3149 target = asg.targets[0]
3150 elif isinstance(asg, _single_targets_nodes):
3150 elif isinstance(asg, _single_targets_nodes):
3151 target = asg.target
3151 target = asg.target
3152 else:
3152 else:
3153 target = None
3153 target = None
3154 if isinstance(target, ast.Name):
3154 if isinstance(target, ast.Name):
3155 nnode = ast.Expr(ast.Name(target.id, ast.Load()))
3155 nnode = ast.Expr(ast.Name(target.id, ast.Load()))
3156 ast.fix_missing_locations(nnode)
3156 ast.fix_missing_locations(nnode)
3157 nodelist.append(nnode)
3157 nodelist.append(nnode)
3158 interactivity = 'last_expr'
3158 interactivity = 'last_expr'
3159
3159
3160 _async = False
3160 _async = False
3161 if interactivity == 'last_expr':
3161 if interactivity == 'last_expr':
3162 if isinstance(nodelist[-1], ast.Expr):
3162 if isinstance(nodelist[-1], ast.Expr):
3163 interactivity = "last"
3163 interactivity = "last"
3164 else:
3164 else:
3165 interactivity = "none"
3165 interactivity = "none"
3166
3166
3167 if interactivity == 'none':
3167 if interactivity == 'none':
3168 to_run_exec, to_run_interactive = nodelist, []
3168 to_run_exec, to_run_interactive = nodelist, []
3169 elif interactivity == 'last':
3169 elif interactivity == 'last':
3170 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
3170 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
3171 elif interactivity == 'all':
3171 elif interactivity == 'all':
3172 to_run_exec, to_run_interactive = [], nodelist
3172 to_run_exec, to_run_interactive = [], nodelist
3173 else:
3173 else:
3174 raise ValueError("Interactivity was %r" % interactivity)
3174 raise ValueError("Interactivity was %r" % interactivity)
3175
3175
3176 try:
3176 try:
3177
3177
3178 def compare(code):
3178 def compare(code):
3179 is_async = inspect.CO_COROUTINE & code.co_flags == inspect.CO_COROUTINE
3179 is_async = inspect.CO_COROUTINE & code.co_flags == inspect.CO_COROUTINE
3180 return is_async
3180 return is_async
3181
3181
3182 # refactor that to just change the mod constructor.
3182 # refactor that to just change the mod constructor.
3183 to_run = []
3183 to_run = []
3184 for node in to_run_exec:
3184 for node in to_run_exec:
3185 to_run.append((node, "exec"))
3185 to_run.append((node, "exec"))
3186
3186
3187 for node in to_run_interactive:
3187 for node in to_run_interactive:
3188 to_run.append((node, "single"))
3188 to_run.append((node, "single"))
3189
3189
3190 for node, mode in to_run:
3190 for node, mode in to_run:
3191 if mode == "exec":
3191 if mode == "exec":
3192 mod = Module([node], [])
3192 mod = Module([node], [])
3193 elif mode == "single":
3193 elif mode == "single":
3194 mod = ast.Interactive([node])
3194 mod = ast.Interactive([node])
3195 with compiler.extra_flags(
3195 with compiler.extra_flags(
3196 getattr(ast, "PyCF_ALLOW_TOP_LEVEL_AWAIT", 0x0)
3196 getattr(ast, "PyCF_ALLOW_TOP_LEVEL_AWAIT", 0x0)
3197 if self.autoawait
3197 if self.autoawait
3198 else 0x0
3198 else 0x0
3199 ):
3199 ):
3200 code = compiler(mod, cell_name, mode)
3200 code = compiler(mod, cell_name, mode)
3201 asy = compare(code)
3201 asy = compare(code)
3202 if await self.run_code(code, result, async_=asy):
3202 if await self.run_code(code, result, async_=asy):
3203 return True
3203 return True
3204
3204
3205 # Flush softspace
3205 # Flush softspace
3206 if softspace(sys.stdout, 0):
3206 if softspace(sys.stdout, 0):
3207 print()
3207 print()
3208
3208
3209 except:
3209 except:
3210 # It's possible to have exceptions raised here, typically by
3210 # It's possible to have exceptions raised here, typically by
3211 # compilation of odd code (such as a naked 'return' outside a
3211 # compilation of odd code (such as a naked 'return' outside a
3212 # function) that did parse but isn't valid. Typically the exception
3212 # function) that did parse but isn't valid. Typically the exception
3213 # is a SyntaxError, but it's safest just to catch anything and show
3213 # is a SyntaxError, but it's safest just to catch anything and show
3214 # the user a traceback.
3214 # the user a traceback.
3215
3215
3216 # We do only one try/except outside the loop to minimize the impact
3216 # We do only one try/except outside the loop to minimize the impact
3217 # on runtime, and also because if any node in the node list is
3217 # on runtime, and also because if any node in the node list is
3218 # broken, we should stop execution completely.
3218 # broken, we should stop execution completely.
3219 if result:
3219 if result:
3220 result.error_before_exec = sys.exc_info()[1]
3220 result.error_before_exec = sys.exc_info()[1]
3221 self.showtraceback()
3221 self.showtraceback()
3222 return True
3222 return True
3223
3223
3224 return False
3224 return False
3225
3225
3226 async def run_code(self, code_obj, result=None, *, async_=False):
3226 async def run_code(self, code_obj, result=None, *, async_=False):
3227 """Execute a code object.
3227 """Execute a code object.
3228
3228
3229 When an exception occurs, self.showtraceback() is called to display a
3229 When an exception occurs, self.showtraceback() is called to display a
3230 traceback.
3230 traceback.
3231
3231
3232 Parameters
3232 Parameters
3233 ----------
3233 ----------
3234 code_obj : code object
3234 code_obj : code object
3235 A compiled code object, to be executed
3235 A compiled code object, to be executed
3236 result : ExecutionResult, optional
3236 result : ExecutionResult, optional
3237 An object to store exceptions that occur during execution.
3237 An object to store exceptions that occur during execution.
3238 async_ : Bool (Experimental)
3238 async_ : Bool (Experimental)
3239 Attempt to run top-level asynchronous code in a default loop.
3239 Attempt to run top-level asynchronous code in a default loop.
3240
3240
3241 Returns
3241 Returns
3242 -------
3242 -------
3243 False : successful execution.
3243 False : successful execution.
3244 True : an error occurred.
3244 True : an error occurred.
3245 """
3245 """
3246 # special value to say that anything above is IPython and should be
3246 # special value to say that anything above is IPython and should be
3247 # hidden.
3247 # hidden.
3248 __tracebackhide__ = "__ipython_bottom__"
3248 __tracebackhide__ = "__ipython_bottom__"
3249 # Set our own excepthook in case the user code tries to call it
3249 # Set our own excepthook in case the user code tries to call it
3250 # directly, so that the IPython crash handler doesn't get triggered
3250 # directly, so that the IPython crash handler doesn't get triggered
3251 old_excepthook, sys.excepthook = sys.excepthook, self.excepthook
3251 old_excepthook, sys.excepthook = sys.excepthook, self.excepthook
3252
3252
3253 # we save the original sys.excepthook in the instance, in case config
3253 # we save the original sys.excepthook in the instance, in case config
3254 # code (such as magics) needs access to it.
3254 # code (such as magics) needs access to it.
3255 self.sys_excepthook = old_excepthook
3255 self.sys_excepthook = old_excepthook
3256 outflag = True # happens in more places, so it's easier as default
3256 outflag = True # happens in more places, so it's easier as default
3257 try:
3257 try:
3258 try:
3258 try:
3259 if async_:
3259 if async_:
3260 await eval(code_obj, self.user_global_ns, self.user_ns)
3260 await eval(code_obj, self.user_global_ns, self.user_ns)
3261 else:
3261 else:
3262 exec(code_obj, self.user_global_ns, self.user_ns)
3262 exec(code_obj, self.user_global_ns, self.user_ns)
3263 finally:
3263 finally:
3264 # Reset our crash handler in place
3264 # Reset our crash handler in place
3265 sys.excepthook = old_excepthook
3265 sys.excepthook = old_excepthook
3266 except SystemExit as e:
3266 except SystemExit as e:
3267 if result is not None:
3267 if result is not None:
3268 result.error_in_exec = e
3268 result.error_in_exec = e
3269 self.showtraceback(exception_only=True)
3269 self.showtraceback(exception_only=True)
3270 warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
3270 warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
3271 except self.custom_exceptions:
3271 except self.custom_exceptions:
3272 etype, value, tb = sys.exc_info()
3272 etype, value, tb = sys.exc_info()
3273 if result is not None:
3273 if result is not None:
3274 result.error_in_exec = value
3274 result.error_in_exec = value
3275 self.CustomTB(etype, value, tb)
3275 self.CustomTB(etype, value, tb)
3276 except:
3276 except:
3277 if result is not None:
3277 if result is not None:
3278 result.error_in_exec = sys.exc_info()[1]
3278 result.error_in_exec = sys.exc_info()[1]
3279 self.showtraceback(running_compiled_code=True)
3279 self.showtraceback(running_compiled_code=True)
3280 else:
3280 else:
3281 outflag = False
3281 outflag = False
3282 return outflag
3282 return outflag
3283
3283
3284 # For backwards compatibility
3284 # For backwards compatibility
3285 runcode = run_code
3285 runcode = run_code
3286
3286
3287 def check_complete(self, code: str) -> Tuple[str, str]:
3287 def check_complete(self, code: str) -> Tuple[str, str]:
3288 """Return whether a block of code is ready to execute, or should be continued
3288 """Return whether a block of code is ready to execute, or should be continued
3289
3289
3290 Parameters
3290 Parameters
3291 ----------
3291 ----------
3292 code : string
3292 code : string
3293 Python input code, which can be multiline.
3293 Python input code, which can be multiline.
3294
3294
3295 Returns
3295 Returns
3296 -------
3296 -------
3297 status : str
3297 status : str
3298 One of 'complete', 'incomplete', or 'invalid' if source is not a
3298 One of 'complete', 'incomplete', or 'invalid' if source is not a
3299 prefix of valid code.
3299 prefix of valid code.
3300 indent : str
3300 indent : str
3301 When status is 'incomplete', this is some whitespace to insert on
3301 When status is 'incomplete', this is some whitespace to insert on
3302 the next line of the prompt.
3302 the next line of the prompt.
3303 """
3303 """
3304 status, nspaces = self.input_transformer_manager.check_complete(code)
3304 status, nspaces = self.input_transformer_manager.check_complete(code)
3305 return status, ' ' * (nspaces or 0)
3305 return status, ' ' * (nspaces or 0)
3306
3306
3307 #-------------------------------------------------------------------------
3307 #-------------------------------------------------------------------------
3308 # Things related to GUI support and pylab
3308 # Things related to GUI support and pylab
3309 #-------------------------------------------------------------------------
3309 #-------------------------------------------------------------------------
3310
3310
3311 active_eventloop = None
3311 active_eventloop = None
3312
3312
3313 def enable_gui(self, gui=None):
3313 def enable_gui(self, gui=None):
3314 raise NotImplementedError('Implement enable_gui in a subclass')
3314 raise NotImplementedError('Implement enable_gui in a subclass')
3315
3315
3316 def enable_matplotlib(self, gui=None):
3316 def enable_matplotlib(self, gui=None):
3317 """Enable interactive matplotlib and inline figure support.
3317 """Enable interactive matplotlib and inline figure support.
3318
3318
3319 This takes the following steps:
3319 This takes the following steps:
3320
3320
3321 1. select the appropriate eventloop and matplotlib backend
3321 1. select the appropriate eventloop and matplotlib backend
3322 2. set up matplotlib for interactive use with that backend
3322 2. set up matplotlib for interactive use with that backend
3323 3. configure formatters for inline figure display
3323 3. configure formatters for inline figure display
3324 4. enable the selected gui eventloop
3324 4. enable the selected gui eventloop
3325
3325
3326 Parameters
3326 Parameters
3327 ----------
3327 ----------
3328 gui : optional, string
3328 gui : optional, string
3329 If given, dictates the choice of matplotlib GUI backend to use
3329 If given, dictates the choice of matplotlib GUI backend to use
3330 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3330 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3331 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3331 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3332 matplotlib (as dictated by the matplotlib build-time options plus the
3332 matplotlib (as dictated by the matplotlib build-time options plus the
3333 user's matplotlibrc configuration file). Note that not all backends
3333 user's matplotlibrc configuration file). Note that not all backends
3334 make sense in all contexts, for example a terminal ipython can't
3334 make sense in all contexts, for example a terminal ipython can't
3335 display figures inline.
3335 display figures inline.
3336 """
3336 """
3337 from IPython.core import pylabtools as pt
3337 from IPython.core import pylabtools as pt
3338 from matplotlib_inline.backend_inline import configure_inline_support
3338 from matplotlib_inline.backend_inline import configure_inline_support
3339 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
3339 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
3340
3340
3341 if gui != 'inline':
3341 if gui != 'inline':
3342 # If we have our first gui selection, store it
3342 # If we have our first gui selection, store it
3343 if self.pylab_gui_select is None:
3343 if self.pylab_gui_select is None:
3344 self.pylab_gui_select = gui
3344 self.pylab_gui_select = gui
3345 # Otherwise if they are different
3345 # Otherwise if they are different
3346 elif gui != self.pylab_gui_select:
3346 elif gui != self.pylab_gui_select:
3347 print('Warning: Cannot change to a different GUI toolkit: %s.'
3347 print('Warning: Cannot change to a different GUI toolkit: %s.'
3348 ' Using %s instead.' % (gui, self.pylab_gui_select))
3348 ' Using %s instead.' % (gui, self.pylab_gui_select))
3349 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
3349 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
3350
3350
3351 pt.activate_matplotlib(backend)
3351 pt.activate_matplotlib(backend)
3352 configure_inline_support(self, backend)
3352 configure_inline_support(self, backend)
3353
3353
3354 # Now we must activate the gui pylab wants to use, and fix %run to take
3354 # Now we must activate the gui pylab wants to use, and fix %run to take
3355 # plot updates into account
3355 # plot updates into account
3356 self.enable_gui(gui)
3356 self.enable_gui(gui)
3357 self.magics_manager.registry['ExecutionMagics'].default_runner = \
3357 self.magics_manager.registry['ExecutionMagics'].default_runner = \
3358 pt.mpl_runner(self.safe_execfile)
3358 pt.mpl_runner(self.safe_execfile)
3359
3359
3360 return gui, backend
3360 return gui, backend
3361
3361
3362 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
3362 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
3363 """Activate pylab support at runtime.
3363 """Activate pylab support at runtime.
3364
3364
3365 This turns on support for matplotlib, preloads into the interactive
3365 This turns on support for matplotlib, preloads into the interactive
3366 namespace all of numpy and pylab, and configures IPython to correctly
3366 namespace all of numpy and pylab, and configures IPython to correctly
3367 interact with the GUI event loop. The GUI backend to be used can be
3367 interact with the GUI event loop. The GUI backend to be used can be
3368 optionally selected with the optional ``gui`` argument.
3368 optionally selected with the optional ``gui`` argument.
3369
3369
3370 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
3370 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
3371
3371
3372 Parameters
3372 Parameters
3373 ----------
3373 ----------
3374 gui : optional, string
3374 gui : optional, string
3375 If given, dictates the choice of matplotlib GUI backend to use
3375 If given, dictates the choice of matplotlib GUI backend to use
3376 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3376 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3377 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3377 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3378 matplotlib (as dictated by the matplotlib build-time options plus the
3378 matplotlib (as dictated by the matplotlib build-time options plus the
3379 user's matplotlibrc configuration file). Note that not all backends
3379 user's matplotlibrc configuration file). Note that not all backends
3380 make sense in all contexts, for example a terminal ipython can't
3380 make sense in all contexts, for example a terminal ipython can't
3381 display figures inline.
3381 display figures inline.
3382 import_all : optional, bool, default: True
3382 import_all : optional, bool, default: True
3383 Whether to do `from numpy import *` and `from pylab import *`
3383 Whether to do `from numpy import *` and `from pylab import *`
3384 in addition to module imports.
3384 in addition to module imports.
3385 welcome_message : deprecated
3385 welcome_message : deprecated
3386 This argument is ignored, no welcome message will be displayed.
3386 This argument is ignored, no welcome message will be displayed.
3387 """
3387 """
3388 from IPython.core.pylabtools import import_pylab
3388 from IPython.core.pylabtools import import_pylab
3389
3389
3390 gui, backend = self.enable_matplotlib(gui)
3390 gui, backend = self.enable_matplotlib(gui)
3391
3391
3392 # We want to prevent the loading of pylab to pollute the user's
3392 # We want to prevent the loading of pylab to pollute the user's
3393 # namespace as shown by the %who* magics, so we execute the activation
3393 # namespace as shown by the %who* magics, so we execute the activation
3394 # code in an empty namespace, and we update *both* user_ns and
3394 # code in an empty namespace, and we update *both* user_ns and
3395 # user_ns_hidden with this information.
3395 # user_ns_hidden with this information.
3396 ns = {}
3396 ns = {}
3397 import_pylab(ns, import_all)
3397 import_pylab(ns, import_all)
3398 # warn about clobbered names
3398 # warn about clobbered names
3399 ignored = {"__builtins__"}
3399 ignored = {"__builtins__"}
3400 both = set(ns).intersection(self.user_ns).difference(ignored)
3400 both = set(ns).intersection(self.user_ns).difference(ignored)
3401 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
3401 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
3402 self.user_ns.update(ns)
3402 self.user_ns.update(ns)
3403 self.user_ns_hidden.update(ns)
3403 self.user_ns_hidden.update(ns)
3404 return gui, backend, clobbered
3404 return gui, backend, clobbered
3405
3405
3406 #-------------------------------------------------------------------------
3406 #-------------------------------------------------------------------------
3407 # Utilities
3407 # Utilities
3408 #-------------------------------------------------------------------------
3408 #-------------------------------------------------------------------------
3409
3409
3410 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
3410 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
3411 """Expand python variables in a string.
3411 """Expand python variables in a string.
3412
3412
3413 The depth argument indicates how many frames above the caller should
3413 The depth argument indicates how many frames above the caller should
3414 be walked to look for the local namespace where to expand variables.
3414 be walked to look for the local namespace where to expand variables.
3415
3415
3416 The global namespace for expansion is always the user's interactive
3416 The global namespace for expansion is always the user's interactive
3417 namespace.
3417 namespace.
3418 """
3418 """
3419 ns = self.user_ns.copy()
3419 ns = self.user_ns.copy()
3420 try:
3420 try:
3421 frame = sys._getframe(depth+1)
3421 frame = sys._getframe(depth+1)
3422 except ValueError:
3422 except ValueError:
3423 # This is thrown if there aren't that many frames on the stack,
3423 # This is thrown if there aren't that many frames on the stack,
3424 # e.g. if a script called run_line_magic() directly.
3424 # e.g. if a script called run_line_magic() directly.
3425 pass
3425 pass
3426 else:
3426 else:
3427 ns.update(frame.f_locals)
3427 ns.update(frame.f_locals)
3428
3428
3429 try:
3429 try:
3430 # We have to use .vformat() here, because 'self' is a valid and common
3430 # We have to use .vformat() here, because 'self' is a valid and common
3431 # name, and expanding **ns for .format() would make it collide with
3431 # name, and expanding **ns for .format() would make it collide with
3432 # the 'self' argument of the method.
3432 # the 'self' argument of the method.
3433 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
3433 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
3434 except Exception:
3434 except Exception:
3435 # if formatter couldn't format, just let it go untransformed
3435 # if formatter couldn't format, just let it go untransformed
3436 pass
3436 pass
3437 return cmd
3437 return cmd
3438
3438
3439 def mktempfile(self, data=None, prefix='ipython_edit_'):
3439 def mktempfile(self, data=None, prefix='ipython_edit_'):
3440 """Make a new tempfile and return its filename.
3440 """Make a new tempfile and return its filename.
3441
3441
3442 This makes a call to tempfile.mkstemp (created in a tempfile.mkdtemp),
3442 This makes a call to tempfile.mkstemp (created in a tempfile.mkdtemp),
3443 but it registers the created filename internally so ipython cleans it up
3443 but it registers the created filename internally so ipython cleans it up
3444 at exit time.
3444 at exit time.
3445
3445
3446 Optional inputs:
3446 Optional inputs:
3447
3447
3448 - data(None): if data is given, it gets written out to the temp file
3448 - data(None): if data is given, it gets written out to the temp file
3449 immediately, and the file is closed again."""
3449 immediately, and the file is closed again."""
3450
3450
3451 dir_path = Path(tempfile.mkdtemp(prefix=prefix))
3451 dir_path = Path(tempfile.mkdtemp(prefix=prefix))
3452 self.tempdirs.append(dir_path)
3452 self.tempdirs.append(dir_path)
3453
3453
3454 handle, filename = tempfile.mkstemp(".py", prefix, dir=str(dir_path))
3454 handle, filename = tempfile.mkstemp(".py", prefix, dir=str(dir_path))
3455 os.close(handle) # On Windows, there can only be one open handle on a file
3455 os.close(handle) # On Windows, there can only be one open handle on a file
3456
3456
3457 file_path = Path(filename)
3457 file_path = Path(filename)
3458 self.tempfiles.append(file_path)
3458 self.tempfiles.append(file_path)
3459
3459
3460 if data:
3460 if data:
3461 file_path.write_text(data, encoding='utf-8')
3461 file_path.write_text(data, encoding="utf-8")
3462 return filename
3462 return filename
3463
3463
3464 def ask_yes_no(self, prompt, default=None, interrupt=None):
3464 def ask_yes_no(self, prompt, default=None, interrupt=None):
3465 if self.quiet:
3465 if self.quiet:
3466 return True
3466 return True
3467 return ask_yes_no(prompt,default,interrupt)
3467 return ask_yes_no(prompt,default,interrupt)
3468
3468
3469 def show_usage(self):
3469 def show_usage(self):
3470 """Show a usage message"""
3470 """Show a usage message"""
3471 page.page(IPython.core.usage.interactive_usage)
3471 page.page(IPython.core.usage.interactive_usage)
3472
3472
3473 def extract_input_lines(self, range_str, raw=False):
3473 def extract_input_lines(self, range_str, raw=False):
3474 """Return as a string a set of input history slices.
3474 """Return as a string a set of input history slices.
3475
3475
3476 Parameters
3476 Parameters
3477 ----------
3477 ----------
3478 range_str : str
3478 range_str : str
3479 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3479 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3480 since this function is for use by magic functions which get their
3480 since this function is for use by magic functions which get their
3481 arguments as strings. The number before the / is the session
3481 arguments as strings. The number before the / is the session
3482 number: ~n goes n back from the current session.
3482 number: ~n goes n back from the current session.
3483
3483
3484 If empty string is given, returns history of current session
3484 If empty string is given, returns history of current session
3485 without the last input.
3485 without the last input.
3486
3486
3487 raw : bool, optional
3487 raw : bool, optional
3488 By default, the processed input is used. If this is true, the raw
3488 By default, the processed input is used. If this is true, the raw
3489 input history is used instead.
3489 input history is used instead.
3490
3490
3491 Notes
3491 Notes
3492 -----
3492 -----
3493 Slices can be described with two notations:
3493 Slices can be described with two notations:
3494
3494
3495 * ``N:M`` -> standard python form, means including items N...(M-1).
3495 * ``N:M`` -> standard python form, means including items N...(M-1).
3496 * ``N-M`` -> include items N..M (closed endpoint).
3496 * ``N-M`` -> include items N..M (closed endpoint).
3497 """
3497 """
3498 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3498 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3499 text = "\n".join(x for _, _, x in lines)
3499 text = "\n".join(x for _, _, x in lines)
3500
3500
3501 # Skip the last line, as it's probably the magic that called this
3501 # Skip the last line, as it's probably the magic that called this
3502 if not range_str:
3502 if not range_str:
3503 if "\n" not in text:
3503 if "\n" not in text:
3504 text = ""
3504 text = ""
3505 else:
3505 else:
3506 text = text[: text.rfind("\n")]
3506 text = text[: text.rfind("\n")]
3507
3507
3508 return text
3508 return text
3509
3509
3510 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True, search_ns=False):
3510 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True, search_ns=False):
3511 """Get a code string from history, file, url, or a string or macro.
3511 """Get a code string from history, file, url, or a string or macro.
3512
3512
3513 This is mainly used by magic functions.
3513 This is mainly used by magic functions.
3514
3514
3515 Parameters
3515 Parameters
3516 ----------
3516 ----------
3517 target : str
3517 target : str
3518 A string specifying code to retrieve. This will be tried respectively
3518 A string specifying code to retrieve. This will be tried respectively
3519 as: ranges of input history (see %history for syntax), url,
3519 as: ranges of input history (see %history for syntax), url,
3520 corresponding .py file, filename, or an expression evaluating to a
3520 corresponding .py file, filename, or an expression evaluating to a
3521 string or Macro in the user namespace.
3521 string or Macro in the user namespace.
3522
3522
3523 If empty string is given, returns complete history of current
3523 If empty string is given, returns complete history of current
3524 session, without the last line.
3524 session, without the last line.
3525
3525
3526 raw : bool
3526 raw : bool
3527 If true (default), retrieve raw history. Has no effect on the other
3527 If true (default), retrieve raw history. Has no effect on the other
3528 retrieval mechanisms.
3528 retrieval mechanisms.
3529
3529
3530 py_only : bool (default False)
3530 py_only : bool (default False)
3531 Only try to fetch python code, do not try alternative methods to decode file
3531 Only try to fetch python code, do not try alternative methods to decode file
3532 if unicode fails.
3532 if unicode fails.
3533
3533
3534 Returns
3534 Returns
3535 -------
3535 -------
3536 A string of code.
3536 A string of code.
3537 ValueError is raised if nothing is found, and TypeError if it evaluates
3537 ValueError is raised if nothing is found, and TypeError if it evaluates
3538 to an object of another type. In each case, .args[0] is a printable
3538 to an object of another type. In each case, .args[0] is a printable
3539 message.
3539 message.
3540 """
3540 """
3541 code = self.extract_input_lines(target, raw=raw) # Grab history
3541 code = self.extract_input_lines(target, raw=raw) # Grab history
3542 if code:
3542 if code:
3543 return code
3543 return code
3544 try:
3544 try:
3545 if target.startswith(('http://', 'https://')):
3545 if target.startswith(('http://', 'https://')):
3546 return openpy.read_py_url(target, skip_encoding_cookie=skip_encoding_cookie)
3546 return openpy.read_py_url(target, skip_encoding_cookie=skip_encoding_cookie)
3547 except UnicodeDecodeError as e:
3547 except UnicodeDecodeError as e:
3548 if not py_only :
3548 if not py_only :
3549 # Deferred import
3549 # Deferred import
3550 from urllib.request import urlopen
3550 from urllib.request import urlopen
3551 response = urlopen(target)
3551 response = urlopen(target)
3552 return response.read().decode('latin1')
3552 return response.read().decode('latin1')
3553 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3553 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3554
3554
3555 potential_target = [target]
3555 potential_target = [target]
3556 try :
3556 try :
3557 potential_target.insert(0,get_py_filename(target))
3557 potential_target.insert(0,get_py_filename(target))
3558 except IOError:
3558 except IOError:
3559 pass
3559 pass
3560
3560
3561 for tgt in potential_target :
3561 for tgt in potential_target :
3562 if os.path.isfile(tgt): # Read file
3562 if os.path.isfile(tgt): # Read file
3563 try :
3563 try :
3564 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3564 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3565 except UnicodeDecodeError as e:
3565 except UnicodeDecodeError as e:
3566 if not py_only :
3566 if not py_only :
3567 with io_open(tgt,'r', encoding='latin1') as f :
3567 with io_open(tgt,'r', encoding='latin1') as f :
3568 return f.read()
3568 return f.read()
3569 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3569 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3570 elif os.path.isdir(os.path.expanduser(tgt)):
3570 elif os.path.isdir(os.path.expanduser(tgt)):
3571 raise ValueError("'%s' is a directory, not a regular file." % target)
3571 raise ValueError("'%s' is a directory, not a regular file." % target)
3572
3572
3573 if search_ns:
3573 if search_ns:
3574 # Inspect namespace to load object source
3574 # Inspect namespace to load object source
3575 object_info = self.object_inspect(target, detail_level=1)
3575 object_info = self.object_inspect(target, detail_level=1)
3576 if object_info['found'] and object_info['source']:
3576 if object_info['found'] and object_info['source']:
3577 return object_info['source']
3577 return object_info['source']
3578
3578
3579 try: # User namespace
3579 try: # User namespace
3580 codeobj = eval(target, self.user_ns)
3580 codeobj = eval(target, self.user_ns)
3581 except Exception as e:
3581 except Exception as e:
3582 raise ValueError(("'%s' was not found in history, as a file, url, "
3582 raise ValueError(("'%s' was not found in history, as a file, url, "
3583 "nor in the user namespace.") % target) from e
3583 "nor in the user namespace.") % target) from e
3584
3584
3585 if isinstance(codeobj, str):
3585 if isinstance(codeobj, str):
3586 return codeobj
3586 return codeobj
3587 elif isinstance(codeobj, Macro):
3587 elif isinstance(codeobj, Macro):
3588 return codeobj.value
3588 return codeobj.value
3589
3589
3590 raise TypeError("%s is neither a string nor a macro." % target,
3590 raise TypeError("%s is neither a string nor a macro." % target,
3591 codeobj)
3591 codeobj)
3592
3592
3593 def _atexit_once(self):
3593 def _atexit_once(self):
3594 """
3594 """
3595 At exist operation that need to be called at most once.
3595 At exist operation that need to be called at most once.
3596 Second call to this function per instance will do nothing.
3596 Second call to this function per instance will do nothing.
3597 """
3597 """
3598
3598
3599 if not getattr(self, "_atexit_once_called", False):
3599 if not getattr(self, "_atexit_once_called", False):
3600 self._atexit_once_called = True
3600 self._atexit_once_called = True
3601 # Clear all user namespaces to release all references cleanly.
3601 # Clear all user namespaces to release all references cleanly.
3602 self.reset(new_session=False)
3602 self.reset(new_session=False)
3603 # Close the history session (this stores the end time and line count)
3603 # Close the history session (this stores the end time and line count)
3604 # this must be *before* the tempfile cleanup, in case of temporary
3604 # this must be *before* the tempfile cleanup, in case of temporary
3605 # history db
3605 # history db
3606 self.history_manager.end_session()
3606 self.history_manager.end_session()
3607 self.history_manager = None
3607 self.history_manager = None
3608
3608
3609 #-------------------------------------------------------------------------
3609 #-------------------------------------------------------------------------
3610 # Things related to IPython exiting
3610 # Things related to IPython exiting
3611 #-------------------------------------------------------------------------
3611 #-------------------------------------------------------------------------
3612 def atexit_operations(self):
3612 def atexit_operations(self):
3613 """This will be executed at the time of exit.
3613 """This will be executed at the time of exit.
3614
3614
3615 Cleanup operations and saving of persistent data that is done
3615 Cleanup operations and saving of persistent data that is done
3616 unconditionally by IPython should be performed here.
3616 unconditionally by IPython should be performed here.
3617
3617
3618 For things that may depend on startup flags or platform specifics (such
3618 For things that may depend on startup flags or platform specifics (such
3619 as having readline or not), register a separate atexit function in the
3619 as having readline or not), register a separate atexit function in the
3620 code that has the appropriate information, rather than trying to
3620 code that has the appropriate information, rather than trying to
3621 clutter
3621 clutter
3622 """
3622 """
3623 self._atexit_once()
3623 self._atexit_once()
3624
3624
3625 # Cleanup all tempfiles and folders left around
3625 # Cleanup all tempfiles and folders left around
3626 for tfile in self.tempfiles:
3626 for tfile in self.tempfiles:
3627 try:
3627 try:
3628 tfile.unlink()
3628 tfile.unlink()
3629 self.tempfiles.remove(tfile)
3629 self.tempfiles.remove(tfile)
3630 except FileNotFoundError:
3630 except FileNotFoundError:
3631 pass
3631 pass
3632 del self.tempfiles
3632 del self.tempfiles
3633 for tdir in self.tempdirs:
3633 for tdir in self.tempdirs:
3634 try:
3634 try:
3635 tdir.rmdir()
3635 tdir.rmdir()
3636 self.tempdirs.remove(tdir)
3636 self.tempdirs.remove(tdir)
3637 except FileNotFoundError:
3637 except FileNotFoundError:
3638 pass
3638 pass
3639 del self.tempdirs
3639 del self.tempdirs
3640
3640
3641
3641
3642 def cleanup(self):
3642 def cleanup(self):
3643 self.restore_sys_module_state()
3643 self.restore_sys_module_state()
3644
3644
3645
3645
3646 # Overridden in terminal subclass to change prompts
3646 # Overridden in terminal subclass to change prompts
3647 def switch_doctest_mode(self, mode):
3647 def switch_doctest_mode(self, mode):
3648 pass
3648 pass
3649
3649
3650
3650
3651 class InteractiveShellABC(metaclass=abc.ABCMeta):
3651 class InteractiveShellABC(metaclass=abc.ABCMeta):
3652 """An abstract base class for InteractiveShell."""
3652 """An abstract base class for InteractiveShell."""
3653
3653
3654 InteractiveShellABC.register(InteractiveShell)
3654 InteractiveShellABC.register(InteractiveShell)
@@ -1,755 +1,755 b''
1 """Implementation of code management magic functions.
1 """Implementation of code management magic functions.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
4 # Copyright (c) 2012 The IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 # Stdlib
15 # Stdlib
16 import inspect
16 import inspect
17 import io
17 import io
18 import os
18 import os
19 import re
19 import re
20 import sys
20 import sys
21 import ast
21 import ast
22 from itertools import chain
22 from itertools import chain
23 from urllib.request import Request, urlopen
23 from urllib.request import Request, urlopen
24 from urllib.parse import urlencode
24 from urllib.parse import urlencode
25 from pathlib import Path
25 from pathlib import Path
26
26
27 # Our own packages
27 # Our own packages
28 from IPython.core.error import TryNext, StdinNotImplementedError, UsageError
28 from IPython.core.error import TryNext, StdinNotImplementedError, UsageError
29 from IPython.core.macro import Macro
29 from IPython.core.macro import Macro
30 from IPython.core.magic import Magics, magics_class, line_magic
30 from IPython.core.magic import Magics, magics_class, line_magic
31 from IPython.core.oinspect import find_file, find_source_lines
31 from IPython.core.oinspect import find_file, find_source_lines
32 from IPython.core.release import version
32 from IPython.core.release import version
33 from IPython.testing.skipdoctest import skip_doctest
33 from IPython.testing.skipdoctest import skip_doctest
34 from IPython.utils.contexts import preserve_keys
34 from IPython.utils.contexts import preserve_keys
35 from IPython.utils.path import get_py_filename
35 from IPython.utils.path import get_py_filename
36 from warnings import warn
36 from warnings import warn
37 from logging import error
37 from logging import error
38 from IPython.utils.text import get_text_list
38 from IPython.utils.text import get_text_list
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Magic implementation classes
41 # Magic implementation classes
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44 # Used for exception handling in magic_edit
44 # Used for exception handling in magic_edit
45 class MacroToEdit(ValueError): pass
45 class MacroToEdit(ValueError): pass
46
46
47 ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
47 ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
48
48
49 # To match, e.g. 8-10 1:5 :10 3-
49 # To match, e.g. 8-10 1:5 :10 3-
50 range_re = re.compile(r"""
50 range_re = re.compile(r"""
51 (?P<start>\d+)?
51 (?P<start>\d+)?
52 ((?P<sep>[\-:])
52 ((?P<sep>[\-:])
53 (?P<end>\d+)?)?
53 (?P<end>\d+)?)?
54 $""", re.VERBOSE)
54 $""", re.VERBOSE)
55
55
56
56
57 def extract_code_ranges(ranges_str):
57 def extract_code_ranges(ranges_str):
58 """Turn a string of range for %%load into 2-tuples of (start, stop)
58 """Turn a string of range for %%load into 2-tuples of (start, stop)
59 ready to use as a slice of the content split by lines.
59 ready to use as a slice of the content split by lines.
60
60
61 Examples
61 Examples
62 --------
62 --------
63 list(extract_input_ranges("5-10 2"))
63 list(extract_input_ranges("5-10 2"))
64 [(4, 10), (1, 2)]
64 [(4, 10), (1, 2)]
65 """
65 """
66 for range_str in ranges_str.split():
66 for range_str in ranges_str.split():
67 rmatch = range_re.match(range_str)
67 rmatch = range_re.match(range_str)
68 if not rmatch:
68 if not rmatch:
69 continue
69 continue
70 sep = rmatch.group("sep")
70 sep = rmatch.group("sep")
71 start = rmatch.group("start")
71 start = rmatch.group("start")
72 end = rmatch.group("end")
72 end = rmatch.group("end")
73
73
74 if sep == '-':
74 if sep == '-':
75 start = int(start) - 1 if start else None
75 start = int(start) - 1 if start else None
76 end = int(end) if end else None
76 end = int(end) if end else None
77 elif sep == ':':
77 elif sep == ':':
78 start = int(start) - 1 if start else None
78 start = int(start) - 1 if start else None
79 end = int(end) - 1 if end else None
79 end = int(end) - 1 if end else None
80 else:
80 else:
81 end = int(start)
81 end = int(start)
82 start = int(start) - 1
82 start = int(start) - 1
83 yield (start, end)
83 yield (start, end)
84
84
85
85
86 def extract_symbols(code, symbols):
86 def extract_symbols(code, symbols):
87 """
87 """
88 Return a tuple (blocks, not_found)
88 Return a tuple (blocks, not_found)
89 where ``blocks`` is a list of code fragments
89 where ``blocks`` is a list of code fragments
90 for each symbol parsed from code, and ``not_found`` are
90 for each symbol parsed from code, and ``not_found`` are
91 symbols not found in the code.
91 symbols not found in the code.
92
92
93 For example::
93 For example::
94
94
95 In [1]: code = '''a = 10
95 In [1]: code = '''a = 10
96 ...: def b(): return 42
96 ...: def b(): return 42
97 ...: class A: pass'''
97 ...: class A: pass'''
98
98
99 In [2]: extract_symbols(code, 'A,b,z')
99 In [2]: extract_symbols(code, 'A,b,z')
100 Out[2]: (['class A: pass\\n', 'def b(): return 42\\n'], ['z'])
100 Out[2]: (['class A: pass\\n', 'def b(): return 42\\n'], ['z'])
101 """
101 """
102 symbols = symbols.split(',')
102 symbols = symbols.split(',')
103
103
104 # this will raise SyntaxError if code isn't valid Python
104 # this will raise SyntaxError if code isn't valid Python
105 py_code = ast.parse(code)
105 py_code = ast.parse(code)
106
106
107 marks = [(getattr(s, 'name', None), s.lineno) for s in py_code.body]
107 marks = [(getattr(s, 'name', None), s.lineno) for s in py_code.body]
108 code = code.split('\n')
108 code = code.split('\n')
109
109
110 symbols_lines = {}
110 symbols_lines = {}
111
111
112 # we already know the start_lineno of each symbol (marks).
112 # we already know the start_lineno of each symbol (marks).
113 # To find each end_lineno, we traverse in reverse order until each
113 # To find each end_lineno, we traverse in reverse order until each
114 # non-blank line
114 # non-blank line
115 end = len(code)
115 end = len(code)
116 for name, start in reversed(marks):
116 for name, start in reversed(marks):
117 while not code[end - 1].strip():
117 while not code[end - 1].strip():
118 end -= 1
118 end -= 1
119 if name:
119 if name:
120 symbols_lines[name] = (start - 1, end)
120 symbols_lines[name] = (start - 1, end)
121 end = start - 1
121 end = start - 1
122
122
123 # Now symbols_lines is a map
123 # Now symbols_lines is a map
124 # {'symbol_name': (start_lineno, end_lineno), ...}
124 # {'symbol_name': (start_lineno, end_lineno), ...}
125
125
126 # fill a list with chunks of codes for each requested symbol
126 # fill a list with chunks of codes for each requested symbol
127 blocks = []
127 blocks = []
128 not_found = []
128 not_found = []
129 for symbol in symbols:
129 for symbol in symbols:
130 if symbol in symbols_lines:
130 if symbol in symbols_lines:
131 start, end = symbols_lines[symbol]
131 start, end = symbols_lines[symbol]
132 blocks.append('\n'.join(code[start:end]) + '\n')
132 blocks.append('\n'.join(code[start:end]) + '\n')
133 else:
133 else:
134 not_found.append(symbol)
134 not_found.append(symbol)
135
135
136 return blocks, not_found
136 return blocks, not_found
137
137
138 def strip_initial_indent(lines):
138 def strip_initial_indent(lines):
139 """For %load, strip indent from lines until finding an unindented line.
139 """For %load, strip indent from lines until finding an unindented line.
140
140
141 https://github.com/ipython/ipython/issues/9775
141 https://github.com/ipython/ipython/issues/9775
142 """
142 """
143 indent_re = re.compile(r'\s+')
143 indent_re = re.compile(r'\s+')
144
144
145 it = iter(lines)
145 it = iter(lines)
146 first_line = next(it)
146 first_line = next(it)
147 indent_match = indent_re.match(first_line)
147 indent_match = indent_re.match(first_line)
148
148
149 if indent_match:
149 if indent_match:
150 # First line was indented
150 # First line was indented
151 indent = indent_match.group()
151 indent = indent_match.group()
152 yield first_line[len(indent):]
152 yield first_line[len(indent):]
153
153
154 for line in it:
154 for line in it:
155 if line.startswith(indent):
155 if line.startswith(indent):
156 yield line[len(indent):]
156 yield line[len(indent):]
157 else:
157 else:
158 # Less indented than the first line - stop dedenting
158 # Less indented than the first line - stop dedenting
159 yield line
159 yield line
160 break
160 break
161 else:
161 else:
162 yield first_line
162 yield first_line
163
163
164 # Pass the remaining lines through without dedenting
164 # Pass the remaining lines through without dedenting
165 for line in it:
165 for line in it:
166 yield line
166 yield line
167
167
168
168
169 class InteractivelyDefined(Exception):
169 class InteractivelyDefined(Exception):
170 """Exception for interactively defined variable in magic_edit"""
170 """Exception for interactively defined variable in magic_edit"""
171 def __init__(self, index):
171 def __init__(self, index):
172 self.index = index
172 self.index = index
173
173
174
174
175 @magics_class
175 @magics_class
176 class CodeMagics(Magics):
176 class CodeMagics(Magics):
177 """Magics related to code management (loading, saving, editing, ...)."""
177 """Magics related to code management (loading, saving, editing, ...)."""
178
178
179 def __init__(self, *args, **kwargs):
179 def __init__(self, *args, **kwargs):
180 self._knowntemps = set()
180 self._knowntemps = set()
181 super(CodeMagics, self).__init__(*args, **kwargs)
181 super(CodeMagics, self).__init__(*args, **kwargs)
182
182
183 @line_magic
183 @line_magic
184 def save(self, parameter_s=''):
184 def save(self, parameter_s=''):
185 """Save a set of lines or a macro to a given filename.
185 """Save a set of lines or a macro to a given filename.
186
186
187 Usage:\\
187 Usage:\\
188 %save [options] filename [history]
188 %save [options] filename [history]
189
189
190 Options:
190 Options:
191
191
192 -r: use 'raw' input. By default, the 'processed' history is used,
192 -r: use 'raw' input. By default, the 'processed' history is used,
193 so that magics are loaded in their transformed version to valid
193 so that magics are loaded in their transformed version to valid
194 Python. If this option is given, the raw input as typed as the
194 Python. If this option is given, the raw input as typed as the
195 command line is used instead.
195 command line is used instead.
196
196
197 -f: force overwrite. If file exists, %save will prompt for overwrite
197 -f: force overwrite. If file exists, %save will prompt for overwrite
198 unless -f is given.
198 unless -f is given.
199
199
200 -a: append to the file instead of overwriting it.
200 -a: append to the file instead of overwriting it.
201
201
202 The history argument uses the same syntax as %history for input ranges,
202 The history argument uses the same syntax as %history for input ranges,
203 then saves the lines to the filename you specify.
203 then saves the lines to the filename you specify.
204
204
205 If no ranges are specified, saves history of the current session up to
205 If no ranges are specified, saves history of the current session up to
206 this point.
206 this point.
207
207
208 It adds a '.py' extension to the file if you don't do so yourself, and
208 It adds a '.py' extension to the file if you don't do so yourself, and
209 it asks for confirmation before overwriting existing files.
209 it asks for confirmation before overwriting existing files.
210
210
211 If `-r` option is used, the default extension is `.ipy`.
211 If `-r` option is used, the default extension is `.ipy`.
212 """
212 """
213
213
214 opts,args = self.parse_options(parameter_s,'fra',mode='list')
214 opts,args = self.parse_options(parameter_s,'fra',mode='list')
215 if not args:
215 if not args:
216 raise UsageError('Missing filename.')
216 raise UsageError('Missing filename.')
217 raw = 'r' in opts
217 raw = 'r' in opts
218 force = 'f' in opts
218 force = 'f' in opts
219 append = 'a' in opts
219 append = 'a' in opts
220 mode = 'a' if append else 'w'
220 mode = 'a' if append else 'w'
221 ext = '.ipy' if raw else '.py'
221 ext = '.ipy' if raw else '.py'
222 fname, codefrom = args[0], " ".join(args[1:])
222 fname, codefrom = args[0], " ".join(args[1:])
223 if not fname.endswith(('.py','.ipy')):
223 if not fname.endswith(('.py','.ipy')):
224 fname += ext
224 fname += ext
225 fname = os.path.expanduser(fname)
225 fname = os.path.expanduser(fname)
226 file_exists = os.path.isfile(fname)
226 file_exists = os.path.isfile(fname)
227 if file_exists and not force and not append:
227 if file_exists and not force and not append:
228 try:
228 try:
229 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
229 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
230 except StdinNotImplementedError:
230 except StdinNotImplementedError:
231 print("File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s))
231 print("File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s))
232 return
232 return
233 if not overwrite :
233 if not overwrite :
234 print('Operation cancelled.')
234 print('Operation cancelled.')
235 return
235 return
236 try:
236 try:
237 cmds = self.shell.find_user_code(codefrom,raw)
237 cmds = self.shell.find_user_code(codefrom,raw)
238 except (TypeError, ValueError) as e:
238 except (TypeError, ValueError) as e:
239 print(e.args[0])
239 print(e.args[0])
240 return
240 return
241 with io.open(fname, mode, encoding="utf-8") as f:
241 with io.open(fname, mode, encoding="utf-8") as f:
242 if not file_exists or not append:
242 if not file_exists or not append:
243 f.write("# coding: utf-8\n")
243 f.write("# coding: utf-8\n")
244 f.write(cmds)
244 f.write(cmds)
245 # make sure we end on a newline
245 # make sure we end on a newline
246 if not cmds.endswith('\n'):
246 if not cmds.endswith('\n'):
247 f.write('\n')
247 f.write('\n')
248 print('The following commands were written to file `%s`:' % fname)
248 print('The following commands were written to file `%s`:' % fname)
249 print(cmds)
249 print(cmds)
250
250
251 @line_magic
251 @line_magic
252 def pastebin(self, parameter_s=''):
252 def pastebin(self, parameter_s=''):
253 """Upload code to dpaste.com, returning the URL.
253 """Upload code to dpaste.com, returning the URL.
254
254
255 Usage:\\
255 Usage:\\
256 %pastebin [-d "Custom description"][-e 24] 1-7
256 %pastebin [-d "Custom description"][-e 24] 1-7
257
257
258 The argument can be an input history range, a filename, or the name of a
258 The argument can be an input history range, a filename, or the name of a
259 string or macro.
259 string or macro.
260
260
261 If no arguments are given, uploads the history of this session up to
261 If no arguments are given, uploads the history of this session up to
262 this point.
262 this point.
263
263
264 Options:
264 Options:
265
265
266 -d: Pass a custom description. The default will say
266 -d: Pass a custom description. The default will say
267 "Pasted from IPython".
267 "Pasted from IPython".
268 -e: Pass number of days for the link to be expired.
268 -e: Pass number of days for the link to be expired.
269 The default will be 7 days.
269 The default will be 7 days.
270 """
270 """
271 opts, args = self.parse_options(parameter_s, "d:e:")
271 opts, args = self.parse_options(parameter_s, "d:e:")
272
272
273 try:
273 try:
274 code = self.shell.find_user_code(args)
274 code = self.shell.find_user_code(args)
275 except (ValueError, TypeError) as e:
275 except (ValueError, TypeError) as e:
276 print(e.args[0])
276 print(e.args[0])
277 return
277 return
278
278
279 expiry_days = 7
279 expiry_days = 7
280 try:
280 try:
281 expiry_days = int(opts.get("e", 7))
281 expiry_days = int(opts.get("e", 7))
282 except ValueError as e:
282 except ValueError as e:
283 print(e.args[0].capitalize())
283 print(e.args[0].capitalize())
284 return
284 return
285 if expiry_days < 1 or expiry_days > 365:
285 if expiry_days < 1 or expiry_days > 365:
286 print("Expiry days should be in range of 1 to 365")
286 print("Expiry days should be in range of 1 to 365")
287 return
287 return
288
288
289 post_data = urlencode(
289 post_data = urlencode(
290 {
290 {
291 "title": opts.get("d", "Pasted from IPython"),
291 "title": opts.get("d", "Pasted from IPython"),
292 "syntax": "python",
292 "syntax": "python",
293 "content": code,
293 "content": code,
294 "expiry_days": expiry_days,
294 "expiry_days": expiry_days,
295 }
295 }
296 ).encode("utf-8")
296 ).encode("utf-8")
297
297
298 request = Request(
298 request = Request(
299 "https://dpaste.com/api/v2/",
299 "https://dpaste.com/api/v2/",
300 headers={"User-Agent": "IPython v{}".format(version)},
300 headers={"User-Agent": "IPython v{}".format(version)},
301 )
301 )
302 response = urlopen(request, post_data)
302 response = urlopen(request, post_data)
303 return response.headers.get('Location')
303 return response.headers.get('Location')
304
304
305 @line_magic
305 @line_magic
306 def loadpy(self, arg_s):
306 def loadpy(self, arg_s):
307 """Alias of `%load`
307 """Alias of `%load`
308
308
309 `%loadpy` has gained some flexibility and dropped the requirement of a `.py`
309 `%loadpy` has gained some flexibility and dropped the requirement of a `.py`
310 extension. So it has been renamed simply into %load. You can look at
310 extension. So it has been renamed simply into %load. You can look at
311 `%load`'s docstring for more info.
311 `%load`'s docstring for more info.
312 """
312 """
313 self.load(arg_s)
313 self.load(arg_s)
314
314
315 @line_magic
315 @line_magic
316 def load(self, arg_s):
316 def load(self, arg_s):
317 """Load code into the current frontend.
317 """Load code into the current frontend.
318
318
319 Usage:\\
319 Usage:\\
320 %load [options] source
320 %load [options] source
321
321
322 where source can be a filename, URL, input history range, macro, or
322 where source can be a filename, URL, input history range, macro, or
323 element in the user namespace
323 element in the user namespace
324
324
325 If no arguments are given, loads the history of this session up to this
325 If no arguments are given, loads the history of this session up to this
326 point.
326 point.
327
327
328 Options:
328 Options:
329
329
330 -r <lines>: Specify lines or ranges of lines to load from the source.
330 -r <lines>: Specify lines or ranges of lines to load from the source.
331 Ranges could be specified as x-y (x..y) or in python-style x:y
331 Ranges could be specified as x-y (x..y) or in python-style x:y
332 (x..(y-1)). Both limits x and y can be left blank (meaning the
332 (x..(y-1)). Both limits x and y can be left blank (meaning the
333 beginning and end of the file, respectively).
333 beginning and end of the file, respectively).
334
334
335 -s <symbols>: Specify function or classes to load from python source.
335 -s <symbols>: Specify function or classes to load from python source.
336
336
337 -y : Don't ask confirmation for loading source above 200 000 characters.
337 -y : Don't ask confirmation for loading source above 200 000 characters.
338
338
339 -n : Include the user's namespace when searching for source code.
339 -n : Include the user's namespace when searching for source code.
340
340
341 This magic command can either take a local filename, a URL, an history
341 This magic command can either take a local filename, a URL, an history
342 range (see %history) or a macro as argument, it will prompt for
342 range (see %history) or a macro as argument, it will prompt for
343 confirmation before loading source with more than 200 000 characters, unless
343 confirmation before loading source with more than 200 000 characters, unless
344 -y flag is passed or if the frontend does not support raw_input::
344 -y flag is passed or if the frontend does not support raw_input::
345
345
346 %load
346 %load
347 %load myscript.py
347 %load myscript.py
348 %load 7-27
348 %load 7-27
349 %load myMacro
349 %load myMacro
350 %load http://www.example.com/myscript.py
350 %load http://www.example.com/myscript.py
351 %load -r 5-10 myscript.py
351 %load -r 5-10 myscript.py
352 %load -r 10-20,30,40: foo.py
352 %load -r 10-20,30,40: foo.py
353 %load -s MyClass,wonder_function myscript.py
353 %load -s MyClass,wonder_function myscript.py
354 %load -n MyClass
354 %load -n MyClass
355 %load -n my_module.wonder_function
355 %load -n my_module.wonder_function
356 """
356 """
357 opts,args = self.parse_options(arg_s,'yns:r:')
357 opts,args = self.parse_options(arg_s,'yns:r:')
358 search_ns = 'n' in opts
358 search_ns = 'n' in opts
359 contents = self.shell.find_user_code(args, search_ns=search_ns)
359 contents = self.shell.find_user_code(args, search_ns=search_ns)
360
360
361 if 's' in opts:
361 if 's' in opts:
362 try:
362 try:
363 blocks, not_found = extract_symbols(contents, opts['s'])
363 blocks, not_found = extract_symbols(contents, opts['s'])
364 except SyntaxError:
364 except SyntaxError:
365 # non python code
365 # non python code
366 error("Unable to parse the input as valid Python code")
366 error("Unable to parse the input as valid Python code")
367 return
367 return
368
368
369 if len(not_found) == 1:
369 if len(not_found) == 1:
370 warn('The symbol `%s` was not found' % not_found[0])
370 warn('The symbol `%s` was not found' % not_found[0])
371 elif len(not_found) > 1:
371 elif len(not_found) > 1:
372 warn('The symbols %s were not found' % get_text_list(not_found,
372 warn('The symbols %s were not found' % get_text_list(not_found,
373 wrap_item_with='`')
373 wrap_item_with='`')
374 )
374 )
375
375
376 contents = '\n'.join(blocks)
376 contents = '\n'.join(blocks)
377
377
378 if 'r' in opts:
378 if 'r' in opts:
379 ranges = opts['r'].replace(',', ' ')
379 ranges = opts['r'].replace(',', ' ')
380 lines = contents.split('\n')
380 lines = contents.split('\n')
381 slices = extract_code_ranges(ranges)
381 slices = extract_code_ranges(ranges)
382 contents = [lines[slice(*slc)] for slc in slices]
382 contents = [lines[slice(*slc)] for slc in slices]
383 contents = '\n'.join(strip_initial_indent(chain.from_iterable(contents)))
383 contents = '\n'.join(strip_initial_indent(chain.from_iterable(contents)))
384
384
385 l = len(contents)
385 l = len(contents)
386
386
387 # 200 000 is ~ 2500 full 80 character lines
387 # 200 000 is ~ 2500 full 80 character lines
388 # so in average, more than 5000 lines
388 # so in average, more than 5000 lines
389 if l > 200000 and 'y' not in opts:
389 if l > 200000 and 'y' not in opts:
390 try:
390 try:
391 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
391 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
392 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
392 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
393 except StdinNotImplementedError:
393 except StdinNotImplementedError:
394 #assume yes if raw input not implemented
394 #assume yes if raw input not implemented
395 ans = True
395 ans = True
396
396
397 if ans is False :
397 if ans is False :
398 print('Operation cancelled.')
398 print('Operation cancelled.')
399 return
399 return
400
400
401 contents = "# %load {}\n".format(arg_s) + contents
401 contents = "# %load {}\n".format(arg_s) + contents
402
402
403 self.shell.set_next_input(contents, replace=True)
403 self.shell.set_next_input(contents, replace=True)
404
404
405 @staticmethod
405 @staticmethod
406 def _find_edit_target(shell, args, opts, last_call):
406 def _find_edit_target(shell, args, opts, last_call):
407 """Utility method used by magic_edit to find what to edit."""
407 """Utility method used by magic_edit to find what to edit."""
408
408
409 def make_filename(arg):
409 def make_filename(arg):
410 "Make a filename from the given args"
410 "Make a filename from the given args"
411 try:
411 try:
412 filename = get_py_filename(arg)
412 filename = get_py_filename(arg)
413 except IOError:
413 except IOError:
414 # If it ends with .py but doesn't already exist, assume we want
414 # If it ends with .py but doesn't already exist, assume we want
415 # a new file.
415 # a new file.
416 if arg.endswith('.py'):
416 if arg.endswith('.py'):
417 filename = arg
417 filename = arg
418 else:
418 else:
419 filename = None
419 filename = None
420 return filename
420 return filename
421
421
422 # Set a few locals from the options for convenience:
422 # Set a few locals from the options for convenience:
423 opts_prev = 'p' in opts
423 opts_prev = 'p' in opts
424 opts_raw = 'r' in opts
424 opts_raw = 'r' in opts
425
425
426 # custom exceptions
426 # custom exceptions
427 class DataIsObject(Exception): pass
427 class DataIsObject(Exception): pass
428
428
429 # Default line number value
429 # Default line number value
430 lineno = opts.get('n',None)
430 lineno = opts.get('n',None)
431
431
432 if opts_prev:
432 if opts_prev:
433 args = '_%s' % last_call[0]
433 args = '_%s' % last_call[0]
434 if args not in shell.user_ns:
434 if args not in shell.user_ns:
435 args = last_call[1]
435 args = last_call[1]
436
436
437 # by default this is done with temp files, except when the given
437 # by default this is done with temp files, except when the given
438 # arg is a filename
438 # arg is a filename
439 use_temp = True
439 use_temp = True
440
440
441 data = ''
441 data = ''
442
442
443 # First, see if the arguments should be a filename.
443 # First, see if the arguments should be a filename.
444 filename = make_filename(args)
444 filename = make_filename(args)
445 if filename:
445 if filename:
446 use_temp = False
446 use_temp = False
447 elif args:
447 elif args:
448 # Mode where user specifies ranges of lines, like in %macro.
448 # Mode where user specifies ranges of lines, like in %macro.
449 data = shell.extract_input_lines(args, opts_raw)
449 data = shell.extract_input_lines(args, opts_raw)
450 if not data:
450 if not data:
451 try:
451 try:
452 # Load the parameter given as a variable. If not a string,
452 # Load the parameter given as a variable. If not a string,
453 # process it as an object instead (below)
453 # process it as an object instead (below)
454
454
455 #print '*** args',args,'type',type(args) # dbg
455 #print '*** args',args,'type',type(args) # dbg
456 data = eval(args, shell.user_ns)
456 data = eval(args, shell.user_ns)
457 if not isinstance(data, str):
457 if not isinstance(data, str):
458 raise DataIsObject
458 raise DataIsObject
459
459
460 except (NameError,SyntaxError):
460 except (NameError,SyntaxError):
461 # given argument is not a variable, try as a filename
461 # given argument is not a variable, try as a filename
462 filename = make_filename(args)
462 filename = make_filename(args)
463 if filename is None:
463 if filename is None:
464 warn("Argument given (%s) can't be found as a variable "
464 warn("Argument given (%s) can't be found as a variable "
465 "or as a filename." % args)
465 "or as a filename." % args)
466 return (None, None, None)
466 return (None, None, None)
467 use_temp = False
467 use_temp = False
468
468
469 except DataIsObject as e:
469 except DataIsObject as e:
470 # macros have a special edit function
470 # macros have a special edit function
471 if isinstance(data, Macro):
471 if isinstance(data, Macro):
472 raise MacroToEdit(data) from e
472 raise MacroToEdit(data) from e
473
473
474 # For objects, try to edit the file where they are defined
474 # For objects, try to edit the file where they are defined
475 filename = find_file(data)
475 filename = find_file(data)
476 if filename:
476 if filename:
477 if 'fakemodule' in filename.lower() and \
477 if 'fakemodule' in filename.lower() and \
478 inspect.isclass(data):
478 inspect.isclass(data):
479 # class created by %edit? Try to find source
479 # class created by %edit? Try to find source
480 # by looking for method definitions instead, the
480 # by looking for method definitions instead, the
481 # __module__ in those classes is FakeModule.
481 # __module__ in those classes is FakeModule.
482 attrs = [getattr(data, aname) for aname in dir(data)]
482 attrs = [getattr(data, aname) for aname in dir(data)]
483 for attr in attrs:
483 for attr in attrs:
484 if not inspect.ismethod(attr):
484 if not inspect.ismethod(attr):
485 continue
485 continue
486 filename = find_file(attr)
486 filename = find_file(attr)
487 if filename and \
487 if filename and \
488 'fakemodule' not in filename.lower():
488 'fakemodule' not in filename.lower():
489 # change the attribute to be the edit
489 # change the attribute to be the edit
490 # target instead
490 # target instead
491 data = attr
491 data = attr
492 break
492 break
493
493
494 m = ipython_input_pat.match(os.path.basename(filename))
494 m = ipython_input_pat.match(os.path.basename(filename))
495 if m:
495 if m:
496 raise InteractivelyDefined(int(m.groups()[0])) from e
496 raise InteractivelyDefined(int(m.groups()[0])) from e
497
497
498 datafile = 1
498 datafile = 1
499 if filename is None:
499 if filename is None:
500 filename = make_filename(args)
500 filename = make_filename(args)
501 datafile = 1
501 datafile = 1
502 if filename is not None:
502 if filename is not None:
503 # only warn about this if we get a real name
503 # only warn about this if we get a real name
504 warn('Could not find file where `%s` is defined.\n'
504 warn('Could not find file where `%s` is defined.\n'
505 'Opening a file named `%s`' % (args, filename))
505 'Opening a file named `%s`' % (args, filename))
506 # Now, make sure we can actually read the source (if it was
506 # Now, make sure we can actually read the source (if it was
507 # in a temp file it's gone by now).
507 # in a temp file it's gone by now).
508 if datafile:
508 if datafile:
509 if lineno is None:
509 if lineno is None:
510 lineno = find_source_lines(data)
510 lineno = find_source_lines(data)
511 if lineno is None:
511 if lineno is None:
512 filename = make_filename(args)
512 filename = make_filename(args)
513 if filename is None:
513 if filename is None:
514 warn('The file where `%s` was defined '
514 warn('The file where `%s` was defined '
515 'cannot be read or found.' % data)
515 'cannot be read or found.' % data)
516 return (None, None, None)
516 return (None, None, None)
517 use_temp = False
517 use_temp = False
518
518
519 if use_temp:
519 if use_temp:
520 filename = shell.mktempfile(data)
520 filename = shell.mktempfile(data)
521 print('IPython will make a temporary file named:',filename)
521 print('IPython will make a temporary file named:',filename)
522
522
523 # use last_call to remember the state of the previous call, but don't
523 # use last_call to remember the state of the previous call, but don't
524 # let it be clobbered by successive '-p' calls.
524 # let it be clobbered by successive '-p' calls.
525 try:
525 try:
526 last_call[0] = shell.displayhook.prompt_count
526 last_call[0] = shell.displayhook.prompt_count
527 if not opts_prev:
527 if not opts_prev:
528 last_call[1] = args
528 last_call[1] = args
529 except:
529 except:
530 pass
530 pass
531
531
532
532
533 return filename, lineno, use_temp
533 return filename, lineno, use_temp
534
534
535 def _edit_macro(self,mname,macro):
535 def _edit_macro(self,mname,macro):
536 """open an editor with the macro data in a file"""
536 """open an editor with the macro data in a file"""
537 filename = self.shell.mktempfile(macro.value)
537 filename = self.shell.mktempfile(macro.value)
538 self.shell.hooks.editor(filename)
538 self.shell.hooks.editor(filename)
539
539
540 # and make a new macro object, to replace the old one
540 # and make a new macro object, to replace the old one
541 mvalue = Path(filename).read_text(encoding='utf-8')
541 mvalue = Path(filename).read_text(encoding="utf-8")
542 self.shell.user_ns[mname] = Macro(mvalue)
542 self.shell.user_ns[mname] = Macro(mvalue)
543
543
544 @skip_doctest
544 @skip_doctest
545 @line_magic
545 @line_magic
546 def edit(self, parameter_s='',last_call=['','']):
546 def edit(self, parameter_s='',last_call=['','']):
547 """Bring up an editor and execute the resulting code.
547 """Bring up an editor and execute the resulting code.
548
548
549 Usage:
549 Usage:
550 %edit [options] [args]
550 %edit [options] [args]
551
551
552 %edit runs IPython's editor hook. The default version of this hook is
552 %edit runs IPython's editor hook. The default version of this hook is
553 set to call the editor specified by your $EDITOR environment variable.
553 set to call the editor specified by your $EDITOR environment variable.
554 If this isn't found, it will default to vi under Linux/Unix and to
554 If this isn't found, it will default to vi under Linux/Unix and to
555 notepad under Windows. See the end of this docstring for how to change
555 notepad under Windows. See the end of this docstring for how to change
556 the editor hook.
556 the editor hook.
557
557
558 You can also set the value of this editor via the
558 You can also set the value of this editor via the
559 ``TerminalInteractiveShell.editor`` option in your configuration file.
559 ``TerminalInteractiveShell.editor`` option in your configuration file.
560 This is useful if you wish to use a different editor from your typical
560 This is useful if you wish to use a different editor from your typical
561 default with IPython (and for Windows users who typically don't set
561 default with IPython (and for Windows users who typically don't set
562 environment variables).
562 environment variables).
563
563
564 This command allows you to conveniently edit multi-line code right in
564 This command allows you to conveniently edit multi-line code right in
565 your IPython session.
565 your IPython session.
566
566
567 If called without arguments, %edit opens up an empty editor with a
567 If called without arguments, %edit opens up an empty editor with a
568 temporary file and will execute the contents of this file when you
568 temporary file and will execute the contents of this file when you
569 close it (don't forget to save it!).
569 close it (don't forget to save it!).
570
570
571
571
572 Options:
572 Options:
573
573
574 -n <number>: open the editor at a specified line number. By default,
574 -n <number>: open the editor at a specified line number. By default,
575 the IPython editor hook uses the unix syntax 'editor +N filename', but
575 the IPython editor hook uses the unix syntax 'editor +N filename', but
576 you can configure this by providing your own modified hook if your
576 you can configure this by providing your own modified hook if your
577 favorite editor supports line-number specifications with a different
577 favorite editor supports line-number specifications with a different
578 syntax.
578 syntax.
579
579
580 -p: this will call the editor with the same data as the previous time
580 -p: this will call the editor with the same data as the previous time
581 it was used, regardless of how long ago (in your current session) it
581 it was used, regardless of how long ago (in your current session) it
582 was.
582 was.
583
583
584 -r: use 'raw' input. This option only applies to input taken from the
584 -r: use 'raw' input. This option only applies to input taken from the
585 user's history. By default, the 'processed' history is used, so that
585 user's history. By default, the 'processed' history is used, so that
586 magics are loaded in their transformed version to valid Python. If
586 magics are loaded in their transformed version to valid Python. If
587 this option is given, the raw input as typed as the command line is
587 this option is given, the raw input as typed as the command line is
588 used instead. When you exit the editor, it will be executed by
588 used instead. When you exit the editor, it will be executed by
589 IPython's own processor.
589 IPython's own processor.
590
590
591 -x: do not execute the edited code immediately upon exit. This is
591 -x: do not execute the edited code immediately upon exit. This is
592 mainly useful if you are editing programs which need to be called with
592 mainly useful if you are editing programs which need to be called with
593 command line arguments, which you can then do using %run.
593 command line arguments, which you can then do using %run.
594
594
595
595
596 Arguments:
596 Arguments:
597
597
598 If arguments are given, the following possibilities exist:
598 If arguments are given, the following possibilities exist:
599
599
600 - If the argument is a filename, IPython will load that into the
600 - If the argument is a filename, IPython will load that into the
601 editor. It will execute its contents with execfile() when you exit,
601 editor. It will execute its contents with execfile() when you exit,
602 loading any code in the file into your interactive namespace.
602 loading any code in the file into your interactive namespace.
603
603
604 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
604 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
605 The syntax is the same as in the %history magic.
605 The syntax is the same as in the %history magic.
606
606
607 - If the argument is a string variable, its contents are loaded
607 - If the argument is a string variable, its contents are loaded
608 into the editor. You can thus edit any string which contains
608 into the editor. You can thus edit any string which contains
609 python code (including the result of previous edits).
609 python code (including the result of previous edits).
610
610
611 - If the argument is the name of an object (other than a string),
611 - If the argument is the name of an object (other than a string),
612 IPython will try to locate the file where it was defined and open the
612 IPython will try to locate the file where it was defined and open the
613 editor at the point where it is defined. You can use `%edit function`
613 editor at the point where it is defined. You can use `%edit function`
614 to load an editor exactly at the point where 'function' is defined,
614 to load an editor exactly at the point where 'function' is defined,
615 edit it and have the file be executed automatically.
615 edit it and have the file be executed automatically.
616
616
617 - If the object is a macro (see %macro for details), this opens up your
617 - If the object is a macro (see %macro for details), this opens up your
618 specified editor with a temporary file containing the macro's data.
618 specified editor with a temporary file containing the macro's data.
619 Upon exit, the macro is reloaded with the contents of the file.
619 Upon exit, the macro is reloaded with the contents of the file.
620
620
621 Note: opening at an exact line is only supported under Unix, and some
621 Note: opening at an exact line is only supported under Unix, and some
622 editors (like kedit and gedit up to Gnome 2.8) do not understand the
622 editors (like kedit and gedit up to Gnome 2.8) do not understand the
623 '+NUMBER' parameter necessary for this feature. Good editors like
623 '+NUMBER' parameter necessary for this feature. Good editors like
624 (X)Emacs, vi, jed, pico and joe all do.
624 (X)Emacs, vi, jed, pico and joe all do.
625
625
626 After executing your code, %edit will return as output the code you
626 After executing your code, %edit will return as output the code you
627 typed in the editor (except when it was an existing file). This way
627 typed in the editor (except when it was an existing file). This way
628 you can reload the code in further invocations of %edit as a variable,
628 you can reload the code in further invocations of %edit as a variable,
629 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
629 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
630 the output.
630 the output.
631
631
632 Note that %edit is also available through the alias %ed.
632 Note that %edit is also available through the alias %ed.
633
633
634 This is an example of creating a simple function inside the editor and
634 This is an example of creating a simple function inside the editor and
635 then modifying it. First, start up the editor::
635 then modifying it. First, start up the editor::
636
636
637 In [1]: edit
637 In [1]: edit
638 Editing... done. Executing edited code...
638 Editing... done. Executing edited code...
639 Out[1]: 'def foo():\\n print "foo() was defined in an editing
639 Out[1]: 'def foo():\\n print "foo() was defined in an editing
640 session"\\n'
640 session"\\n'
641
641
642 We can then call the function foo()::
642 We can then call the function foo()::
643
643
644 In [2]: foo()
644 In [2]: foo()
645 foo() was defined in an editing session
645 foo() was defined in an editing session
646
646
647 Now we edit foo. IPython automatically loads the editor with the
647 Now we edit foo. IPython automatically loads the editor with the
648 (temporary) file where foo() was previously defined::
648 (temporary) file where foo() was previously defined::
649
649
650 In [3]: edit foo
650 In [3]: edit foo
651 Editing... done. Executing edited code...
651 Editing... done. Executing edited code...
652
652
653 And if we call foo() again we get the modified version::
653 And if we call foo() again we get the modified version::
654
654
655 In [4]: foo()
655 In [4]: foo()
656 foo() has now been changed!
656 foo() has now been changed!
657
657
658 Here is an example of how to edit a code snippet successive
658 Here is an example of how to edit a code snippet successive
659 times. First we call the editor::
659 times. First we call the editor::
660
660
661 In [5]: edit
661 In [5]: edit
662 Editing... done. Executing edited code...
662 Editing... done. Executing edited code...
663 hello
663 hello
664 Out[5]: "print 'hello'\\n"
664 Out[5]: "print 'hello'\\n"
665
665
666 Now we call it again with the previous output (stored in _)::
666 Now we call it again with the previous output (stored in _)::
667
667
668 In [6]: edit _
668 In [6]: edit _
669 Editing... done. Executing edited code...
669 Editing... done. Executing edited code...
670 hello world
670 hello world
671 Out[6]: "print 'hello world'\\n"
671 Out[6]: "print 'hello world'\\n"
672
672
673 Now we call it with the output #8 (stored in _8, also as Out[8])::
673 Now we call it with the output #8 (stored in _8, also as Out[8])::
674
674
675 In [7]: edit _8
675 In [7]: edit _8
676 Editing... done. Executing edited code...
676 Editing... done. Executing edited code...
677 hello again
677 hello again
678 Out[7]: "print 'hello again'\\n"
678 Out[7]: "print 'hello again'\\n"
679
679
680
680
681 Changing the default editor hook:
681 Changing the default editor hook:
682
682
683 If you wish to write your own editor hook, you can put it in a
683 If you wish to write your own editor hook, you can put it in a
684 configuration file which you load at startup time. The default hook
684 configuration file which you load at startup time. The default hook
685 is defined in the IPython.core.hooks module, and you can use that as a
685 is defined in the IPython.core.hooks module, and you can use that as a
686 starting example for further modifications. That file also has
686 starting example for further modifications. That file also has
687 general instructions on how to set a new hook for use once you've
687 general instructions on how to set a new hook for use once you've
688 defined it."""
688 defined it."""
689 opts,args = self.parse_options(parameter_s,'prxn:')
689 opts,args = self.parse_options(parameter_s,'prxn:')
690
690
691 try:
691 try:
692 filename, lineno, is_temp = self._find_edit_target(self.shell,
692 filename, lineno, is_temp = self._find_edit_target(self.shell,
693 args, opts, last_call)
693 args, opts, last_call)
694 except MacroToEdit as e:
694 except MacroToEdit as e:
695 self._edit_macro(args, e.args[0])
695 self._edit_macro(args, e.args[0])
696 return
696 return
697 except InteractivelyDefined as e:
697 except InteractivelyDefined as e:
698 print("Editing In[%i]" % e.index)
698 print("Editing In[%i]" % e.index)
699 args = str(e.index)
699 args = str(e.index)
700 filename, lineno, is_temp = self._find_edit_target(self.shell,
700 filename, lineno, is_temp = self._find_edit_target(self.shell,
701 args, opts, last_call)
701 args, opts, last_call)
702 if filename is None:
702 if filename is None:
703 # nothing was found, warnings have already been issued,
703 # nothing was found, warnings have already been issued,
704 # just give up.
704 # just give up.
705 return
705 return
706
706
707 if is_temp:
707 if is_temp:
708 self._knowntemps.add(filename)
708 self._knowntemps.add(filename)
709 elif (filename in self._knowntemps):
709 elif (filename in self._knowntemps):
710 is_temp = True
710 is_temp = True
711
711
712
712
713 # do actual editing here
713 # do actual editing here
714 print('Editing...', end=' ')
714 print('Editing...', end=' ')
715 sys.stdout.flush()
715 sys.stdout.flush()
716 filepath = Path(filename)
716 filepath = Path(filename)
717 try:
717 try:
718 # Quote filenames that may have spaces in them when opening
718 # Quote filenames that may have spaces in them when opening
719 # the editor
719 # the editor
720 quoted = filename = str(filepath.absolute())
720 quoted = filename = str(filepath.absolute())
721 if " " in quoted:
721 if " " in quoted:
722 quoted = "'%s'" % quoted
722 quoted = "'%s'" % quoted
723 self.shell.hooks.editor(quoted, lineno)
723 self.shell.hooks.editor(quoted, lineno)
724 except TryNext:
724 except TryNext:
725 warn('Could not open editor')
725 warn('Could not open editor')
726 return
726 return
727
727
728 # XXX TODO: should this be generalized for all string vars?
728 # XXX TODO: should this be generalized for all string vars?
729 # For now, this is special-cased to blocks created by cpaste
729 # For now, this is special-cased to blocks created by cpaste
730 if args.strip() == "pasted_block":
730 if args.strip() == "pasted_block":
731 self.shell.user_ns["pasted_block"] = filepath.read_text(encoding='utf-8')
731 self.shell.user_ns["pasted_block"] = filepath.read_text(encoding="utf-8")
732
732
733 if 'x' in opts: # -x prevents actual execution
733 if 'x' in opts: # -x prevents actual execution
734 print()
734 print()
735 else:
735 else:
736 print('done. Executing edited code...')
736 print('done. Executing edited code...')
737 with preserve_keys(self.shell.user_ns, '__file__'):
737 with preserve_keys(self.shell.user_ns, '__file__'):
738 if not is_temp:
738 if not is_temp:
739 self.shell.user_ns['__file__'] = filename
739 self.shell.user_ns["__file__"] = filename
740 if 'r' in opts: # Untranslated IPython code
740 if "r" in opts: # Untranslated IPython code
741 source = filepath.read_text(encoding='utf-8')
741 source = filepath.read_text(encoding="utf-8")
742 self.shell.run_cell(source, store_history=False)
742 self.shell.run_cell(source, store_history=False)
743 else:
743 else:
744 self.shell.safe_execfile(filename, self.shell.user_ns,
744 self.shell.safe_execfile(filename, self.shell.user_ns,
745 self.shell.user_ns)
745 self.shell.user_ns)
746
746
747 if is_temp:
747 if is_temp:
748 try:
748 try:
749 return filepath.read_text(encoding='utf-8')
749 return filepath.read_text(encoding="utf-8")
750 except IOError as msg:
750 except IOError as msg:
751 if Path(msg.filename) == filepath:
751 if Path(msg.filename) == filepath:
752 warn('File not found. Did you forget to save?')
752 warn('File not found. Did you forget to save?')
753 return
753 return
754 else:
754 else:
755 self.shell.showtraceback()
755 self.shell.showtraceback()
@@ -1,1510 +1,1510 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Implementation of execution-related magic functions."""
2 """Implementation of execution-related magic functions."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7
7
8 import ast
8 import ast
9 import bdb
9 import bdb
10 import builtins as builtin_mod
10 import builtins as builtin_mod
11 import cProfile as profile
11 import cProfile as profile
12 import gc
12 import gc
13 import itertools
13 import itertools
14 import math
14 import math
15 import os
15 import os
16 import pstats
16 import pstats
17 import re
17 import re
18 import shlex
18 import shlex
19 import sys
19 import sys
20 import time
20 import time
21 import timeit
21 import timeit
22 from ast import Module
22 from ast import Module
23 from io import StringIO
23 from io import StringIO
24 from logging import error
24 from logging import error
25 from pathlib import Path
25 from pathlib import Path
26 from pdb import Restart
26 from pdb import Restart
27 from warnings import warn
27 from warnings import warn
28
28
29 from IPython.core import magic_arguments, oinspect, page
29 from IPython.core import magic_arguments, oinspect, page
30 from IPython.core.error import UsageError
30 from IPython.core.error import UsageError
31 from IPython.core.macro import Macro
31 from IPython.core.macro import Macro
32 from IPython.core.magic import (
32 from IPython.core.magic import (
33 Magics,
33 Magics,
34 cell_magic,
34 cell_magic,
35 line_cell_magic,
35 line_cell_magic,
36 line_magic,
36 line_magic,
37 magics_class,
37 magics_class,
38 needs_local_scope,
38 needs_local_scope,
39 no_var_expand,
39 no_var_expand,
40 on_off,
40 on_off,
41 )
41 )
42 from IPython.testing.skipdoctest import skip_doctest
42 from IPython.testing.skipdoctest import skip_doctest
43 from IPython.utils.capture import capture_output
43 from IPython.utils.capture import capture_output
44 from IPython.utils.contexts import preserve_keys
44 from IPython.utils.contexts import preserve_keys
45 from IPython.utils.ipstruct import Struct
45 from IPython.utils.ipstruct import Struct
46 from IPython.utils.module_paths import find_mod
46 from IPython.utils.module_paths import find_mod
47 from IPython.utils.path import get_py_filename, shellglob
47 from IPython.utils.path import get_py_filename, shellglob
48 from IPython.utils.timing import clock, clock2
48 from IPython.utils.timing import clock, clock2
49
49
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51 # Magic implementation classes
51 # Magic implementation classes
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53
53
54
54
55 class TimeitResult(object):
55 class TimeitResult(object):
56 """
56 """
57 Object returned by the timeit magic with info about the run.
57 Object returned by the timeit magic with info about the run.
58
58
59 Contains the following attributes :
59 Contains the following attributes :
60
60
61 loops: (int) number of loops done per measurement
61 loops: (int) number of loops done per measurement
62 repeat: (int) number of times the measurement has been repeated
62 repeat: (int) number of times the measurement has been repeated
63 best: (float) best execution time / number
63 best: (float) best execution time / number
64 all_runs: (list of float) execution time of each run (in s)
64 all_runs: (list of float) execution time of each run (in s)
65 compile_time: (float) time of statement compilation (s)
65 compile_time: (float) time of statement compilation (s)
66
66
67 """
67 """
68 def __init__(self, loops, repeat, best, worst, all_runs, compile_time, precision):
68 def __init__(self, loops, repeat, best, worst, all_runs, compile_time, precision):
69 self.loops = loops
69 self.loops = loops
70 self.repeat = repeat
70 self.repeat = repeat
71 self.best = best
71 self.best = best
72 self.worst = worst
72 self.worst = worst
73 self.all_runs = all_runs
73 self.all_runs = all_runs
74 self.compile_time = compile_time
74 self.compile_time = compile_time
75 self._precision = precision
75 self._precision = precision
76 self.timings = [ dt / self.loops for dt in all_runs]
76 self.timings = [ dt / self.loops for dt in all_runs]
77
77
78 @property
78 @property
79 def average(self):
79 def average(self):
80 return math.fsum(self.timings) / len(self.timings)
80 return math.fsum(self.timings) / len(self.timings)
81
81
82 @property
82 @property
83 def stdev(self):
83 def stdev(self):
84 mean = self.average
84 mean = self.average
85 return (math.fsum([(x - mean) ** 2 for x in self.timings]) / len(self.timings)) ** 0.5
85 return (math.fsum([(x - mean) ** 2 for x in self.timings]) / len(self.timings)) ** 0.5
86
86
87 def __str__(self):
87 def __str__(self):
88 pm = '+-'
88 pm = '+-'
89 if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
89 if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
90 try:
90 try:
91 u'\xb1'.encode(sys.stdout.encoding)
91 u'\xb1'.encode(sys.stdout.encoding)
92 pm = u'\xb1'
92 pm = u'\xb1'
93 except:
93 except:
94 pass
94 pass
95 return "{mean} {pm} {std} per loop (mean {pm} std. dev. of {runs} run{run_plural}, {loops:,} loop{loop_plural} each)".format(
95 return "{mean} {pm} {std} per loop (mean {pm} std. dev. of {runs} run{run_plural}, {loops:,} loop{loop_plural} each)".format(
96 pm=pm,
96 pm=pm,
97 runs=self.repeat,
97 runs=self.repeat,
98 loops=self.loops,
98 loops=self.loops,
99 loop_plural="" if self.loops == 1 else "s",
99 loop_plural="" if self.loops == 1 else "s",
100 run_plural="" if self.repeat == 1 else "s",
100 run_plural="" if self.repeat == 1 else "s",
101 mean=_format_time(self.average, self._precision),
101 mean=_format_time(self.average, self._precision),
102 std=_format_time(self.stdev, self._precision),
102 std=_format_time(self.stdev, self._precision),
103 )
103 )
104
104
105 def _repr_pretty_(self, p , cycle):
105 def _repr_pretty_(self, p , cycle):
106 unic = self.__str__()
106 unic = self.__str__()
107 p.text(u'<TimeitResult : '+unic+u'>')
107 p.text(u'<TimeitResult : '+unic+u'>')
108
108
109
109
110 class TimeitTemplateFiller(ast.NodeTransformer):
110 class TimeitTemplateFiller(ast.NodeTransformer):
111 """Fill in the AST template for timing execution.
111 """Fill in the AST template for timing execution.
112
112
113 This is quite closely tied to the template definition, which is in
113 This is quite closely tied to the template definition, which is in
114 :meth:`ExecutionMagics.timeit`.
114 :meth:`ExecutionMagics.timeit`.
115 """
115 """
116 def __init__(self, ast_setup, ast_stmt):
116 def __init__(self, ast_setup, ast_stmt):
117 self.ast_setup = ast_setup
117 self.ast_setup = ast_setup
118 self.ast_stmt = ast_stmt
118 self.ast_stmt = ast_stmt
119
119
120 def visit_FunctionDef(self, node):
120 def visit_FunctionDef(self, node):
121 "Fill in the setup statement"
121 "Fill in the setup statement"
122 self.generic_visit(node)
122 self.generic_visit(node)
123 if node.name == "inner":
123 if node.name == "inner":
124 node.body[:1] = self.ast_setup.body
124 node.body[:1] = self.ast_setup.body
125
125
126 return node
126 return node
127
127
128 def visit_For(self, node):
128 def visit_For(self, node):
129 "Fill in the statement to be timed"
129 "Fill in the statement to be timed"
130 if getattr(getattr(node.body[0], 'value', None), 'id', None) == 'stmt':
130 if getattr(getattr(node.body[0], 'value', None), 'id', None) == 'stmt':
131 node.body = self.ast_stmt.body
131 node.body = self.ast_stmt.body
132 return node
132 return node
133
133
134
134
135 class Timer(timeit.Timer):
135 class Timer(timeit.Timer):
136 """Timer class that explicitly uses self.inner
136 """Timer class that explicitly uses self.inner
137
137
138 which is an undocumented implementation detail of CPython,
138 which is an undocumented implementation detail of CPython,
139 not shared by PyPy.
139 not shared by PyPy.
140 """
140 """
141 # Timer.timeit copied from CPython 3.4.2
141 # Timer.timeit copied from CPython 3.4.2
142 def timeit(self, number=timeit.default_number):
142 def timeit(self, number=timeit.default_number):
143 """Time 'number' executions of the main statement.
143 """Time 'number' executions of the main statement.
144
144
145 To be precise, this executes the setup statement once, and
145 To be precise, this executes the setup statement once, and
146 then returns the time it takes to execute the main statement
146 then returns the time it takes to execute the main statement
147 a number of times, as a float measured in seconds. The
147 a number of times, as a float measured in seconds. The
148 argument is the number of times through the loop, defaulting
148 argument is the number of times through the loop, defaulting
149 to one million. The main statement, the setup statement and
149 to one million. The main statement, the setup statement and
150 the timer function to be used are passed to the constructor.
150 the timer function to be used are passed to the constructor.
151 """
151 """
152 it = itertools.repeat(None, number)
152 it = itertools.repeat(None, number)
153 gcold = gc.isenabled()
153 gcold = gc.isenabled()
154 gc.disable()
154 gc.disable()
155 try:
155 try:
156 timing = self.inner(it, self.timer)
156 timing = self.inner(it, self.timer)
157 finally:
157 finally:
158 if gcold:
158 if gcold:
159 gc.enable()
159 gc.enable()
160 return timing
160 return timing
161
161
162
162
163 @magics_class
163 @magics_class
164 class ExecutionMagics(Magics):
164 class ExecutionMagics(Magics):
165 """Magics related to code execution, debugging, profiling, etc.
165 """Magics related to code execution, debugging, profiling, etc.
166
166
167 """
167 """
168
168
169 def __init__(self, shell):
169 def __init__(self, shell):
170 super(ExecutionMagics, self).__init__(shell)
170 super(ExecutionMagics, self).__init__(shell)
171 # Default execution function used to actually run user code.
171 # Default execution function used to actually run user code.
172 self.default_runner = None
172 self.default_runner = None
173
173
174 @skip_doctest
174 @skip_doctest
175 @no_var_expand
175 @no_var_expand
176 @line_cell_magic
176 @line_cell_magic
177 def prun(self, parameter_s='', cell=None):
177 def prun(self, parameter_s='', cell=None):
178
178
179 """Run a statement through the python code profiler.
179 """Run a statement through the python code profiler.
180
180
181 Usage, in line mode:
181 Usage, in line mode:
182 %prun [options] statement
182 %prun [options] statement
183
183
184 Usage, in cell mode:
184 Usage, in cell mode:
185 %%prun [options] [statement]
185 %%prun [options] [statement]
186 code...
186 code...
187 code...
187 code...
188
188
189 In cell mode, the additional code lines are appended to the (possibly
189 In cell mode, the additional code lines are appended to the (possibly
190 empty) statement in the first line. Cell mode allows you to easily
190 empty) statement in the first line. Cell mode allows you to easily
191 profile multiline blocks without having to put them in a separate
191 profile multiline blocks without having to put them in a separate
192 function.
192 function.
193
193
194 The given statement (which doesn't require quote marks) is run via the
194 The given statement (which doesn't require quote marks) is run via the
195 python profiler in a manner similar to the profile.run() function.
195 python profiler in a manner similar to the profile.run() function.
196 Namespaces are internally managed to work correctly; profile.run
196 Namespaces are internally managed to work correctly; profile.run
197 cannot be used in IPython because it makes certain assumptions about
197 cannot be used in IPython because it makes certain assumptions about
198 namespaces which do not hold under IPython.
198 namespaces which do not hold under IPython.
199
199
200 Options:
200 Options:
201
201
202 -l <limit>
202 -l <limit>
203 you can place restrictions on what or how much of the
203 you can place restrictions on what or how much of the
204 profile gets printed. The limit value can be:
204 profile gets printed. The limit value can be:
205
205
206 * A string: only information for function names containing this string
206 * A string: only information for function names containing this string
207 is printed.
207 is printed.
208
208
209 * An integer: only these many lines are printed.
209 * An integer: only these many lines are printed.
210
210
211 * A float (between 0 and 1): this fraction of the report is printed
211 * A float (between 0 and 1): this fraction of the report is printed
212 (for example, use a limit of 0.4 to see the topmost 40% only).
212 (for example, use a limit of 0.4 to see the topmost 40% only).
213
213
214 You can combine several limits with repeated use of the option. For
214 You can combine several limits with repeated use of the option. For
215 example, ``-l __init__ -l 5`` will print only the topmost 5 lines of
215 example, ``-l __init__ -l 5`` will print only the topmost 5 lines of
216 information about class constructors.
216 information about class constructors.
217
217
218 -r
218 -r
219 return the pstats.Stats object generated by the profiling. This
219 return the pstats.Stats object generated by the profiling. This
220 object has all the information about the profile in it, and you can
220 object has all the information about the profile in it, and you can
221 later use it for further analysis or in other functions.
221 later use it for further analysis or in other functions.
222
222
223 -s <key>
223 -s <key>
224 sort profile by given key. You can provide more than one key
224 sort profile by given key. You can provide more than one key
225 by using the option several times: '-s key1 -s key2 -s key3...'. The
225 by using the option several times: '-s key1 -s key2 -s key3...'. The
226 default sorting key is 'time'.
226 default sorting key is 'time'.
227
227
228 The following is copied verbatim from the profile documentation
228 The following is copied verbatim from the profile documentation
229 referenced below:
229 referenced below:
230
230
231 When more than one key is provided, additional keys are used as
231 When more than one key is provided, additional keys are used as
232 secondary criteria when the there is equality in all keys selected
232 secondary criteria when the there is equality in all keys selected
233 before them.
233 before them.
234
234
235 Abbreviations can be used for any key names, as long as the
235 Abbreviations can be used for any key names, as long as the
236 abbreviation is unambiguous. The following are the keys currently
236 abbreviation is unambiguous. The following are the keys currently
237 defined:
237 defined:
238
238
239 ============ =====================
239 ============ =====================
240 Valid Arg Meaning
240 Valid Arg Meaning
241 ============ =====================
241 ============ =====================
242 "calls" call count
242 "calls" call count
243 "cumulative" cumulative time
243 "cumulative" cumulative time
244 "file" file name
244 "file" file name
245 "module" file name
245 "module" file name
246 "pcalls" primitive call count
246 "pcalls" primitive call count
247 "line" line number
247 "line" line number
248 "name" function name
248 "name" function name
249 "nfl" name/file/line
249 "nfl" name/file/line
250 "stdname" standard name
250 "stdname" standard name
251 "time" internal time
251 "time" internal time
252 ============ =====================
252 ============ =====================
253
253
254 Note that all sorts on statistics are in descending order (placing
254 Note that all sorts on statistics are in descending order (placing
255 most time consuming items first), where as name, file, and line number
255 most time consuming items first), where as name, file, and line number
256 searches are in ascending order (i.e., alphabetical). The subtle
256 searches are in ascending order (i.e., alphabetical). The subtle
257 distinction between "nfl" and "stdname" is that the standard name is a
257 distinction between "nfl" and "stdname" is that the standard name is a
258 sort of the name as printed, which means that the embedded line
258 sort of the name as printed, which means that the embedded line
259 numbers get compared in an odd way. For example, lines 3, 20, and 40
259 numbers get compared in an odd way. For example, lines 3, 20, and 40
260 would (if the file names were the same) appear in the string order
260 would (if the file names were the same) appear in the string order
261 "20" "3" and "40". In contrast, "nfl" does a numeric compare of the
261 "20" "3" and "40". In contrast, "nfl" does a numeric compare of the
262 line numbers. In fact, sort_stats("nfl") is the same as
262 line numbers. In fact, sort_stats("nfl") is the same as
263 sort_stats("name", "file", "line").
263 sort_stats("name", "file", "line").
264
264
265 -T <filename>
265 -T <filename>
266 save profile results as shown on screen to a text
266 save profile results as shown on screen to a text
267 file. The profile is still shown on screen.
267 file. The profile is still shown on screen.
268
268
269 -D <filename>
269 -D <filename>
270 save (via dump_stats) profile statistics to given
270 save (via dump_stats) profile statistics to given
271 filename. This data is in a format understood by the pstats module, and
271 filename. This data is in a format understood by the pstats module, and
272 is generated by a call to the dump_stats() method of profile
272 is generated by a call to the dump_stats() method of profile
273 objects. The profile is still shown on screen.
273 objects. The profile is still shown on screen.
274
274
275 -q
275 -q
276 suppress output to the pager. Best used with -T and/or -D above.
276 suppress output to the pager. Best used with -T and/or -D above.
277
277
278 If you want to run complete programs under the profiler's control, use
278 If you want to run complete programs under the profiler's control, use
279 ``%run -p [prof_opts] filename.py [args to program]`` where prof_opts
279 ``%run -p [prof_opts] filename.py [args to program]`` where prof_opts
280 contains profiler specific options as described here.
280 contains profiler specific options as described here.
281
281
282 You can read the complete documentation for the profile module with::
282 You can read the complete documentation for the profile module with::
283
283
284 In [1]: import profile; profile.help()
284 In [1]: import profile; profile.help()
285
285
286 .. versionchanged:: 7.3
286 .. versionchanged:: 7.3
287 User variables are no longer expanded,
287 User variables are no longer expanded,
288 the magic line is always left unmodified.
288 the magic line is always left unmodified.
289
289
290 """
290 """
291 opts, arg_str = self.parse_options(parameter_s, 'D:l:rs:T:q',
291 opts, arg_str = self.parse_options(parameter_s, 'D:l:rs:T:q',
292 list_all=True, posix=False)
292 list_all=True, posix=False)
293 if cell is not None:
293 if cell is not None:
294 arg_str += '\n' + cell
294 arg_str += '\n' + cell
295 arg_str = self.shell.transform_cell(arg_str)
295 arg_str = self.shell.transform_cell(arg_str)
296 return self._run_with_profiler(arg_str, opts, self.shell.user_ns)
296 return self._run_with_profiler(arg_str, opts, self.shell.user_ns)
297
297
298 def _run_with_profiler(self, code, opts, namespace):
298 def _run_with_profiler(self, code, opts, namespace):
299 """
299 """
300 Run `code` with profiler. Used by ``%prun`` and ``%run -p``.
300 Run `code` with profiler. Used by ``%prun`` and ``%run -p``.
301
301
302 Parameters
302 Parameters
303 ----------
303 ----------
304 code : str
304 code : str
305 Code to be executed.
305 Code to be executed.
306 opts : Struct
306 opts : Struct
307 Options parsed by `self.parse_options`.
307 Options parsed by `self.parse_options`.
308 namespace : dict
308 namespace : dict
309 A dictionary for Python namespace (e.g., `self.shell.user_ns`).
309 A dictionary for Python namespace (e.g., `self.shell.user_ns`).
310
310
311 """
311 """
312
312
313 # Fill default values for unspecified options:
313 # Fill default values for unspecified options:
314 opts.merge(Struct(D=[''], l=[], s=['time'], T=['']))
314 opts.merge(Struct(D=[''], l=[], s=['time'], T=['']))
315
315
316 prof = profile.Profile()
316 prof = profile.Profile()
317 try:
317 try:
318 prof = prof.runctx(code, namespace, namespace)
318 prof = prof.runctx(code, namespace, namespace)
319 sys_exit = ''
319 sys_exit = ''
320 except SystemExit:
320 except SystemExit:
321 sys_exit = """*** SystemExit exception caught in code being profiled."""
321 sys_exit = """*** SystemExit exception caught in code being profiled."""
322
322
323 stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
323 stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
324
324
325 lims = opts.l
325 lims = opts.l
326 if lims:
326 if lims:
327 lims = [] # rebuild lims with ints/floats/strings
327 lims = [] # rebuild lims with ints/floats/strings
328 for lim in opts.l:
328 for lim in opts.l:
329 try:
329 try:
330 lims.append(int(lim))
330 lims.append(int(lim))
331 except ValueError:
331 except ValueError:
332 try:
332 try:
333 lims.append(float(lim))
333 lims.append(float(lim))
334 except ValueError:
334 except ValueError:
335 lims.append(lim)
335 lims.append(lim)
336
336
337 # Trap output.
337 # Trap output.
338 stdout_trap = StringIO()
338 stdout_trap = StringIO()
339 stats_stream = stats.stream
339 stats_stream = stats.stream
340 try:
340 try:
341 stats.stream = stdout_trap
341 stats.stream = stdout_trap
342 stats.print_stats(*lims)
342 stats.print_stats(*lims)
343 finally:
343 finally:
344 stats.stream = stats_stream
344 stats.stream = stats_stream
345
345
346 output = stdout_trap.getvalue()
346 output = stdout_trap.getvalue()
347 output = output.rstrip()
347 output = output.rstrip()
348
348
349 if 'q' not in opts:
349 if 'q' not in opts:
350 page.page(output)
350 page.page(output)
351 print(sys_exit, end=' ')
351 print(sys_exit, end=' ')
352
352
353 dump_file = opts.D[0]
353 dump_file = opts.D[0]
354 text_file = opts.T[0]
354 text_file = opts.T[0]
355 if dump_file:
355 if dump_file:
356 prof.dump_stats(dump_file)
356 prof.dump_stats(dump_file)
357 print(
357 print(
358 f"\n*** Profile stats marshalled to file {repr(dump_file)}.{sys_exit}"
358 f"\n*** Profile stats marshalled to file {repr(dump_file)}.{sys_exit}"
359 )
359 )
360 if text_file:
360 if text_file:
361 pfile = Path(text_file)
361 pfile = Path(text_file)
362 pfile.touch(exist_ok=True)
362 pfile.touch(exist_ok=True)
363 pfile.write_text(output, encoding='utf-8')
363 pfile.write_text(output, encoding="utf-8")
364
364
365 print(
365 print(
366 f"\n*** Profile printout saved to text file {repr(text_file)}.{sys_exit}"
366 f"\n*** Profile printout saved to text file {repr(text_file)}.{sys_exit}"
367 )
367 )
368
368
369 if 'r' in opts:
369 if 'r' in opts:
370 return stats
370 return stats
371
371
372 return None
372 return None
373
373
374 @line_magic
374 @line_magic
375 def pdb(self, parameter_s=''):
375 def pdb(self, parameter_s=''):
376 """Control the automatic calling of the pdb interactive debugger.
376 """Control the automatic calling of the pdb interactive debugger.
377
377
378 Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
378 Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
379 argument it works as a toggle.
379 argument it works as a toggle.
380
380
381 When an exception is triggered, IPython can optionally call the
381 When an exception is triggered, IPython can optionally call the
382 interactive pdb debugger after the traceback printout. %pdb toggles
382 interactive pdb debugger after the traceback printout. %pdb toggles
383 this feature on and off.
383 this feature on and off.
384
384
385 The initial state of this feature is set in your configuration
385 The initial state of this feature is set in your configuration
386 file (the option is ``InteractiveShell.pdb``).
386 file (the option is ``InteractiveShell.pdb``).
387
387
388 If you want to just activate the debugger AFTER an exception has fired,
388 If you want to just activate the debugger AFTER an exception has fired,
389 without having to type '%pdb on' and rerunning your code, you can use
389 without having to type '%pdb on' and rerunning your code, you can use
390 the %debug magic."""
390 the %debug magic."""
391
391
392 par = parameter_s.strip().lower()
392 par = parameter_s.strip().lower()
393
393
394 if par:
394 if par:
395 try:
395 try:
396 new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
396 new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
397 except KeyError:
397 except KeyError:
398 print ('Incorrect argument. Use on/1, off/0, '
398 print ('Incorrect argument. Use on/1, off/0, '
399 'or nothing for a toggle.')
399 'or nothing for a toggle.')
400 return
400 return
401 else:
401 else:
402 # toggle
402 # toggle
403 new_pdb = not self.shell.call_pdb
403 new_pdb = not self.shell.call_pdb
404
404
405 # set on the shell
405 # set on the shell
406 self.shell.call_pdb = new_pdb
406 self.shell.call_pdb = new_pdb
407 print('Automatic pdb calling has been turned',on_off(new_pdb))
407 print('Automatic pdb calling has been turned',on_off(new_pdb))
408
408
409 @magic_arguments.magic_arguments()
409 @magic_arguments.magic_arguments()
410 @magic_arguments.argument('--breakpoint', '-b', metavar='FILE:LINE',
410 @magic_arguments.argument('--breakpoint', '-b', metavar='FILE:LINE',
411 help="""
411 help="""
412 Set break point at LINE in FILE.
412 Set break point at LINE in FILE.
413 """
413 """
414 )
414 )
415 @magic_arguments.argument('statement', nargs='*',
415 @magic_arguments.argument('statement', nargs='*',
416 help="""
416 help="""
417 Code to run in debugger.
417 Code to run in debugger.
418 You can omit this in cell magic mode.
418 You can omit this in cell magic mode.
419 """
419 """
420 )
420 )
421 @no_var_expand
421 @no_var_expand
422 @line_cell_magic
422 @line_cell_magic
423 def debug(self, line='', cell=None):
423 def debug(self, line='', cell=None):
424 """Activate the interactive debugger.
424 """Activate the interactive debugger.
425
425
426 This magic command support two ways of activating debugger.
426 This magic command support two ways of activating debugger.
427 One is to activate debugger before executing code. This way, you
427 One is to activate debugger before executing code. This way, you
428 can set a break point, to step through the code from the point.
428 can set a break point, to step through the code from the point.
429 You can use this mode by giving statements to execute and optionally
429 You can use this mode by giving statements to execute and optionally
430 a breakpoint.
430 a breakpoint.
431
431
432 The other one is to activate debugger in post-mortem mode. You can
432 The other one is to activate debugger in post-mortem mode. You can
433 activate this mode simply running %debug without any argument.
433 activate this mode simply running %debug without any argument.
434 If an exception has just occurred, this lets you inspect its stack
434 If an exception has just occurred, this lets you inspect its stack
435 frames interactively. Note that this will always work only on the last
435 frames interactively. Note that this will always work only on the last
436 traceback that occurred, so you must call this quickly after an
436 traceback that occurred, so you must call this quickly after an
437 exception that you wish to inspect has fired, because if another one
437 exception that you wish to inspect has fired, because if another one
438 occurs, it clobbers the previous one.
438 occurs, it clobbers the previous one.
439
439
440 If you want IPython to automatically do this on every exception, see
440 If you want IPython to automatically do this on every exception, see
441 the %pdb magic for more details.
441 the %pdb magic for more details.
442
442
443 .. versionchanged:: 7.3
443 .. versionchanged:: 7.3
444 When running code, user variables are no longer expanded,
444 When running code, user variables are no longer expanded,
445 the magic line is always left unmodified.
445 the magic line is always left unmodified.
446
446
447 """
447 """
448 args = magic_arguments.parse_argstring(self.debug, line)
448 args = magic_arguments.parse_argstring(self.debug, line)
449
449
450 if not (args.breakpoint or args.statement or cell):
450 if not (args.breakpoint or args.statement or cell):
451 self._debug_post_mortem()
451 self._debug_post_mortem()
452 elif not (args.breakpoint or cell):
452 elif not (args.breakpoint or cell):
453 # If there is no breakpoints, the line is just code to execute
453 # If there is no breakpoints, the line is just code to execute
454 self._debug_exec(line, None)
454 self._debug_exec(line, None)
455 else:
455 else:
456 # Here we try to reconstruct the code from the output of
456 # Here we try to reconstruct the code from the output of
457 # parse_argstring. This might not work if the code has spaces
457 # parse_argstring. This might not work if the code has spaces
458 # For example this fails for `print("a b")`
458 # For example this fails for `print("a b")`
459 code = "\n".join(args.statement)
459 code = "\n".join(args.statement)
460 if cell:
460 if cell:
461 code += "\n" + cell
461 code += "\n" + cell
462 self._debug_exec(code, args.breakpoint)
462 self._debug_exec(code, args.breakpoint)
463
463
464 def _debug_post_mortem(self):
464 def _debug_post_mortem(self):
465 self.shell.debugger(force=True)
465 self.shell.debugger(force=True)
466
466
467 def _debug_exec(self, code, breakpoint):
467 def _debug_exec(self, code, breakpoint):
468 if breakpoint:
468 if breakpoint:
469 (filename, bp_line) = breakpoint.rsplit(':', 1)
469 (filename, bp_line) = breakpoint.rsplit(':', 1)
470 bp_line = int(bp_line)
470 bp_line = int(bp_line)
471 else:
471 else:
472 (filename, bp_line) = (None, None)
472 (filename, bp_line) = (None, None)
473 self._run_with_debugger(code, self.shell.user_ns, filename, bp_line)
473 self._run_with_debugger(code, self.shell.user_ns, filename, bp_line)
474
474
475 @line_magic
475 @line_magic
476 def tb(self, s):
476 def tb(self, s):
477 """Print the last traceback.
477 """Print the last traceback.
478
478
479 Optionally, specify an exception reporting mode, tuning the
479 Optionally, specify an exception reporting mode, tuning the
480 verbosity of the traceback. By default the currently-active exception
480 verbosity of the traceback. By default the currently-active exception
481 mode is used. See %xmode for changing exception reporting modes.
481 mode is used. See %xmode for changing exception reporting modes.
482
482
483 Valid modes: Plain, Context, Verbose, and Minimal.
483 Valid modes: Plain, Context, Verbose, and Minimal.
484 """
484 """
485 interactive_tb = self.shell.InteractiveTB
485 interactive_tb = self.shell.InteractiveTB
486 if s:
486 if s:
487 # Switch exception reporting mode for this one call.
487 # Switch exception reporting mode for this one call.
488 # Ensure it is switched back.
488 # Ensure it is switched back.
489 def xmode_switch_err(name):
489 def xmode_switch_err(name):
490 warn('Error changing %s exception modes.\n%s' %
490 warn('Error changing %s exception modes.\n%s' %
491 (name,sys.exc_info()[1]))
491 (name,sys.exc_info()[1]))
492
492
493 new_mode = s.strip().capitalize()
493 new_mode = s.strip().capitalize()
494 original_mode = interactive_tb.mode
494 original_mode = interactive_tb.mode
495 try:
495 try:
496 try:
496 try:
497 interactive_tb.set_mode(mode=new_mode)
497 interactive_tb.set_mode(mode=new_mode)
498 except Exception:
498 except Exception:
499 xmode_switch_err('user')
499 xmode_switch_err('user')
500 else:
500 else:
501 self.shell.showtraceback()
501 self.shell.showtraceback()
502 finally:
502 finally:
503 interactive_tb.set_mode(mode=original_mode)
503 interactive_tb.set_mode(mode=original_mode)
504 else:
504 else:
505 self.shell.showtraceback()
505 self.shell.showtraceback()
506
506
507 @skip_doctest
507 @skip_doctest
508 @line_magic
508 @line_magic
509 def run(self, parameter_s='', runner=None,
509 def run(self, parameter_s='', runner=None,
510 file_finder=get_py_filename):
510 file_finder=get_py_filename):
511 """Run the named file inside IPython as a program.
511 """Run the named file inside IPython as a program.
512
512
513 Usage::
513 Usage::
514
514
515 %run [-n -i -e -G]
515 %run [-n -i -e -G]
516 [( -t [-N<N>] | -d [-b<N>] | -p [profile options] )]
516 [( -t [-N<N>] | -d [-b<N>] | -p [profile options] )]
517 ( -m mod | filename ) [args]
517 ( -m mod | filename ) [args]
518
518
519 The filename argument should be either a pure Python script (with
519 The filename argument should be either a pure Python script (with
520 extension ``.py``), or a file with custom IPython syntax (such as
520 extension ``.py``), or a file with custom IPython syntax (such as
521 magics). If the latter, the file can be either a script with ``.ipy``
521 magics). If the latter, the file can be either a script with ``.ipy``
522 extension, or a Jupyter notebook with ``.ipynb`` extension. When running
522 extension, or a Jupyter notebook with ``.ipynb`` extension. When running
523 a Jupyter notebook, the output from print statements and other
523 a Jupyter notebook, the output from print statements and other
524 displayed objects will appear in the terminal (even matplotlib figures
524 displayed objects will appear in the terminal (even matplotlib figures
525 will open, if a terminal-compliant backend is being used). Note that,
525 will open, if a terminal-compliant backend is being used). Note that,
526 at the system command line, the ``jupyter run`` command offers similar
526 at the system command line, the ``jupyter run`` command offers similar
527 functionality for executing notebooks (albeit currently with some
527 functionality for executing notebooks (albeit currently with some
528 differences in supported options).
528 differences in supported options).
529
529
530 Parameters after the filename are passed as command-line arguments to
530 Parameters after the filename are passed as command-line arguments to
531 the program (put in sys.argv). Then, control returns to IPython's
531 the program (put in sys.argv). Then, control returns to IPython's
532 prompt.
532 prompt.
533
533
534 This is similar to running at a system prompt ``python file args``,
534 This is similar to running at a system prompt ``python file args``,
535 but with the advantage of giving you IPython's tracebacks, and of
535 but with the advantage of giving you IPython's tracebacks, and of
536 loading all variables into your interactive namespace for further use
536 loading all variables into your interactive namespace for further use
537 (unless -p is used, see below).
537 (unless -p is used, see below).
538
538
539 The file is executed in a namespace initially consisting only of
539 The file is executed in a namespace initially consisting only of
540 ``__name__=='__main__'`` and sys.argv constructed as indicated. It thus
540 ``__name__=='__main__'`` and sys.argv constructed as indicated. It thus
541 sees its environment as if it were being run as a stand-alone program
541 sees its environment as if it were being run as a stand-alone program
542 (except for sharing global objects such as previously imported
542 (except for sharing global objects such as previously imported
543 modules). But after execution, the IPython interactive namespace gets
543 modules). But after execution, the IPython interactive namespace gets
544 updated with all variables defined in the program (except for __name__
544 updated with all variables defined in the program (except for __name__
545 and sys.argv). This allows for very convenient loading of code for
545 and sys.argv). This allows for very convenient loading of code for
546 interactive work, while giving each program a 'clean sheet' to run in.
546 interactive work, while giving each program a 'clean sheet' to run in.
547
547
548 Arguments are expanded using shell-like glob match. Patterns
548 Arguments are expanded using shell-like glob match. Patterns
549 '*', '?', '[seq]' and '[!seq]' can be used. Additionally,
549 '*', '?', '[seq]' and '[!seq]' can be used. Additionally,
550 tilde '~' will be expanded into user's home directory. Unlike
550 tilde '~' will be expanded into user's home directory. Unlike
551 real shells, quotation does not suppress expansions. Use
551 real shells, quotation does not suppress expansions. Use
552 *two* back slashes (e.g. ``\\\\*``) to suppress expansions.
552 *two* back slashes (e.g. ``\\\\*``) to suppress expansions.
553 To completely disable these expansions, you can use -G flag.
553 To completely disable these expansions, you can use -G flag.
554
554
555 On Windows systems, the use of single quotes `'` when specifying
555 On Windows systems, the use of single quotes `'` when specifying
556 a file is not supported. Use double quotes `"`.
556 a file is not supported. Use double quotes `"`.
557
557
558 Options:
558 Options:
559
559
560 -n
560 -n
561 __name__ is NOT set to '__main__', but to the running file's name
561 __name__ is NOT set to '__main__', but to the running file's name
562 without extension (as python does under import). This allows running
562 without extension (as python does under import). This allows running
563 scripts and reloading the definitions in them without calling code
563 scripts and reloading the definitions in them without calling code
564 protected by an ``if __name__ == "__main__"`` clause.
564 protected by an ``if __name__ == "__main__"`` clause.
565
565
566 -i
566 -i
567 run the file in IPython's namespace instead of an empty one. This
567 run the file in IPython's namespace instead of an empty one. This
568 is useful if you are experimenting with code written in a text editor
568 is useful if you are experimenting with code written in a text editor
569 which depends on variables defined interactively.
569 which depends on variables defined interactively.
570
570
571 -e
571 -e
572 ignore sys.exit() calls or SystemExit exceptions in the script
572 ignore sys.exit() calls or SystemExit exceptions in the script
573 being run. This is particularly useful if IPython is being used to
573 being run. This is particularly useful if IPython is being used to
574 run unittests, which always exit with a sys.exit() call. In such
574 run unittests, which always exit with a sys.exit() call. In such
575 cases you are interested in the output of the test results, not in
575 cases you are interested in the output of the test results, not in
576 seeing a traceback of the unittest module.
576 seeing a traceback of the unittest module.
577
577
578 -t
578 -t
579 print timing information at the end of the run. IPython will give
579 print timing information at the end of the run. IPython will give
580 you an estimated CPU time consumption for your script, which under
580 you an estimated CPU time consumption for your script, which under
581 Unix uses the resource module to avoid the wraparound problems of
581 Unix uses the resource module to avoid the wraparound problems of
582 time.clock(). Under Unix, an estimate of time spent on system tasks
582 time.clock(). Under Unix, an estimate of time spent on system tasks
583 is also given (for Windows platforms this is reported as 0.0).
583 is also given (for Windows platforms this is reported as 0.0).
584
584
585 If -t is given, an additional ``-N<N>`` option can be given, where <N>
585 If -t is given, an additional ``-N<N>`` option can be given, where <N>
586 must be an integer indicating how many times you want the script to
586 must be an integer indicating how many times you want the script to
587 run. The final timing report will include total and per run results.
587 run. The final timing report will include total and per run results.
588
588
589 For example (testing the script uniq_stable.py)::
589 For example (testing the script uniq_stable.py)::
590
590
591 In [1]: run -t uniq_stable
591 In [1]: run -t uniq_stable
592
592
593 IPython CPU timings (estimated):
593 IPython CPU timings (estimated):
594 User : 0.19597 s.
594 User : 0.19597 s.
595 System: 0.0 s.
595 System: 0.0 s.
596
596
597 In [2]: run -t -N5 uniq_stable
597 In [2]: run -t -N5 uniq_stable
598
598
599 IPython CPU timings (estimated):
599 IPython CPU timings (estimated):
600 Total runs performed: 5
600 Total runs performed: 5
601 Times : Total Per run
601 Times : Total Per run
602 User : 0.910862 s, 0.1821724 s.
602 User : 0.910862 s, 0.1821724 s.
603 System: 0.0 s, 0.0 s.
603 System: 0.0 s, 0.0 s.
604
604
605 -d
605 -d
606 run your program under the control of pdb, the Python debugger.
606 run your program under the control of pdb, the Python debugger.
607 This allows you to execute your program step by step, watch variables,
607 This allows you to execute your program step by step, watch variables,
608 etc. Internally, what IPython does is similar to calling::
608 etc. Internally, what IPython does is similar to calling::
609
609
610 pdb.run('execfile("YOURFILENAME")')
610 pdb.run('execfile("YOURFILENAME")')
611
611
612 with a breakpoint set on line 1 of your file. You can change the line
612 with a breakpoint set on line 1 of your file. You can change the line
613 number for this automatic breakpoint to be <N> by using the -bN option
613 number for this automatic breakpoint to be <N> by using the -bN option
614 (where N must be an integer). For example::
614 (where N must be an integer). For example::
615
615
616 %run -d -b40 myscript
616 %run -d -b40 myscript
617
617
618 will set the first breakpoint at line 40 in myscript.py. Note that
618 will set the first breakpoint at line 40 in myscript.py. Note that
619 the first breakpoint must be set on a line which actually does
619 the first breakpoint must be set on a line which actually does
620 something (not a comment or docstring) for it to stop execution.
620 something (not a comment or docstring) for it to stop execution.
621
621
622 Or you can specify a breakpoint in a different file::
622 Or you can specify a breakpoint in a different file::
623
623
624 %run -d -b myotherfile.py:20 myscript
624 %run -d -b myotherfile.py:20 myscript
625
625
626 When the pdb debugger starts, you will see a (Pdb) prompt. You must
626 When the pdb debugger starts, you will see a (Pdb) prompt. You must
627 first enter 'c' (without quotes) to start execution up to the first
627 first enter 'c' (without quotes) to start execution up to the first
628 breakpoint.
628 breakpoint.
629
629
630 Entering 'help' gives information about the use of the debugger. You
630 Entering 'help' gives information about the use of the debugger. You
631 can easily see pdb's full documentation with "import pdb;pdb.help()"
631 can easily see pdb's full documentation with "import pdb;pdb.help()"
632 at a prompt.
632 at a prompt.
633
633
634 -p
634 -p
635 run program under the control of the Python profiler module (which
635 run program under the control of the Python profiler module (which
636 prints a detailed report of execution times, function calls, etc).
636 prints a detailed report of execution times, function calls, etc).
637
637
638 You can pass other options after -p which affect the behavior of the
638 You can pass other options after -p which affect the behavior of the
639 profiler itself. See the docs for %prun for details.
639 profiler itself. See the docs for %prun for details.
640
640
641 In this mode, the program's variables do NOT propagate back to the
641 In this mode, the program's variables do NOT propagate back to the
642 IPython interactive namespace (because they remain in the namespace
642 IPython interactive namespace (because they remain in the namespace
643 where the profiler executes them).
643 where the profiler executes them).
644
644
645 Internally this triggers a call to %prun, see its documentation for
645 Internally this triggers a call to %prun, see its documentation for
646 details on the options available specifically for profiling.
646 details on the options available specifically for profiling.
647
647
648 There is one special usage for which the text above doesn't apply:
648 There is one special usage for which the text above doesn't apply:
649 if the filename ends with .ipy[nb], the file is run as ipython script,
649 if the filename ends with .ipy[nb], the file is run as ipython script,
650 just as if the commands were written on IPython prompt.
650 just as if the commands were written on IPython prompt.
651
651
652 -m
652 -m
653 specify module name to load instead of script path. Similar to
653 specify module name to load instead of script path. Similar to
654 the -m option for the python interpreter. Use this option last if you
654 the -m option for the python interpreter. Use this option last if you
655 want to combine with other %run options. Unlike the python interpreter
655 want to combine with other %run options. Unlike the python interpreter
656 only source modules are allowed no .pyc or .pyo files.
656 only source modules are allowed no .pyc or .pyo files.
657 For example::
657 For example::
658
658
659 %run -m example
659 %run -m example
660
660
661 will run the example module.
661 will run the example module.
662
662
663 -G
663 -G
664 disable shell-like glob expansion of arguments.
664 disable shell-like glob expansion of arguments.
665
665
666 """
666 """
667
667
668 # Logic to handle issue #3664
668 # Logic to handle issue #3664
669 # Add '--' after '-m <module_name>' to ignore additional args passed to a module.
669 # Add '--' after '-m <module_name>' to ignore additional args passed to a module.
670 if '-m' in parameter_s and '--' not in parameter_s:
670 if '-m' in parameter_s and '--' not in parameter_s:
671 argv = shlex.split(parameter_s, posix=(os.name == 'posix'))
671 argv = shlex.split(parameter_s, posix=(os.name == 'posix'))
672 for idx, arg in enumerate(argv):
672 for idx, arg in enumerate(argv):
673 if arg and arg.startswith('-') and arg != '-':
673 if arg and arg.startswith('-') and arg != '-':
674 if arg == '-m':
674 if arg == '-m':
675 argv.insert(idx + 2, '--')
675 argv.insert(idx + 2, '--')
676 break
676 break
677 else:
677 else:
678 # Positional arg, break
678 # Positional arg, break
679 break
679 break
680 parameter_s = ' '.join(shlex.quote(arg) for arg in argv)
680 parameter_s = ' '.join(shlex.quote(arg) for arg in argv)
681
681
682 # get arguments and set sys.argv for program to be run.
682 # get arguments and set sys.argv for program to be run.
683 opts, arg_lst = self.parse_options(parameter_s,
683 opts, arg_lst = self.parse_options(parameter_s,
684 'nidtN:b:pD:l:rs:T:em:G',
684 'nidtN:b:pD:l:rs:T:em:G',
685 mode='list', list_all=1)
685 mode='list', list_all=1)
686 if "m" in opts:
686 if "m" in opts:
687 modulename = opts["m"][0]
687 modulename = opts["m"][0]
688 modpath = find_mod(modulename)
688 modpath = find_mod(modulename)
689 if modpath is None:
689 if modpath is None:
690 msg = '%r is not a valid modulename on sys.path'%modulename
690 msg = '%r is not a valid modulename on sys.path'%modulename
691 raise Exception(msg)
691 raise Exception(msg)
692 arg_lst = [modpath] + arg_lst
692 arg_lst = [modpath] + arg_lst
693 try:
693 try:
694 fpath = None # initialize to make sure fpath is in scope later
694 fpath = None # initialize to make sure fpath is in scope later
695 fpath = arg_lst[0]
695 fpath = arg_lst[0]
696 filename = file_finder(fpath)
696 filename = file_finder(fpath)
697 except IndexError as e:
697 except IndexError as e:
698 msg = 'you must provide at least a filename.'
698 msg = 'you must provide at least a filename.'
699 raise Exception(msg) from e
699 raise Exception(msg) from e
700 except IOError as e:
700 except IOError as e:
701 try:
701 try:
702 msg = str(e)
702 msg = str(e)
703 except UnicodeError:
703 except UnicodeError:
704 msg = e.message
704 msg = e.message
705 if os.name == 'nt' and re.match(r"^'.*'$",fpath):
705 if os.name == 'nt' and re.match(r"^'.*'$",fpath):
706 warn('For Windows, use double quotes to wrap a filename: %run "mypath\\myfile.py"')
706 warn('For Windows, use double quotes to wrap a filename: %run "mypath\\myfile.py"')
707 raise Exception(msg) from e
707 raise Exception(msg) from e
708 except TypeError:
708 except TypeError:
709 if fpath in sys.meta_path:
709 if fpath in sys.meta_path:
710 filename = ""
710 filename = ""
711 else:
711 else:
712 raise
712 raise
713
713
714 if filename.lower().endswith(('.ipy', '.ipynb')):
714 if filename.lower().endswith(('.ipy', '.ipynb')):
715 with preserve_keys(self.shell.user_ns, '__file__'):
715 with preserve_keys(self.shell.user_ns, '__file__'):
716 self.shell.user_ns['__file__'] = filename
716 self.shell.user_ns['__file__'] = filename
717 self.shell.safe_execfile_ipy(filename, raise_exceptions=True)
717 self.shell.safe_execfile_ipy(filename, raise_exceptions=True)
718 return
718 return
719
719
720 # Control the response to exit() calls made by the script being run
720 # Control the response to exit() calls made by the script being run
721 exit_ignore = 'e' in opts
721 exit_ignore = 'e' in opts
722
722
723 # Make sure that the running script gets a proper sys.argv as if it
723 # Make sure that the running script gets a proper sys.argv as if it
724 # were run from a system shell.
724 # were run from a system shell.
725 save_argv = sys.argv # save it for later restoring
725 save_argv = sys.argv # save it for later restoring
726
726
727 if 'G' in opts:
727 if 'G' in opts:
728 args = arg_lst[1:]
728 args = arg_lst[1:]
729 else:
729 else:
730 # tilde and glob expansion
730 # tilde and glob expansion
731 args = shellglob(map(os.path.expanduser, arg_lst[1:]))
731 args = shellglob(map(os.path.expanduser, arg_lst[1:]))
732
732
733 sys.argv = [filename] + args # put in the proper filename
733 sys.argv = [filename] + args # put in the proper filename
734
734
735 if 'n' in opts:
735 if 'n' in opts:
736 name = Path(filename).stem
736 name = Path(filename).stem
737 else:
737 else:
738 name = '__main__'
738 name = '__main__'
739
739
740 if 'i' in opts:
740 if 'i' in opts:
741 # Run in user's interactive namespace
741 # Run in user's interactive namespace
742 prog_ns = self.shell.user_ns
742 prog_ns = self.shell.user_ns
743 __name__save = self.shell.user_ns['__name__']
743 __name__save = self.shell.user_ns['__name__']
744 prog_ns['__name__'] = name
744 prog_ns['__name__'] = name
745 main_mod = self.shell.user_module
745 main_mod = self.shell.user_module
746
746
747 # Since '%run foo' emulates 'python foo.py' at the cmd line, we must
747 # Since '%run foo' emulates 'python foo.py' at the cmd line, we must
748 # set the __file__ global in the script's namespace
748 # set the __file__ global in the script's namespace
749 # TK: Is this necessary in interactive mode?
749 # TK: Is this necessary in interactive mode?
750 prog_ns['__file__'] = filename
750 prog_ns['__file__'] = filename
751 else:
751 else:
752 # Run in a fresh, empty namespace
752 # Run in a fresh, empty namespace
753
753
754 # The shell MUST hold a reference to prog_ns so after %run
754 # The shell MUST hold a reference to prog_ns so after %run
755 # exits, the python deletion mechanism doesn't zero it out
755 # exits, the python deletion mechanism doesn't zero it out
756 # (leaving dangling references). See interactiveshell for details
756 # (leaving dangling references). See interactiveshell for details
757 main_mod = self.shell.new_main_mod(filename, name)
757 main_mod = self.shell.new_main_mod(filename, name)
758 prog_ns = main_mod.__dict__
758 prog_ns = main_mod.__dict__
759
759
760 # pickle fix. See interactiveshell for an explanation. But we need to
760 # pickle fix. See interactiveshell for an explanation. But we need to
761 # make sure that, if we overwrite __main__, we replace it at the end
761 # make sure that, if we overwrite __main__, we replace it at the end
762 main_mod_name = prog_ns['__name__']
762 main_mod_name = prog_ns['__name__']
763
763
764 if main_mod_name == '__main__':
764 if main_mod_name == '__main__':
765 restore_main = sys.modules['__main__']
765 restore_main = sys.modules['__main__']
766 else:
766 else:
767 restore_main = False
767 restore_main = False
768
768
769 # This needs to be undone at the end to prevent holding references to
769 # This needs to be undone at the end to prevent holding references to
770 # every single object ever created.
770 # every single object ever created.
771 sys.modules[main_mod_name] = main_mod
771 sys.modules[main_mod_name] = main_mod
772
772
773 if 'p' in opts or 'd' in opts:
773 if 'p' in opts or 'd' in opts:
774 if 'm' in opts:
774 if 'm' in opts:
775 code = 'run_module(modulename, prog_ns)'
775 code = 'run_module(modulename, prog_ns)'
776 code_ns = {
776 code_ns = {
777 'run_module': self.shell.safe_run_module,
777 'run_module': self.shell.safe_run_module,
778 'prog_ns': prog_ns,
778 'prog_ns': prog_ns,
779 'modulename': modulename,
779 'modulename': modulename,
780 }
780 }
781 else:
781 else:
782 if 'd' in opts:
782 if 'd' in opts:
783 # allow exceptions to raise in debug mode
783 # allow exceptions to raise in debug mode
784 code = 'execfile(filename, prog_ns, raise_exceptions=True)'
784 code = 'execfile(filename, prog_ns, raise_exceptions=True)'
785 else:
785 else:
786 code = 'execfile(filename, prog_ns)'
786 code = 'execfile(filename, prog_ns)'
787 code_ns = {
787 code_ns = {
788 'execfile': self.shell.safe_execfile,
788 'execfile': self.shell.safe_execfile,
789 'prog_ns': prog_ns,
789 'prog_ns': prog_ns,
790 'filename': get_py_filename(filename),
790 'filename': get_py_filename(filename),
791 }
791 }
792
792
793 try:
793 try:
794 stats = None
794 stats = None
795 if 'p' in opts:
795 if 'p' in opts:
796 stats = self._run_with_profiler(code, opts, code_ns)
796 stats = self._run_with_profiler(code, opts, code_ns)
797 else:
797 else:
798 if 'd' in opts:
798 if 'd' in opts:
799 bp_file, bp_line = parse_breakpoint(
799 bp_file, bp_line = parse_breakpoint(
800 opts.get('b', ['1'])[0], filename)
800 opts.get('b', ['1'])[0], filename)
801 self._run_with_debugger(
801 self._run_with_debugger(
802 code, code_ns, filename, bp_line, bp_file)
802 code, code_ns, filename, bp_line, bp_file)
803 else:
803 else:
804 if 'm' in opts:
804 if 'm' in opts:
805 def run():
805 def run():
806 self.shell.safe_run_module(modulename, prog_ns)
806 self.shell.safe_run_module(modulename, prog_ns)
807 else:
807 else:
808 if runner is None:
808 if runner is None:
809 runner = self.default_runner
809 runner = self.default_runner
810 if runner is None:
810 if runner is None:
811 runner = self.shell.safe_execfile
811 runner = self.shell.safe_execfile
812
812
813 def run():
813 def run():
814 runner(filename, prog_ns, prog_ns,
814 runner(filename, prog_ns, prog_ns,
815 exit_ignore=exit_ignore)
815 exit_ignore=exit_ignore)
816
816
817 if 't' in opts:
817 if 't' in opts:
818 # timed execution
818 # timed execution
819 try:
819 try:
820 nruns = int(opts['N'][0])
820 nruns = int(opts['N'][0])
821 if nruns < 1:
821 if nruns < 1:
822 error('Number of runs must be >=1')
822 error('Number of runs must be >=1')
823 return
823 return
824 except (KeyError):
824 except (KeyError):
825 nruns = 1
825 nruns = 1
826 self._run_with_timing(run, nruns)
826 self._run_with_timing(run, nruns)
827 else:
827 else:
828 # regular execution
828 # regular execution
829 run()
829 run()
830
830
831 if 'i' in opts:
831 if 'i' in opts:
832 self.shell.user_ns['__name__'] = __name__save
832 self.shell.user_ns['__name__'] = __name__save
833 else:
833 else:
834 # update IPython interactive namespace
834 # update IPython interactive namespace
835
835
836 # Some forms of read errors on the file may mean the
836 # Some forms of read errors on the file may mean the
837 # __name__ key was never set; using pop we don't have to
837 # __name__ key was never set; using pop we don't have to
838 # worry about a possible KeyError.
838 # worry about a possible KeyError.
839 prog_ns.pop('__name__', None)
839 prog_ns.pop('__name__', None)
840
840
841 with preserve_keys(self.shell.user_ns, '__file__'):
841 with preserve_keys(self.shell.user_ns, '__file__'):
842 self.shell.user_ns.update(prog_ns)
842 self.shell.user_ns.update(prog_ns)
843 finally:
843 finally:
844 # It's a bit of a mystery why, but __builtins__ can change from
844 # It's a bit of a mystery why, but __builtins__ can change from
845 # being a module to becoming a dict missing some key data after
845 # being a module to becoming a dict missing some key data after
846 # %run. As best I can see, this is NOT something IPython is doing
846 # %run. As best I can see, this is NOT something IPython is doing
847 # at all, and similar problems have been reported before:
847 # at all, and similar problems have been reported before:
848 # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
848 # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
849 # Since this seems to be done by the interpreter itself, the best
849 # Since this seems to be done by the interpreter itself, the best
850 # we can do is to at least restore __builtins__ for the user on
850 # we can do is to at least restore __builtins__ for the user on
851 # exit.
851 # exit.
852 self.shell.user_ns['__builtins__'] = builtin_mod
852 self.shell.user_ns['__builtins__'] = builtin_mod
853
853
854 # Ensure key global structures are restored
854 # Ensure key global structures are restored
855 sys.argv = save_argv
855 sys.argv = save_argv
856 if restore_main:
856 if restore_main:
857 sys.modules['__main__'] = restore_main
857 sys.modules['__main__'] = restore_main
858 if '__mp_main__' in sys.modules:
858 if '__mp_main__' in sys.modules:
859 sys.modules['__mp_main__'] = restore_main
859 sys.modules['__mp_main__'] = restore_main
860 else:
860 else:
861 # Remove from sys.modules the reference to main_mod we'd
861 # Remove from sys.modules the reference to main_mod we'd
862 # added. Otherwise it will trap references to objects
862 # added. Otherwise it will trap references to objects
863 # contained therein.
863 # contained therein.
864 del sys.modules[main_mod_name]
864 del sys.modules[main_mod_name]
865
865
866 return stats
866 return stats
867
867
868 def _run_with_debugger(self, code, code_ns, filename=None,
868 def _run_with_debugger(self, code, code_ns, filename=None,
869 bp_line=None, bp_file=None):
869 bp_line=None, bp_file=None):
870 """
870 """
871 Run `code` in debugger with a break point.
871 Run `code` in debugger with a break point.
872
872
873 Parameters
873 Parameters
874 ----------
874 ----------
875 code : str
875 code : str
876 Code to execute.
876 Code to execute.
877 code_ns : dict
877 code_ns : dict
878 A namespace in which `code` is executed.
878 A namespace in which `code` is executed.
879 filename : str
879 filename : str
880 `code` is ran as if it is in `filename`.
880 `code` is ran as if it is in `filename`.
881 bp_line : int, optional
881 bp_line : int, optional
882 Line number of the break point.
882 Line number of the break point.
883 bp_file : str, optional
883 bp_file : str, optional
884 Path to the file in which break point is specified.
884 Path to the file in which break point is specified.
885 `filename` is used if not given.
885 `filename` is used if not given.
886
886
887 Raises
887 Raises
888 ------
888 ------
889 UsageError
889 UsageError
890 If the break point given by `bp_line` is not valid.
890 If the break point given by `bp_line` is not valid.
891
891
892 """
892 """
893 deb = self.shell.InteractiveTB.pdb
893 deb = self.shell.InteractiveTB.pdb
894 if not deb:
894 if not deb:
895 self.shell.InteractiveTB.pdb = self.shell.InteractiveTB.debugger_cls()
895 self.shell.InteractiveTB.pdb = self.shell.InteractiveTB.debugger_cls()
896 deb = self.shell.InteractiveTB.pdb
896 deb = self.shell.InteractiveTB.pdb
897
897
898 # deb.checkline() fails if deb.curframe exists but is None; it can
898 # deb.checkline() fails if deb.curframe exists but is None; it can
899 # handle it not existing. https://github.com/ipython/ipython/issues/10028
899 # handle it not existing. https://github.com/ipython/ipython/issues/10028
900 if hasattr(deb, 'curframe'):
900 if hasattr(deb, 'curframe'):
901 del deb.curframe
901 del deb.curframe
902
902
903 # reset Breakpoint state, which is moronically kept
903 # reset Breakpoint state, which is moronically kept
904 # in a class
904 # in a class
905 bdb.Breakpoint.next = 1
905 bdb.Breakpoint.next = 1
906 bdb.Breakpoint.bplist = {}
906 bdb.Breakpoint.bplist = {}
907 bdb.Breakpoint.bpbynumber = [None]
907 bdb.Breakpoint.bpbynumber = [None]
908 deb.clear_all_breaks()
908 deb.clear_all_breaks()
909 if bp_line is not None:
909 if bp_line is not None:
910 # Set an initial breakpoint to stop execution
910 # Set an initial breakpoint to stop execution
911 maxtries = 10
911 maxtries = 10
912 bp_file = bp_file or filename
912 bp_file = bp_file or filename
913 checkline = deb.checkline(bp_file, bp_line)
913 checkline = deb.checkline(bp_file, bp_line)
914 if not checkline:
914 if not checkline:
915 for bp in range(bp_line + 1, bp_line + maxtries + 1):
915 for bp in range(bp_line + 1, bp_line + maxtries + 1):
916 if deb.checkline(bp_file, bp):
916 if deb.checkline(bp_file, bp):
917 break
917 break
918 else:
918 else:
919 msg = ("\nI failed to find a valid line to set "
919 msg = ("\nI failed to find a valid line to set "
920 "a breakpoint\n"
920 "a breakpoint\n"
921 "after trying up to line: %s.\n"
921 "after trying up to line: %s.\n"
922 "Please set a valid breakpoint manually "
922 "Please set a valid breakpoint manually "
923 "with the -b option." % bp)
923 "with the -b option." % bp)
924 raise UsageError(msg)
924 raise UsageError(msg)
925 # if we find a good linenumber, set the breakpoint
925 # if we find a good linenumber, set the breakpoint
926 deb.do_break('%s:%s' % (bp_file, bp_line))
926 deb.do_break('%s:%s' % (bp_file, bp_line))
927
927
928 if filename:
928 if filename:
929 # Mimic Pdb._runscript(...)
929 # Mimic Pdb._runscript(...)
930 deb._wait_for_mainpyfile = True
930 deb._wait_for_mainpyfile = True
931 deb.mainpyfile = deb.canonic(filename)
931 deb.mainpyfile = deb.canonic(filename)
932
932
933 # Start file run
933 # Start file run
934 print("NOTE: Enter 'c' at the %s prompt to continue execution." % deb.prompt)
934 print("NOTE: Enter 'c' at the %s prompt to continue execution." % deb.prompt)
935 try:
935 try:
936 if filename:
936 if filename:
937 # save filename so it can be used by methods on the deb object
937 # save filename so it can be used by methods on the deb object
938 deb._exec_filename = filename
938 deb._exec_filename = filename
939 while True:
939 while True:
940 try:
940 try:
941 trace = sys.gettrace()
941 trace = sys.gettrace()
942 deb.run(code, code_ns)
942 deb.run(code, code_ns)
943 except Restart:
943 except Restart:
944 print("Restarting")
944 print("Restarting")
945 if filename:
945 if filename:
946 deb._wait_for_mainpyfile = True
946 deb._wait_for_mainpyfile = True
947 deb.mainpyfile = deb.canonic(filename)
947 deb.mainpyfile = deb.canonic(filename)
948 continue
948 continue
949 else:
949 else:
950 break
950 break
951 finally:
951 finally:
952 sys.settrace(trace)
952 sys.settrace(trace)
953
953
954
954
955 except:
955 except:
956 etype, value, tb = sys.exc_info()
956 etype, value, tb = sys.exc_info()
957 # Skip three frames in the traceback: the %run one,
957 # Skip three frames in the traceback: the %run one,
958 # one inside bdb.py, and the command-line typed by the
958 # one inside bdb.py, and the command-line typed by the
959 # user (run by exec in pdb itself).
959 # user (run by exec in pdb itself).
960 self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
960 self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
961
961
962 @staticmethod
962 @staticmethod
963 def _run_with_timing(run, nruns):
963 def _run_with_timing(run, nruns):
964 """
964 """
965 Run function `run` and print timing information.
965 Run function `run` and print timing information.
966
966
967 Parameters
967 Parameters
968 ----------
968 ----------
969 run : callable
969 run : callable
970 Any callable object which takes no argument.
970 Any callable object which takes no argument.
971 nruns : int
971 nruns : int
972 Number of times to execute `run`.
972 Number of times to execute `run`.
973
973
974 """
974 """
975 twall0 = time.perf_counter()
975 twall0 = time.perf_counter()
976 if nruns == 1:
976 if nruns == 1:
977 t0 = clock2()
977 t0 = clock2()
978 run()
978 run()
979 t1 = clock2()
979 t1 = clock2()
980 t_usr = t1[0] - t0[0]
980 t_usr = t1[0] - t0[0]
981 t_sys = t1[1] - t0[1]
981 t_sys = t1[1] - t0[1]
982 print("\nIPython CPU timings (estimated):")
982 print("\nIPython CPU timings (estimated):")
983 print(" User : %10.2f s." % t_usr)
983 print(" User : %10.2f s." % t_usr)
984 print(" System : %10.2f s." % t_sys)
984 print(" System : %10.2f s." % t_sys)
985 else:
985 else:
986 runs = range(nruns)
986 runs = range(nruns)
987 t0 = clock2()
987 t0 = clock2()
988 for nr in runs:
988 for nr in runs:
989 run()
989 run()
990 t1 = clock2()
990 t1 = clock2()
991 t_usr = t1[0] - t0[0]
991 t_usr = t1[0] - t0[0]
992 t_sys = t1[1] - t0[1]
992 t_sys = t1[1] - t0[1]
993 print("\nIPython CPU timings (estimated):")
993 print("\nIPython CPU timings (estimated):")
994 print("Total runs performed:", nruns)
994 print("Total runs performed:", nruns)
995 print(" Times : %10s %10s" % ('Total', 'Per run'))
995 print(" Times : %10s %10s" % ('Total', 'Per run'))
996 print(" User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns))
996 print(" User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns))
997 print(" System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns))
997 print(" System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns))
998 twall1 = time.perf_counter()
998 twall1 = time.perf_counter()
999 print("Wall time: %10.2f s." % (twall1 - twall0))
999 print("Wall time: %10.2f s." % (twall1 - twall0))
1000
1000
1001 @skip_doctest
1001 @skip_doctest
1002 @no_var_expand
1002 @no_var_expand
1003 @line_cell_magic
1003 @line_cell_magic
1004 @needs_local_scope
1004 @needs_local_scope
1005 def timeit(self, line='', cell=None, local_ns=None):
1005 def timeit(self, line='', cell=None, local_ns=None):
1006 """Time execution of a Python statement or expression
1006 """Time execution of a Python statement or expression
1007
1007
1008 Usage, in line mode:
1008 Usage, in line mode:
1009 %timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] statement
1009 %timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] statement
1010 or in cell mode:
1010 or in cell mode:
1011 %%timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] setup_code
1011 %%timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] setup_code
1012 code
1012 code
1013 code...
1013 code...
1014
1014
1015 Time execution of a Python statement or expression using the timeit
1015 Time execution of a Python statement or expression using the timeit
1016 module. This function can be used both as a line and cell magic:
1016 module. This function can be used both as a line and cell magic:
1017
1017
1018 - In line mode you can time a single-line statement (though multiple
1018 - In line mode you can time a single-line statement (though multiple
1019 ones can be chained with using semicolons).
1019 ones can be chained with using semicolons).
1020
1020
1021 - In cell mode, the statement in the first line is used as setup code
1021 - In cell mode, the statement in the first line is used as setup code
1022 (executed but not timed) and the body of the cell is timed. The cell
1022 (executed but not timed) and the body of the cell is timed. The cell
1023 body has access to any variables created in the setup code.
1023 body has access to any variables created in the setup code.
1024
1024
1025 Options:
1025 Options:
1026 -n<N>: execute the given statement <N> times in a loop. If <N> is not
1026 -n<N>: execute the given statement <N> times in a loop. If <N> is not
1027 provided, <N> is determined so as to get sufficient accuracy.
1027 provided, <N> is determined so as to get sufficient accuracy.
1028
1028
1029 -r<R>: number of repeats <R>, each consisting of <N> loops, and take the
1029 -r<R>: number of repeats <R>, each consisting of <N> loops, and take the
1030 best result.
1030 best result.
1031 Default: 7
1031 Default: 7
1032
1032
1033 -t: use time.time to measure the time, which is the default on Unix.
1033 -t: use time.time to measure the time, which is the default on Unix.
1034 This function measures wall time.
1034 This function measures wall time.
1035
1035
1036 -c: use time.clock to measure the time, which is the default on
1036 -c: use time.clock to measure the time, which is the default on
1037 Windows and measures wall time. On Unix, resource.getrusage is used
1037 Windows and measures wall time. On Unix, resource.getrusage is used
1038 instead and returns the CPU user time.
1038 instead and returns the CPU user time.
1039
1039
1040 -p<P>: use a precision of <P> digits to display the timing result.
1040 -p<P>: use a precision of <P> digits to display the timing result.
1041 Default: 3
1041 Default: 3
1042
1042
1043 -q: Quiet, do not print result.
1043 -q: Quiet, do not print result.
1044
1044
1045 -o: return a TimeitResult that can be stored in a variable to inspect
1045 -o: return a TimeitResult that can be stored in a variable to inspect
1046 the result in more details.
1046 the result in more details.
1047
1047
1048 .. versionchanged:: 7.3
1048 .. versionchanged:: 7.3
1049 User variables are no longer expanded,
1049 User variables are no longer expanded,
1050 the magic line is always left unmodified.
1050 the magic line is always left unmodified.
1051
1051
1052 Examples
1052 Examples
1053 --------
1053 --------
1054 ::
1054 ::
1055
1055
1056 In [1]: %timeit pass
1056 In [1]: %timeit pass
1057 8.26 ns ± 0.12 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)
1057 8.26 ns ± 0.12 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)
1058
1058
1059 In [2]: u = None
1059 In [2]: u = None
1060
1060
1061 In [3]: %timeit u is None
1061 In [3]: %timeit u is None
1062 29.9 ns ± 0.643 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
1062 29.9 ns ± 0.643 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
1063
1063
1064 In [4]: %timeit -r 4 u == None
1064 In [4]: %timeit -r 4 u == None
1065
1065
1066 In [5]: import time
1066 In [5]: import time
1067
1067
1068 In [6]: %timeit -n1 time.sleep(2)
1068 In [6]: %timeit -n1 time.sleep(2)
1069
1069
1070 The times reported by %timeit will be slightly higher than those
1070 The times reported by %timeit will be slightly higher than those
1071 reported by the timeit.py script when variables are accessed. This is
1071 reported by the timeit.py script when variables are accessed. This is
1072 due to the fact that %timeit executes the statement in the namespace
1072 due to the fact that %timeit executes the statement in the namespace
1073 of the shell, compared with timeit.py, which uses a single setup
1073 of the shell, compared with timeit.py, which uses a single setup
1074 statement to import function or create variables. Generally, the bias
1074 statement to import function or create variables. Generally, the bias
1075 does not matter as long as results from timeit.py are not mixed with
1075 does not matter as long as results from timeit.py are not mixed with
1076 those from %timeit."""
1076 those from %timeit."""
1077
1077
1078 opts, stmt = self.parse_options(
1078 opts, stmt = self.parse_options(
1079 line, "n:r:tcp:qo", posix=False, strict=False, preserve_non_opts=True
1079 line, "n:r:tcp:qo", posix=False, strict=False, preserve_non_opts=True
1080 )
1080 )
1081 if stmt == "" and cell is None:
1081 if stmt == "" and cell is None:
1082 return
1082 return
1083
1083
1084 timefunc = timeit.default_timer
1084 timefunc = timeit.default_timer
1085 number = int(getattr(opts, "n", 0))
1085 number = int(getattr(opts, "n", 0))
1086 default_repeat = 7 if timeit.default_repeat < 7 else timeit.default_repeat
1086 default_repeat = 7 if timeit.default_repeat < 7 else timeit.default_repeat
1087 repeat = int(getattr(opts, "r", default_repeat))
1087 repeat = int(getattr(opts, "r", default_repeat))
1088 precision = int(getattr(opts, "p", 3))
1088 precision = int(getattr(opts, "p", 3))
1089 quiet = 'q' in opts
1089 quiet = 'q' in opts
1090 return_result = 'o' in opts
1090 return_result = 'o' in opts
1091 if hasattr(opts, "t"):
1091 if hasattr(opts, "t"):
1092 timefunc = time.time
1092 timefunc = time.time
1093 if hasattr(opts, "c"):
1093 if hasattr(opts, "c"):
1094 timefunc = clock
1094 timefunc = clock
1095
1095
1096 timer = Timer(timer=timefunc)
1096 timer = Timer(timer=timefunc)
1097 # this code has tight coupling to the inner workings of timeit.Timer,
1097 # this code has tight coupling to the inner workings of timeit.Timer,
1098 # but is there a better way to achieve that the code stmt has access
1098 # but is there a better way to achieve that the code stmt has access
1099 # to the shell namespace?
1099 # to the shell namespace?
1100 transform = self.shell.transform_cell
1100 transform = self.shell.transform_cell
1101
1101
1102 if cell is None:
1102 if cell is None:
1103 # called as line magic
1103 # called as line magic
1104 ast_setup = self.shell.compile.ast_parse("pass")
1104 ast_setup = self.shell.compile.ast_parse("pass")
1105 ast_stmt = self.shell.compile.ast_parse(transform(stmt))
1105 ast_stmt = self.shell.compile.ast_parse(transform(stmt))
1106 else:
1106 else:
1107 ast_setup = self.shell.compile.ast_parse(transform(stmt))
1107 ast_setup = self.shell.compile.ast_parse(transform(stmt))
1108 ast_stmt = self.shell.compile.ast_parse(transform(cell))
1108 ast_stmt = self.shell.compile.ast_parse(transform(cell))
1109
1109
1110 ast_setup = self.shell.transform_ast(ast_setup)
1110 ast_setup = self.shell.transform_ast(ast_setup)
1111 ast_stmt = self.shell.transform_ast(ast_stmt)
1111 ast_stmt = self.shell.transform_ast(ast_stmt)
1112
1112
1113 # Check that these compile to valid Python code *outside* the timer func
1113 # Check that these compile to valid Python code *outside* the timer func
1114 # Invalid code may become valid when put inside the function & loop,
1114 # Invalid code may become valid when put inside the function & loop,
1115 # which messes up error messages.
1115 # which messes up error messages.
1116 # https://github.com/ipython/ipython/issues/10636
1116 # https://github.com/ipython/ipython/issues/10636
1117 self.shell.compile(ast_setup, "<magic-timeit-setup>", "exec")
1117 self.shell.compile(ast_setup, "<magic-timeit-setup>", "exec")
1118 self.shell.compile(ast_stmt, "<magic-timeit-stmt>", "exec")
1118 self.shell.compile(ast_stmt, "<magic-timeit-stmt>", "exec")
1119
1119
1120 # This codestring is taken from timeit.template - we fill it in as an
1120 # This codestring is taken from timeit.template - we fill it in as an
1121 # AST, so that we can apply our AST transformations to the user code
1121 # AST, so that we can apply our AST transformations to the user code
1122 # without affecting the timing code.
1122 # without affecting the timing code.
1123 timeit_ast_template = ast.parse('def inner(_it, _timer):\n'
1123 timeit_ast_template = ast.parse('def inner(_it, _timer):\n'
1124 ' setup\n'
1124 ' setup\n'
1125 ' _t0 = _timer()\n'
1125 ' _t0 = _timer()\n'
1126 ' for _i in _it:\n'
1126 ' for _i in _it:\n'
1127 ' stmt\n'
1127 ' stmt\n'
1128 ' _t1 = _timer()\n'
1128 ' _t1 = _timer()\n'
1129 ' return _t1 - _t0\n')
1129 ' return _t1 - _t0\n')
1130
1130
1131 timeit_ast = TimeitTemplateFiller(ast_setup, ast_stmt).visit(timeit_ast_template)
1131 timeit_ast = TimeitTemplateFiller(ast_setup, ast_stmt).visit(timeit_ast_template)
1132 timeit_ast = ast.fix_missing_locations(timeit_ast)
1132 timeit_ast = ast.fix_missing_locations(timeit_ast)
1133
1133
1134 # Track compilation time so it can be reported if too long
1134 # Track compilation time so it can be reported if too long
1135 # Minimum time above which compilation time will be reported
1135 # Minimum time above which compilation time will be reported
1136 tc_min = 0.1
1136 tc_min = 0.1
1137
1137
1138 t0 = clock()
1138 t0 = clock()
1139 code = self.shell.compile(timeit_ast, "<magic-timeit>", "exec")
1139 code = self.shell.compile(timeit_ast, "<magic-timeit>", "exec")
1140 tc = clock()-t0
1140 tc = clock()-t0
1141
1141
1142 ns = {}
1142 ns = {}
1143 glob = self.shell.user_ns
1143 glob = self.shell.user_ns
1144 # handles global vars with same name as local vars. We store them in conflict_globs.
1144 # handles global vars with same name as local vars. We store them in conflict_globs.
1145 conflict_globs = {}
1145 conflict_globs = {}
1146 if local_ns and cell is None:
1146 if local_ns and cell is None:
1147 for var_name, var_val in glob.items():
1147 for var_name, var_val in glob.items():
1148 if var_name in local_ns:
1148 if var_name in local_ns:
1149 conflict_globs[var_name] = var_val
1149 conflict_globs[var_name] = var_val
1150 glob.update(local_ns)
1150 glob.update(local_ns)
1151
1151
1152 exec(code, glob, ns)
1152 exec(code, glob, ns)
1153 timer.inner = ns["inner"]
1153 timer.inner = ns["inner"]
1154
1154
1155 # This is used to check if there is a huge difference between the
1155 # This is used to check if there is a huge difference between the
1156 # best and worst timings.
1156 # best and worst timings.
1157 # Issue: https://github.com/ipython/ipython/issues/6471
1157 # Issue: https://github.com/ipython/ipython/issues/6471
1158 if number == 0:
1158 if number == 0:
1159 # determine number so that 0.2 <= total time < 2.0
1159 # determine number so that 0.2 <= total time < 2.0
1160 for index in range(0, 10):
1160 for index in range(0, 10):
1161 number = 10 ** index
1161 number = 10 ** index
1162 time_number = timer.timeit(number)
1162 time_number = timer.timeit(number)
1163 if time_number >= 0.2:
1163 if time_number >= 0.2:
1164 break
1164 break
1165
1165
1166 all_runs = timer.repeat(repeat, number)
1166 all_runs = timer.repeat(repeat, number)
1167 best = min(all_runs) / number
1167 best = min(all_runs) / number
1168 worst = max(all_runs) / number
1168 worst = max(all_runs) / number
1169 timeit_result = TimeitResult(number, repeat, best, worst, all_runs, tc, precision)
1169 timeit_result = TimeitResult(number, repeat, best, worst, all_runs, tc, precision)
1170
1170
1171 # Restore global vars from conflict_globs
1171 # Restore global vars from conflict_globs
1172 if conflict_globs:
1172 if conflict_globs:
1173 glob.update(conflict_globs)
1173 glob.update(conflict_globs)
1174
1174
1175 if not quiet :
1175 if not quiet :
1176 # Check best timing is greater than zero to avoid a
1176 # Check best timing is greater than zero to avoid a
1177 # ZeroDivisionError.
1177 # ZeroDivisionError.
1178 # In cases where the slowest timing is lesser than a microsecond
1178 # In cases where the slowest timing is lesser than a microsecond
1179 # we assume that it does not really matter if the fastest
1179 # we assume that it does not really matter if the fastest
1180 # timing is 4 times faster than the slowest timing or not.
1180 # timing is 4 times faster than the slowest timing or not.
1181 if worst > 4 * best and best > 0 and worst > 1e-6:
1181 if worst > 4 * best and best > 0 and worst > 1e-6:
1182 print("The slowest run took %0.2f times longer than the "
1182 print("The slowest run took %0.2f times longer than the "
1183 "fastest. This could mean that an intermediate result "
1183 "fastest. This could mean that an intermediate result "
1184 "is being cached." % (worst / best))
1184 "is being cached." % (worst / best))
1185
1185
1186 print( timeit_result )
1186 print( timeit_result )
1187
1187
1188 if tc > tc_min:
1188 if tc > tc_min:
1189 print("Compiler time: %.2f s" % tc)
1189 print("Compiler time: %.2f s" % tc)
1190 if return_result:
1190 if return_result:
1191 return timeit_result
1191 return timeit_result
1192
1192
1193 @skip_doctest
1193 @skip_doctest
1194 @no_var_expand
1194 @no_var_expand
1195 @needs_local_scope
1195 @needs_local_scope
1196 @line_cell_magic
1196 @line_cell_magic
1197 def time(self,line='', cell=None, local_ns=None):
1197 def time(self,line='', cell=None, local_ns=None):
1198 """Time execution of a Python statement or expression.
1198 """Time execution of a Python statement or expression.
1199
1199
1200 The CPU and wall clock times are printed, and the value of the
1200 The CPU and wall clock times are printed, and the value of the
1201 expression (if any) is returned. Note that under Win32, system time
1201 expression (if any) is returned. Note that under Win32, system time
1202 is always reported as 0, since it can not be measured.
1202 is always reported as 0, since it can not be measured.
1203
1203
1204 This function can be used both as a line and cell magic:
1204 This function can be used both as a line and cell magic:
1205
1205
1206 - In line mode you can time a single-line statement (though multiple
1206 - In line mode you can time a single-line statement (though multiple
1207 ones can be chained with using semicolons).
1207 ones can be chained with using semicolons).
1208
1208
1209 - In cell mode, you can time the cell body (a directly
1209 - In cell mode, you can time the cell body (a directly
1210 following statement raises an error).
1210 following statement raises an error).
1211
1211
1212 This function provides very basic timing functionality. Use the timeit
1212 This function provides very basic timing functionality. Use the timeit
1213 magic for more control over the measurement.
1213 magic for more control over the measurement.
1214
1214
1215 .. versionchanged:: 7.3
1215 .. versionchanged:: 7.3
1216 User variables are no longer expanded,
1216 User variables are no longer expanded,
1217 the magic line is always left unmodified.
1217 the magic line is always left unmodified.
1218
1218
1219 Examples
1219 Examples
1220 --------
1220 --------
1221 ::
1221 ::
1222
1222
1223 In [1]: %time 2**128
1223 In [1]: %time 2**128
1224 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1224 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1225 Wall time: 0.00
1225 Wall time: 0.00
1226 Out[1]: 340282366920938463463374607431768211456L
1226 Out[1]: 340282366920938463463374607431768211456L
1227
1227
1228 In [2]: n = 1000000
1228 In [2]: n = 1000000
1229
1229
1230 In [3]: %time sum(range(n))
1230 In [3]: %time sum(range(n))
1231 CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
1231 CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
1232 Wall time: 1.37
1232 Wall time: 1.37
1233 Out[3]: 499999500000L
1233 Out[3]: 499999500000L
1234
1234
1235 In [4]: %time print 'hello world'
1235 In [4]: %time print 'hello world'
1236 hello world
1236 hello world
1237 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1237 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1238 Wall time: 0.00
1238 Wall time: 0.00
1239
1239
1240 .. note::
1240 .. note::
1241 The time needed by Python to compile the given expression will be
1241 The time needed by Python to compile the given expression will be
1242 reported if it is more than 0.1s.
1242 reported if it is more than 0.1s.
1243
1243
1244 In the example below, the actual exponentiation is done by Python
1244 In the example below, the actual exponentiation is done by Python
1245 at compilation time, so while the expression can take a noticeable
1245 at compilation time, so while the expression can take a noticeable
1246 amount of time to compute, that time is purely due to the
1246 amount of time to compute, that time is purely due to the
1247 compilation::
1247 compilation::
1248
1248
1249 In [5]: %time 3**9999;
1249 In [5]: %time 3**9999;
1250 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1250 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1251 Wall time: 0.00 s
1251 Wall time: 0.00 s
1252
1252
1253 In [6]: %time 3**999999;
1253 In [6]: %time 3**999999;
1254 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1254 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1255 Wall time: 0.00 s
1255 Wall time: 0.00 s
1256 Compiler : 0.78 s
1256 Compiler : 0.78 s
1257 """
1257 """
1258 # fail immediately if the given expression can't be compiled
1258 # fail immediately if the given expression can't be compiled
1259
1259
1260 if line and cell:
1260 if line and cell:
1261 raise UsageError("Can't use statement directly after '%%time'!")
1261 raise UsageError("Can't use statement directly after '%%time'!")
1262
1262
1263 if cell:
1263 if cell:
1264 expr = self.shell.transform_cell(cell)
1264 expr = self.shell.transform_cell(cell)
1265 else:
1265 else:
1266 expr = self.shell.transform_cell(line)
1266 expr = self.shell.transform_cell(line)
1267
1267
1268 # Minimum time above which parse time will be reported
1268 # Minimum time above which parse time will be reported
1269 tp_min = 0.1
1269 tp_min = 0.1
1270
1270
1271 t0 = clock()
1271 t0 = clock()
1272 expr_ast = self.shell.compile.ast_parse(expr)
1272 expr_ast = self.shell.compile.ast_parse(expr)
1273 tp = clock()-t0
1273 tp = clock()-t0
1274
1274
1275 # Apply AST transformations
1275 # Apply AST transformations
1276 expr_ast = self.shell.transform_ast(expr_ast)
1276 expr_ast = self.shell.transform_ast(expr_ast)
1277
1277
1278 # Minimum time above which compilation time will be reported
1278 # Minimum time above which compilation time will be reported
1279 tc_min = 0.1
1279 tc_min = 0.1
1280
1280
1281 expr_val=None
1281 expr_val=None
1282 if len(expr_ast.body)==1 and isinstance(expr_ast.body[0], ast.Expr):
1282 if len(expr_ast.body)==1 and isinstance(expr_ast.body[0], ast.Expr):
1283 mode = 'eval'
1283 mode = 'eval'
1284 source = '<timed eval>'
1284 source = '<timed eval>'
1285 expr_ast = ast.Expression(expr_ast.body[0].value)
1285 expr_ast = ast.Expression(expr_ast.body[0].value)
1286 else:
1286 else:
1287 mode = 'exec'
1287 mode = 'exec'
1288 source = '<timed exec>'
1288 source = '<timed exec>'
1289 # multi-line %%time case
1289 # multi-line %%time case
1290 if len(expr_ast.body) > 1 and isinstance(expr_ast.body[-1], ast.Expr):
1290 if len(expr_ast.body) > 1 and isinstance(expr_ast.body[-1], ast.Expr):
1291 expr_val= expr_ast.body[-1]
1291 expr_val= expr_ast.body[-1]
1292 expr_ast = expr_ast.body[:-1]
1292 expr_ast = expr_ast.body[:-1]
1293 expr_ast = Module(expr_ast, [])
1293 expr_ast = Module(expr_ast, [])
1294 expr_val = ast.Expression(expr_val.value)
1294 expr_val = ast.Expression(expr_val.value)
1295
1295
1296 t0 = clock()
1296 t0 = clock()
1297 code = self.shell.compile(expr_ast, source, mode)
1297 code = self.shell.compile(expr_ast, source, mode)
1298 tc = clock()-t0
1298 tc = clock()-t0
1299
1299
1300 # skew measurement as little as possible
1300 # skew measurement as little as possible
1301 glob = self.shell.user_ns
1301 glob = self.shell.user_ns
1302 wtime = time.time
1302 wtime = time.time
1303 # time execution
1303 # time execution
1304 wall_st = wtime()
1304 wall_st = wtime()
1305 if mode=='eval':
1305 if mode=='eval':
1306 st = clock2()
1306 st = clock2()
1307 try:
1307 try:
1308 out = eval(code, glob, local_ns)
1308 out = eval(code, glob, local_ns)
1309 except:
1309 except:
1310 self.shell.showtraceback()
1310 self.shell.showtraceback()
1311 return
1311 return
1312 end = clock2()
1312 end = clock2()
1313 else:
1313 else:
1314 st = clock2()
1314 st = clock2()
1315 try:
1315 try:
1316 exec(code, glob, local_ns)
1316 exec(code, glob, local_ns)
1317 out=None
1317 out=None
1318 # multi-line %%time case
1318 # multi-line %%time case
1319 if expr_val is not None:
1319 if expr_val is not None:
1320 code_2 = self.shell.compile(expr_val, source, 'eval')
1320 code_2 = self.shell.compile(expr_val, source, 'eval')
1321 out = eval(code_2, glob, local_ns)
1321 out = eval(code_2, glob, local_ns)
1322 except:
1322 except:
1323 self.shell.showtraceback()
1323 self.shell.showtraceback()
1324 return
1324 return
1325 end = clock2()
1325 end = clock2()
1326
1326
1327 wall_end = wtime()
1327 wall_end = wtime()
1328 # Compute actual times and report
1328 # Compute actual times and report
1329 wall_time = wall_end - wall_st
1329 wall_time = wall_end - wall_st
1330 cpu_user = end[0] - st[0]
1330 cpu_user = end[0] - st[0]
1331 cpu_sys = end[1] - st[1]
1331 cpu_sys = end[1] - st[1]
1332 cpu_tot = cpu_user + cpu_sys
1332 cpu_tot = cpu_user + cpu_sys
1333 # On windows cpu_sys is always zero, so only total is displayed
1333 # On windows cpu_sys is always zero, so only total is displayed
1334 if sys.platform != "win32":
1334 if sys.platform != "win32":
1335 print(
1335 print(
1336 f"CPU times: user {_format_time(cpu_user)}, sys: {_format_time(cpu_sys)}, total: {_format_time(cpu_tot)}"
1336 f"CPU times: user {_format_time(cpu_user)}, sys: {_format_time(cpu_sys)}, total: {_format_time(cpu_tot)}"
1337 )
1337 )
1338 else:
1338 else:
1339 print(f"CPU times: total: {_format_time(cpu_tot)}")
1339 print(f"CPU times: total: {_format_time(cpu_tot)}")
1340 print(f"Wall time: {_format_time(wall_time)}")
1340 print(f"Wall time: {_format_time(wall_time)}")
1341 if tc > tc_min:
1341 if tc > tc_min:
1342 print(f"Compiler : {_format_time(tc)}")
1342 print(f"Compiler : {_format_time(tc)}")
1343 if tp > tp_min:
1343 if tp > tp_min:
1344 print(f"Parser : {_format_time(tp)}")
1344 print(f"Parser : {_format_time(tp)}")
1345 return out
1345 return out
1346
1346
1347 @skip_doctest
1347 @skip_doctest
1348 @line_magic
1348 @line_magic
1349 def macro(self, parameter_s=''):
1349 def macro(self, parameter_s=''):
1350 """Define a macro for future re-execution. It accepts ranges of history,
1350 """Define a macro for future re-execution. It accepts ranges of history,
1351 filenames or string objects.
1351 filenames or string objects.
1352
1352
1353 Usage:\\
1353 Usage:\\
1354 %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
1354 %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
1355
1355
1356 Options:
1356 Options:
1357
1357
1358 -r: use 'raw' input. By default, the 'processed' history is used,
1358 -r: use 'raw' input. By default, the 'processed' history is used,
1359 so that magics are loaded in their transformed version to valid
1359 so that magics are loaded in their transformed version to valid
1360 Python. If this option is given, the raw input as typed at the
1360 Python. If this option is given, the raw input as typed at the
1361 command line is used instead.
1361 command line is used instead.
1362
1362
1363 -q: quiet macro definition. By default, a tag line is printed
1363 -q: quiet macro definition. By default, a tag line is printed
1364 to indicate the macro has been created, and then the contents of
1364 to indicate the macro has been created, and then the contents of
1365 the macro are printed. If this option is given, then no printout
1365 the macro are printed. If this option is given, then no printout
1366 is produced once the macro is created.
1366 is produced once the macro is created.
1367
1367
1368 This will define a global variable called `name` which is a string
1368 This will define a global variable called `name` which is a string
1369 made of joining the slices and lines you specify (n1,n2,... numbers
1369 made of joining the slices and lines you specify (n1,n2,... numbers
1370 above) from your input history into a single string. This variable
1370 above) from your input history into a single string. This variable
1371 acts like an automatic function which re-executes those lines as if
1371 acts like an automatic function which re-executes those lines as if
1372 you had typed them. You just type 'name' at the prompt and the code
1372 you had typed them. You just type 'name' at the prompt and the code
1373 executes.
1373 executes.
1374
1374
1375 The syntax for indicating input ranges is described in %history.
1375 The syntax for indicating input ranges is described in %history.
1376
1376
1377 Note: as a 'hidden' feature, you can also use traditional python slice
1377 Note: as a 'hidden' feature, you can also use traditional python slice
1378 notation, where N:M means numbers N through M-1.
1378 notation, where N:M means numbers N through M-1.
1379
1379
1380 For example, if your history contains (print using %hist -n )::
1380 For example, if your history contains (print using %hist -n )::
1381
1381
1382 44: x=1
1382 44: x=1
1383 45: y=3
1383 45: y=3
1384 46: z=x+y
1384 46: z=x+y
1385 47: print x
1385 47: print x
1386 48: a=5
1386 48: a=5
1387 49: print 'x',x,'y',y
1387 49: print 'x',x,'y',y
1388
1388
1389 you can create a macro with lines 44 through 47 (included) and line 49
1389 you can create a macro with lines 44 through 47 (included) and line 49
1390 called my_macro with::
1390 called my_macro with::
1391
1391
1392 In [55]: %macro my_macro 44-47 49
1392 In [55]: %macro my_macro 44-47 49
1393
1393
1394 Now, typing `my_macro` (without quotes) will re-execute all this code
1394 Now, typing `my_macro` (without quotes) will re-execute all this code
1395 in one pass.
1395 in one pass.
1396
1396
1397 You don't need to give the line-numbers in order, and any given line
1397 You don't need to give the line-numbers in order, and any given line
1398 number can appear multiple times. You can assemble macros with any
1398 number can appear multiple times. You can assemble macros with any
1399 lines from your input history in any order.
1399 lines from your input history in any order.
1400
1400
1401 The macro is a simple object which holds its value in an attribute,
1401 The macro is a simple object which holds its value in an attribute,
1402 but IPython's display system checks for macros and executes them as
1402 but IPython's display system checks for macros and executes them as
1403 code instead of printing them when you type their name.
1403 code instead of printing them when you type their name.
1404
1404
1405 You can view a macro's contents by explicitly printing it with::
1405 You can view a macro's contents by explicitly printing it with::
1406
1406
1407 print macro_name
1407 print macro_name
1408
1408
1409 """
1409 """
1410 opts,args = self.parse_options(parameter_s,'rq',mode='list')
1410 opts,args = self.parse_options(parameter_s,'rq',mode='list')
1411 if not args: # List existing macros
1411 if not args: # List existing macros
1412 return sorted(k for k,v in self.shell.user_ns.items() if isinstance(v, Macro))
1412 return sorted(k for k,v in self.shell.user_ns.items() if isinstance(v, Macro))
1413 if len(args) == 1:
1413 if len(args) == 1:
1414 raise UsageError(
1414 raise UsageError(
1415 "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
1415 "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
1416 name, codefrom = args[0], " ".join(args[1:])
1416 name, codefrom = args[0], " ".join(args[1:])
1417
1417
1418 #print 'rng',ranges # dbg
1418 #print 'rng',ranges # dbg
1419 try:
1419 try:
1420 lines = self.shell.find_user_code(codefrom, 'r' in opts)
1420 lines = self.shell.find_user_code(codefrom, 'r' in opts)
1421 except (ValueError, TypeError) as e:
1421 except (ValueError, TypeError) as e:
1422 print(e.args[0])
1422 print(e.args[0])
1423 return
1423 return
1424 macro = Macro(lines)
1424 macro = Macro(lines)
1425 self.shell.define_macro(name, macro)
1425 self.shell.define_macro(name, macro)
1426 if not ( 'q' in opts) :
1426 if not ( 'q' in opts) :
1427 print('Macro `%s` created. To execute, type its name (without quotes).' % name)
1427 print('Macro `%s` created. To execute, type its name (without quotes).' % name)
1428 print('=== Macro contents: ===')
1428 print('=== Macro contents: ===')
1429 print(macro, end=' ')
1429 print(macro, end=' ')
1430
1430
1431 @magic_arguments.magic_arguments()
1431 @magic_arguments.magic_arguments()
1432 @magic_arguments.argument('output', type=str, default='', nargs='?',
1432 @magic_arguments.argument('output', type=str, default='', nargs='?',
1433 help="""The name of the variable in which to store output.
1433 help="""The name of the variable in which to store output.
1434 This is a utils.io.CapturedIO object with stdout/err attributes
1434 This is a utils.io.CapturedIO object with stdout/err attributes
1435 for the text of the captured output.
1435 for the text of the captured output.
1436
1436
1437 CapturedOutput also has a show() method for displaying the output,
1437 CapturedOutput also has a show() method for displaying the output,
1438 and __call__ as well, so you can use that to quickly display the
1438 and __call__ as well, so you can use that to quickly display the
1439 output.
1439 output.
1440
1440
1441 If unspecified, captured output is discarded.
1441 If unspecified, captured output is discarded.
1442 """
1442 """
1443 )
1443 )
1444 @magic_arguments.argument('--no-stderr', action="store_true",
1444 @magic_arguments.argument('--no-stderr', action="store_true",
1445 help="""Don't capture stderr."""
1445 help="""Don't capture stderr."""
1446 )
1446 )
1447 @magic_arguments.argument('--no-stdout', action="store_true",
1447 @magic_arguments.argument('--no-stdout', action="store_true",
1448 help="""Don't capture stdout."""
1448 help="""Don't capture stdout."""
1449 )
1449 )
1450 @magic_arguments.argument('--no-display', action="store_true",
1450 @magic_arguments.argument('--no-display', action="store_true",
1451 help="""Don't capture IPython's rich display."""
1451 help="""Don't capture IPython's rich display."""
1452 )
1452 )
1453 @cell_magic
1453 @cell_magic
1454 def capture(self, line, cell):
1454 def capture(self, line, cell):
1455 """run the cell, capturing stdout, stderr, and IPython's rich display() calls."""
1455 """run the cell, capturing stdout, stderr, and IPython's rich display() calls."""
1456 args = magic_arguments.parse_argstring(self.capture, line)
1456 args = magic_arguments.parse_argstring(self.capture, line)
1457 out = not args.no_stdout
1457 out = not args.no_stdout
1458 err = not args.no_stderr
1458 err = not args.no_stderr
1459 disp = not args.no_display
1459 disp = not args.no_display
1460 with capture_output(out, err, disp) as io:
1460 with capture_output(out, err, disp) as io:
1461 self.shell.run_cell(cell)
1461 self.shell.run_cell(cell)
1462 if args.output:
1462 if args.output:
1463 self.shell.user_ns[args.output] = io
1463 self.shell.user_ns[args.output] = io
1464
1464
1465 def parse_breakpoint(text, current_file):
1465 def parse_breakpoint(text, current_file):
1466 '''Returns (file, line) for file:line and (current_file, line) for line'''
1466 '''Returns (file, line) for file:line and (current_file, line) for line'''
1467 colon = text.find(':')
1467 colon = text.find(':')
1468 if colon == -1:
1468 if colon == -1:
1469 return current_file, int(text)
1469 return current_file, int(text)
1470 else:
1470 else:
1471 return text[:colon], int(text[colon+1:])
1471 return text[:colon], int(text[colon+1:])
1472
1472
1473 def _format_time(timespan, precision=3):
1473 def _format_time(timespan, precision=3):
1474 """Formats the timespan in a human readable form"""
1474 """Formats the timespan in a human readable form"""
1475
1475
1476 if timespan >= 60.0:
1476 if timespan >= 60.0:
1477 # we have more than a minute, format that in a human readable form
1477 # we have more than a minute, format that in a human readable form
1478 # Idea from http://snipplr.com/view/5713/
1478 # Idea from http://snipplr.com/view/5713/
1479 parts = [("d", 60*60*24),("h", 60*60),("min", 60), ("s", 1)]
1479 parts = [("d", 60*60*24),("h", 60*60),("min", 60), ("s", 1)]
1480 time = []
1480 time = []
1481 leftover = timespan
1481 leftover = timespan
1482 for suffix, length in parts:
1482 for suffix, length in parts:
1483 value = int(leftover / length)
1483 value = int(leftover / length)
1484 if value > 0:
1484 if value > 0:
1485 leftover = leftover % length
1485 leftover = leftover % length
1486 time.append(u'%s%s' % (str(value), suffix))
1486 time.append(u'%s%s' % (str(value), suffix))
1487 if leftover < 1:
1487 if leftover < 1:
1488 break
1488 break
1489 return " ".join(time)
1489 return " ".join(time)
1490
1490
1491
1491
1492 # Unfortunately the unicode 'micro' symbol can cause problems in
1492 # Unfortunately the unicode 'micro' symbol can cause problems in
1493 # certain terminals.
1493 # certain terminals.
1494 # See bug: https://bugs.launchpad.net/ipython/+bug/348466
1494 # See bug: https://bugs.launchpad.net/ipython/+bug/348466
1495 # Try to prevent crashes by being more secure than it needs to
1495 # Try to prevent crashes by being more secure than it needs to
1496 # E.g. eclipse is able to print a µ, but has no sys.stdout.encoding set.
1496 # E.g. eclipse is able to print a µ, but has no sys.stdout.encoding set.
1497 units = [u"s", u"ms",u'us',"ns"] # the save value
1497 units = [u"s", u"ms",u'us',"ns"] # the save value
1498 if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
1498 if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
1499 try:
1499 try:
1500 u'\xb5'.encode(sys.stdout.encoding)
1500 u'\xb5'.encode(sys.stdout.encoding)
1501 units = [u"s", u"ms",u'\xb5s',"ns"]
1501 units = [u"s", u"ms",u'\xb5s',"ns"]
1502 except:
1502 except:
1503 pass
1503 pass
1504 scaling = [1, 1e3, 1e6, 1e9]
1504 scaling = [1, 1e3, 1e6, 1e9]
1505
1505
1506 if timespan > 0.0:
1506 if timespan > 0.0:
1507 order = min(-int(math.floor(math.log10(timespan)) // 3), 3)
1507 order = min(-int(math.floor(math.log10(timespan)) // 3), 3)
1508 else:
1508 else:
1509 order = 3
1509 order = 3
1510 return u"%.*g %s" % (precision, timespan * scaling[order], units[order])
1510 return u"%.*g %s" % (precision, timespan * scaling[order], units[order])
@@ -1,112 +1,112 b''
1 """Implementation of packaging-related magic functions.
1 """Implementation of packaging-related magic functions.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2018 The IPython Development Team.
4 # Copyright (c) 2018 The IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 import re
11 import re
12 import shlex
12 import shlex
13 import sys
13 import sys
14 from pathlib import Path
14 from pathlib import Path
15
15
16 from IPython.core.magic import Magics, magics_class, line_magic
16 from IPython.core.magic import Magics, magics_class, line_magic
17
17
18
18
19 def _is_conda_environment():
19 def _is_conda_environment():
20 """Return True if the current Python executable is in a conda env"""
20 """Return True if the current Python executable is in a conda env"""
21 # TODO: does this need to change on windows?
21 # TODO: does this need to change on windows?
22 return Path(sys.prefix, "conda-meta", "history").exists()
22 return Path(sys.prefix, "conda-meta", "history").exists()
23
23
24
24
25 def _get_conda_executable():
25 def _get_conda_executable():
26 """Find the path to the conda executable"""
26 """Find the path to the conda executable"""
27 # Check if there is a conda executable in the same directory as the Python executable.
27 # Check if there is a conda executable in the same directory as the Python executable.
28 # This is the case within conda's root environment.
28 # This is the case within conda's root environment.
29 conda = Path(sys.executable).parent / "conda"
29 conda = Path(sys.executable).parent / "conda"
30 if conda.is_file():
30 if conda.is_file():
31 return str(conda)
31 return str(conda)
32
32
33 # Otherwise, attempt to extract the executable from conda history.
33 # Otherwise, attempt to extract the executable from conda history.
34 # This applies in any conda environment.
34 # This applies in any conda environment.
35 history = Path(sys.prefix, "conda-meta", "history").read_text(encoding='utf-8')
35 history = Path(sys.prefix, "conda-meta", "history").read_text(encoding="utf-8")
36 match = re.search(
36 match = re.search(
37 r"^#\s*cmd:\s*(?P<command>.*conda)\s[create|install]",
37 r"^#\s*cmd:\s*(?P<command>.*conda)\s[create|install]",
38 history,
38 history,
39 flags=re.MULTILINE,
39 flags=re.MULTILINE,
40 )
40 )
41 if match:
41 if match:
42 return match.groupdict()["command"]
42 return match.groupdict()["command"]
43
43
44 # Fallback: assume conda is available on the system path.
44 # Fallback: assume conda is available on the system path.
45 return "conda"
45 return "conda"
46
46
47
47
48 CONDA_COMMANDS_REQUIRING_PREFIX = {
48 CONDA_COMMANDS_REQUIRING_PREFIX = {
49 'install', 'list', 'remove', 'uninstall', 'update', 'upgrade',
49 'install', 'list', 'remove', 'uninstall', 'update', 'upgrade',
50 }
50 }
51 CONDA_COMMANDS_REQUIRING_YES = {
51 CONDA_COMMANDS_REQUIRING_YES = {
52 'install', 'remove', 'uninstall', 'update', 'upgrade',
52 'install', 'remove', 'uninstall', 'update', 'upgrade',
53 }
53 }
54 CONDA_ENV_FLAGS = {'-p', '--prefix', '-n', '--name'}
54 CONDA_ENV_FLAGS = {'-p', '--prefix', '-n', '--name'}
55 CONDA_YES_FLAGS = {'-y', '--y'}
55 CONDA_YES_FLAGS = {'-y', '--y'}
56
56
57
57
58 @magics_class
58 @magics_class
59 class PackagingMagics(Magics):
59 class PackagingMagics(Magics):
60 """Magics related to packaging & installation"""
60 """Magics related to packaging & installation"""
61
61
62 @line_magic
62 @line_magic
63 def pip(self, line):
63 def pip(self, line):
64 """Run the pip package manager within the current kernel.
64 """Run the pip package manager within the current kernel.
65
65
66 Usage:
66 Usage:
67 %pip install [pkgs]
67 %pip install [pkgs]
68 """
68 """
69 python = sys.executable
69 python = sys.executable
70 if sys.platform == "win32":
70 if sys.platform == "win32":
71 python = '"' + python + '"'
71 python = '"' + python + '"'
72 else:
72 else:
73 python = shlex.quote(python)
73 python = shlex.quote(python)
74
74
75 self.shell.system(" ".join([python, "-m", "pip", line]))
75 self.shell.system(" ".join([python, "-m", "pip", line]))
76
76
77 print("Note: you may need to restart the kernel to use updated packages.")
77 print("Note: you may need to restart the kernel to use updated packages.")
78
78
79 @line_magic
79 @line_magic
80 def conda(self, line):
80 def conda(self, line):
81 """Run the conda package manager within the current kernel.
81 """Run the conda package manager within the current kernel.
82
82
83 Usage:
83 Usage:
84 %conda install [pkgs]
84 %conda install [pkgs]
85 """
85 """
86 if not _is_conda_environment():
86 if not _is_conda_environment():
87 raise ValueError("The python kernel does not appear to be a conda environment. "
87 raise ValueError("The python kernel does not appear to be a conda environment. "
88 "Please use ``%pip install`` instead.")
88 "Please use ``%pip install`` instead.")
89
89
90 conda = _get_conda_executable()
90 conda = _get_conda_executable()
91 args = shlex.split(line)
91 args = shlex.split(line)
92 command = args[0] if len(args) > 0 else ""
92 command = args[0] if len(args) > 0 else ""
93 args = args[1:] if len(args) > 1 else [""]
93 args = args[1:] if len(args) > 1 else [""]
94
94
95 extra_args = []
95 extra_args = []
96
96
97 # When the subprocess does not allow us to respond "yes" during the installation,
97 # When the subprocess does not allow us to respond "yes" during the installation,
98 # we need to insert --yes in the argument list for some commands
98 # we need to insert --yes in the argument list for some commands
99 stdin_disabled = getattr(self.shell, 'kernel', None) is not None
99 stdin_disabled = getattr(self.shell, 'kernel', None) is not None
100 needs_yes = command in CONDA_COMMANDS_REQUIRING_YES
100 needs_yes = command in CONDA_COMMANDS_REQUIRING_YES
101 has_yes = set(args).intersection(CONDA_YES_FLAGS)
101 has_yes = set(args).intersection(CONDA_YES_FLAGS)
102 if stdin_disabled and needs_yes and not has_yes:
102 if stdin_disabled and needs_yes and not has_yes:
103 extra_args.append("--yes")
103 extra_args.append("--yes")
104
104
105 # Add --prefix to point conda installation to the current environment
105 # Add --prefix to point conda installation to the current environment
106 needs_prefix = command in CONDA_COMMANDS_REQUIRING_PREFIX
106 needs_prefix = command in CONDA_COMMANDS_REQUIRING_PREFIX
107 has_prefix = set(args).intersection(CONDA_ENV_FLAGS)
107 has_prefix = set(args).intersection(CONDA_ENV_FLAGS)
108 if needs_prefix and not has_prefix:
108 if needs_prefix and not has_prefix:
109 extra_args.extend(["--prefix", sys.prefix])
109 extra_args.extend(["--prefix", sys.prefix])
110
110
111 self.shell.system(' '.join([conda, command] + extra_args + args))
111 self.shell.system(' '.join([conda, command] + extra_args + args))
112 print("\nNote: you may need to restart the kernel to use updated packages.")
112 print("\nNote: you may need to restart the kernel to use updated packages.")
@@ -1,345 +1,348 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Paging capabilities for IPython.core
3 Paging capabilities for IPython.core
4
4
5 Notes
5 Notes
6 -----
6 -----
7
7
8 For now this uses IPython hooks, so it can't be in IPython.utils. If we can get
8 For now this uses IPython hooks, so it can't be in IPython.utils. If we can get
9 rid of that dependency, we could move it there.
9 rid of that dependency, we could move it there.
10 -----
10 -----
11 """
11 """
12
12
13 # Copyright (c) IPython Development Team.
13 # Copyright (c) IPython Development Team.
14 # Distributed under the terms of the Modified BSD License.
14 # Distributed under the terms of the Modified BSD License.
15
15
16
16
17 import os
17 import os
18 import io
18 import io
19 import re
19 import re
20 import sys
20 import sys
21 import tempfile
21 import tempfile
22 import subprocess
22 import subprocess
23
23
24 from io import UnsupportedOperation
24 from io import UnsupportedOperation
25 from pathlib import Path
25 from pathlib import Path
26
26
27 from IPython import get_ipython
27 from IPython import get_ipython
28 from IPython.display import display
28 from IPython.display import display
29 from IPython.core.error import TryNext
29 from IPython.core.error import TryNext
30 from IPython.utils.data import chop
30 from IPython.utils.data import chop
31 from IPython.utils.process import system
31 from IPython.utils.process import system
32 from IPython.utils.terminal import get_terminal_size
32 from IPython.utils.terminal import get_terminal_size
33 from IPython.utils import py3compat
33 from IPython.utils import py3compat
34
34
35
35
36 def display_page(strng, start=0, screen_lines=25):
36 def display_page(strng, start=0, screen_lines=25):
37 """Just display, no paging. screen_lines is ignored."""
37 """Just display, no paging. screen_lines is ignored."""
38 if isinstance(strng, dict):
38 if isinstance(strng, dict):
39 data = strng
39 data = strng
40 else:
40 else:
41 if start:
41 if start:
42 strng = u'\n'.join(strng.splitlines()[start:])
42 strng = u'\n'.join(strng.splitlines()[start:])
43 data = { 'text/plain': strng }
43 data = { 'text/plain': strng }
44 display(data, raw=True)
44 display(data, raw=True)
45
45
46
46
47 def as_hook(page_func):
47 def as_hook(page_func):
48 """Wrap a pager func to strip the `self` arg
48 """Wrap a pager func to strip the `self` arg
49
49
50 so it can be called as a hook.
50 so it can be called as a hook.
51 """
51 """
52 return lambda self, *args, **kwargs: page_func(*args, **kwargs)
52 return lambda self, *args, **kwargs: page_func(*args, **kwargs)
53
53
54
54
55 esc_re = re.compile(r"(\x1b[^m]+m)")
55 esc_re = re.compile(r"(\x1b[^m]+m)")
56
56
57 def page_dumb(strng, start=0, screen_lines=25):
57 def page_dumb(strng, start=0, screen_lines=25):
58 """Very dumb 'pager' in Python, for when nothing else works.
58 """Very dumb 'pager' in Python, for when nothing else works.
59
59
60 Only moves forward, same interface as page(), except for pager_cmd and
60 Only moves forward, same interface as page(), except for pager_cmd and
61 mode.
61 mode.
62 """
62 """
63 if isinstance(strng, dict):
63 if isinstance(strng, dict):
64 strng = strng.get('text/plain', '')
64 strng = strng.get('text/plain', '')
65 out_ln = strng.splitlines()[start:]
65 out_ln = strng.splitlines()[start:]
66 screens = chop(out_ln,screen_lines-1)
66 screens = chop(out_ln,screen_lines-1)
67 if len(screens) == 1:
67 if len(screens) == 1:
68 print(os.linesep.join(screens[0]))
68 print(os.linesep.join(screens[0]))
69 else:
69 else:
70 last_escape = ""
70 last_escape = ""
71 for scr in screens[0:-1]:
71 for scr in screens[0:-1]:
72 hunk = os.linesep.join(scr)
72 hunk = os.linesep.join(scr)
73 print(last_escape + hunk)
73 print(last_escape + hunk)
74 if not page_more():
74 if not page_more():
75 return
75 return
76 esc_list = esc_re.findall(hunk)
76 esc_list = esc_re.findall(hunk)
77 if len(esc_list) > 0:
77 if len(esc_list) > 0:
78 last_escape = esc_list[-1]
78 last_escape = esc_list[-1]
79 print(last_escape + os.linesep.join(screens[-1]))
79 print(last_escape + os.linesep.join(screens[-1]))
80
80
81 def _detect_screen_size(screen_lines_def):
81 def _detect_screen_size(screen_lines_def):
82 """Attempt to work out the number of lines on the screen.
82 """Attempt to work out the number of lines on the screen.
83
83
84 This is called by page(). It can raise an error (e.g. when run in the
84 This is called by page(). It can raise an error (e.g. when run in the
85 test suite), so it's separated out so it can easily be called in a try block.
85 test suite), so it's separated out so it can easily be called in a try block.
86 """
86 """
87 TERM = os.environ.get('TERM',None)
87 TERM = os.environ.get('TERM',None)
88 if not((TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5'):
88 if not((TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5'):
89 # curses causes problems on many terminals other than xterm, and
89 # curses causes problems on many terminals other than xterm, and
90 # some termios calls lock up on Sun OS5.
90 # some termios calls lock up on Sun OS5.
91 return screen_lines_def
91 return screen_lines_def
92
92
93 try:
93 try:
94 import termios
94 import termios
95 import curses
95 import curses
96 except ImportError:
96 except ImportError:
97 return screen_lines_def
97 return screen_lines_def
98
98
99 # There is a bug in curses, where *sometimes* it fails to properly
99 # There is a bug in curses, where *sometimes* it fails to properly
100 # initialize, and then after the endwin() call is made, the
100 # initialize, and then after the endwin() call is made, the
101 # terminal is left in an unusable state. Rather than trying to
101 # terminal is left in an unusable state. Rather than trying to
102 # check every time for this (by requesting and comparing termios
102 # check every time for this (by requesting and comparing termios
103 # flags each time), we just save the initial terminal state and
103 # flags each time), we just save the initial terminal state and
104 # unconditionally reset it every time. It's cheaper than making
104 # unconditionally reset it every time. It's cheaper than making
105 # the checks.
105 # the checks.
106 try:
106 try:
107 term_flags = termios.tcgetattr(sys.stdout)
107 term_flags = termios.tcgetattr(sys.stdout)
108 except termios.error as err:
108 except termios.error as err:
109 # can fail on Linux 2.6, pager_page will catch the TypeError
109 # can fail on Linux 2.6, pager_page will catch the TypeError
110 raise TypeError('termios error: {0}'.format(err)) from err
110 raise TypeError('termios error: {0}'.format(err)) from err
111
111
112 try:
112 try:
113 scr = curses.initscr()
113 scr = curses.initscr()
114 except AttributeError:
114 except AttributeError:
115 # Curses on Solaris may not be complete, so we can't use it there
115 # Curses on Solaris may not be complete, so we can't use it there
116 return screen_lines_def
116 return screen_lines_def
117
117
118 screen_lines_real,screen_cols = scr.getmaxyx()
118 screen_lines_real,screen_cols = scr.getmaxyx()
119 curses.endwin()
119 curses.endwin()
120
120
121 # Restore terminal state in case endwin() didn't.
121 # Restore terminal state in case endwin() didn't.
122 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
122 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
123 # Now we have what we needed: the screen size in rows/columns
123 # Now we have what we needed: the screen size in rows/columns
124 return screen_lines_real
124 return screen_lines_real
125 #print '***Screen size:',screen_lines_real,'lines x',\
125 #print '***Screen size:',screen_lines_real,'lines x',\
126 #screen_cols,'columns.' # dbg
126 #screen_cols,'columns.' # dbg
127
127
128 def pager_page(strng, start=0, screen_lines=0, pager_cmd=None):
128 def pager_page(strng, start=0, screen_lines=0, pager_cmd=None):
129 """Display a string, piping through a pager after a certain length.
129 """Display a string, piping through a pager after a certain length.
130
130
131 strng can be a mime-bundle dict, supplying multiple representations,
131 strng can be a mime-bundle dict, supplying multiple representations,
132 keyed by mime-type.
132 keyed by mime-type.
133
133
134 The screen_lines parameter specifies the number of *usable* lines of your
134 The screen_lines parameter specifies the number of *usable* lines of your
135 terminal screen (total lines minus lines you need to reserve to show other
135 terminal screen (total lines minus lines you need to reserve to show other
136 information).
136 information).
137
137
138 If you set screen_lines to a number <=0, page() will try to auto-determine
138 If you set screen_lines to a number <=0, page() will try to auto-determine
139 your screen size and will only use up to (screen_size+screen_lines) for
139 your screen size and will only use up to (screen_size+screen_lines) for
140 printing, paging after that. That is, if you want auto-detection but need
140 printing, paging after that. That is, if you want auto-detection but need
141 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
141 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
142 auto-detection without any lines reserved simply use screen_lines = 0.
142 auto-detection without any lines reserved simply use screen_lines = 0.
143
143
144 If a string won't fit in the allowed lines, it is sent through the
144 If a string won't fit in the allowed lines, it is sent through the
145 specified pager command. If none given, look for PAGER in the environment,
145 specified pager command. If none given, look for PAGER in the environment,
146 and ultimately default to less.
146 and ultimately default to less.
147
147
148 If no system pager works, the string is sent through a 'dumb pager'
148 If no system pager works, the string is sent through a 'dumb pager'
149 written in python, very simplistic.
149 written in python, very simplistic.
150 """
150 """
151
151
152 # for compatibility with mime-bundle form:
152 # for compatibility with mime-bundle form:
153 if isinstance(strng, dict):
153 if isinstance(strng, dict):
154 strng = strng['text/plain']
154 strng = strng['text/plain']
155
155
156 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
156 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
157 TERM = os.environ.get('TERM','dumb')
157 TERM = os.environ.get('TERM','dumb')
158 if TERM in ['dumb','emacs'] and os.name != 'nt':
158 if TERM in ['dumb','emacs'] and os.name != 'nt':
159 print(strng)
159 print(strng)
160 return
160 return
161 # chop off the topmost part of the string we don't want to see
161 # chop off the topmost part of the string we don't want to see
162 str_lines = strng.splitlines()[start:]
162 str_lines = strng.splitlines()[start:]
163 str_toprint = os.linesep.join(str_lines)
163 str_toprint = os.linesep.join(str_lines)
164 num_newlines = len(str_lines)
164 num_newlines = len(str_lines)
165 len_str = len(str_toprint)
165 len_str = len(str_toprint)
166
166
167 # Dumb heuristics to guesstimate number of on-screen lines the string
167 # Dumb heuristics to guesstimate number of on-screen lines the string
168 # takes. Very basic, but good enough for docstrings in reasonable
168 # takes. Very basic, but good enough for docstrings in reasonable
169 # terminals. If someone later feels like refining it, it's not hard.
169 # terminals. If someone later feels like refining it, it's not hard.
170 numlines = max(num_newlines,int(len_str/80)+1)
170 numlines = max(num_newlines,int(len_str/80)+1)
171
171
172 screen_lines_def = get_terminal_size()[1]
172 screen_lines_def = get_terminal_size()[1]
173
173
174 # auto-determine screen size
174 # auto-determine screen size
175 if screen_lines <= 0:
175 if screen_lines <= 0:
176 try:
176 try:
177 screen_lines += _detect_screen_size(screen_lines_def)
177 screen_lines += _detect_screen_size(screen_lines_def)
178 except (TypeError, UnsupportedOperation):
178 except (TypeError, UnsupportedOperation):
179 print(str_toprint)
179 print(str_toprint)
180 return
180 return
181
181
182 #print 'numlines',numlines,'screenlines',screen_lines # dbg
182 #print 'numlines',numlines,'screenlines',screen_lines # dbg
183 if numlines <= screen_lines :
183 if numlines <= screen_lines :
184 #print '*** normal print' # dbg
184 #print '*** normal print' # dbg
185 print(str_toprint)
185 print(str_toprint)
186 else:
186 else:
187 # Try to open pager and default to internal one if that fails.
187 # Try to open pager and default to internal one if that fails.
188 # All failure modes are tagged as 'retval=1', to match the return
188 # All failure modes are tagged as 'retval=1', to match the return
189 # value of a failed system command. If any intermediate attempt
189 # value of a failed system command. If any intermediate attempt
190 # sets retval to 1, at the end we resort to our own page_dumb() pager.
190 # sets retval to 1, at the end we resort to our own page_dumb() pager.
191 pager_cmd = get_pager_cmd(pager_cmd)
191 pager_cmd = get_pager_cmd(pager_cmd)
192 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
192 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
193 if os.name == 'nt':
193 if os.name == 'nt':
194 if pager_cmd.startswith('type'):
194 if pager_cmd.startswith('type'):
195 # The default WinXP 'type' command is failing on complex strings.
195 # The default WinXP 'type' command is failing on complex strings.
196 retval = 1
196 retval = 1
197 else:
197 else:
198 fd, tmpname = tempfile.mkstemp('.txt')
198 fd, tmpname = tempfile.mkstemp('.txt')
199 tmppath = Path(tmpname)
199 tmppath = Path(tmpname)
200 try:
200 try:
201 os.close(fd)
201 os.close(fd)
202 with tmppath.open("wt", encoding='utf-8') as tmpfile:
202 with tmppath.open("wt", encoding="utf-8") as tmpfile:
203 tmpfile.write(strng)
203 tmpfile.write(strng)
204 cmd = "%s < %s" % (pager_cmd, tmppath)
204 cmd = "%s < %s" % (pager_cmd, tmppath)
205 # tmpfile needs to be closed for windows
205 # tmpfile needs to be closed for windows
206 if os.system(cmd):
206 if os.system(cmd):
207 retval = 1
207 retval = 1
208 else:
208 else:
209 retval = None
209 retval = None
210 finally:
210 finally:
211 Path.unlink(tmppath)
211 Path.unlink(tmppath)
212 else:
212 else:
213 try:
213 try:
214 retval = None
214 retval = None
215 # Emulate os.popen, but redirect stderr
215 # Emulate os.popen, but redirect stderr
216 proc = subprocess.Popen(pager_cmd,
216 proc = subprocess.Popen(
217 pager_cmd,
217 shell=True,
218 shell=True,
218 stdin=subprocess.PIPE,
219 stdin=subprocess.PIPE,
219 stderr=subprocess.DEVNULL
220 stderr=subprocess.DEVNULL,
221 )
222 pager = os._wrap_close(
223 io.TextIOWrapper(proc.stdin, encoding="utf-8"), proc
220 )
224 )
221 pager = os._wrap_close(io.TextIOWrapper(proc.stdin, encoding='utf-8'), proc)
222 try:
225 try:
223 pager_encoding = pager.encoding or sys.stdout.encoding
226 pager_encoding = pager.encoding or sys.stdout.encoding
224 pager.write(strng)
227 pager.write(strng)
225 finally:
228 finally:
226 retval = pager.close()
229 retval = pager.close()
227 except IOError as msg: # broken pipe when user quits
230 except IOError as msg: # broken pipe when user quits
228 if msg.args == (32, 'Broken pipe'):
231 if msg.args == (32, 'Broken pipe'):
229 retval = None
232 retval = None
230 else:
233 else:
231 retval = 1
234 retval = 1
232 except OSError:
235 except OSError:
233 # Other strange problems, sometimes seen in Win2k/cygwin
236 # Other strange problems, sometimes seen in Win2k/cygwin
234 retval = 1
237 retval = 1
235 if retval is not None:
238 if retval is not None:
236 page_dumb(strng,screen_lines=screen_lines)
239 page_dumb(strng,screen_lines=screen_lines)
237
240
238
241
239 def page(data, start=0, screen_lines=0, pager_cmd=None):
242 def page(data, start=0, screen_lines=0, pager_cmd=None):
240 """Display content in a pager, piping through a pager after a certain length.
243 """Display content in a pager, piping through a pager after a certain length.
241
244
242 data can be a mime-bundle dict, supplying multiple representations,
245 data can be a mime-bundle dict, supplying multiple representations,
243 keyed by mime-type, or text.
246 keyed by mime-type, or text.
244
247
245 Pager is dispatched via the `show_in_pager` IPython hook.
248 Pager is dispatched via the `show_in_pager` IPython hook.
246 If no hook is registered, `pager_page` will be used.
249 If no hook is registered, `pager_page` will be used.
247 """
250 """
248 # Some routines may auto-compute start offsets incorrectly and pass a
251 # Some routines may auto-compute start offsets incorrectly and pass a
249 # negative value. Offset to 0 for robustness.
252 # negative value. Offset to 0 for robustness.
250 start = max(0, start)
253 start = max(0, start)
251
254
252 # first, try the hook
255 # first, try the hook
253 ip = get_ipython()
256 ip = get_ipython()
254 if ip:
257 if ip:
255 try:
258 try:
256 ip.hooks.show_in_pager(data, start=start, screen_lines=screen_lines)
259 ip.hooks.show_in_pager(data, start=start, screen_lines=screen_lines)
257 return
260 return
258 except TryNext:
261 except TryNext:
259 pass
262 pass
260
263
261 # fallback on default pager
264 # fallback on default pager
262 return pager_page(data, start, screen_lines, pager_cmd)
265 return pager_page(data, start, screen_lines, pager_cmd)
263
266
264
267
265 def page_file(fname, start=0, pager_cmd=None):
268 def page_file(fname, start=0, pager_cmd=None):
266 """Page a file, using an optional pager command and starting line.
269 """Page a file, using an optional pager command and starting line.
267 """
270 """
268
271
269 pager_cmd = get_pager_cmd(pager_cmd)
272 pager_cmd = get_pager_cmd(pager_cmd)
270 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
273 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
271
274
272 try:
275 try:
273 if os.environ['TERM'] in ['emacs','dumb']:
276 if os.environ['TERM'] in ['emacs','dumb']:
274 raise EnvironmentError
277 raise EnvironmentError
275 system(pager_cmd + ' ' + fname)
278 system(pager_cmd + ' ' + fname)
276 except:
279 except:
277 try:
280 try:
278 if start > 0:
281 if start > 0:
279 start -= 1
282 start -= 1
280 page(open(fname, encoding='utf-8').read(),start)
283 page(open(fname, encoding="utf-8").read(), start)
281 except:
284 except:
282 print('Unable to show file',repr(fname))
285 print('Unable to show file',repr(fname))
283
286
284
287
285 def get_pager_cmd(pager_cmd=None):
288 def get_pager_cmd(pager_cmd=None):
286 """Return a pager command.
289 """Return a pager command.
287
290
288 Makes some attempts at finding an OS-correct one.
291 Makes some attempts at finding an OS-correct one.
289 """
292 """
290 if os.name == 'posix':
293 if os.name == 'posix':
291 default_pager_cmd = 'less -R' # -R for color control sequences
294 default_pager_cmd = 'less -R' # -R for color control sequences
292 elif os.name in ['nt','dos']:
295 elif os.name in ['nt','dos']:
293 default_pager_cmd = 'type'
296 default_pager_cmd = 'type'
294
297
295 if pager_cmd is None:
298 if pager_cmd is None:
296 try:
299 try:
297 pager_cmd = os.environ['PAGER']
300 pager_cmd = os.environ['PAGER']
298 except:
301 except:
299 pager_cmd = default_pager_cmd
302 pager_cmd = default_pager_cmd
300
303
301 if pager_cmd == 'less' and '-r' not in os.environ.get('LESS', '').lower():
304 if pager_cmd == 'less' and '-r' not in os.environ.get('LESS', '').lower():
302 pager_cmd += ' -R'
305 pager_cmd += ' -R'
303
306
304 return pager_cmd
307 return pager_cmd
305
308
306
309
307 def get_pager_start(pager, start):
310 def get_pager_start(pager, start):
308 """Return the string for paging files with an offset.
311 """Return the string for paging files with an offset.
309
312
310 This is the '+N' argument which less and more (under Unix) accept.
313 This is the '+N' argument which less and more (under Unix) accept.
311 """
314 """
312
315
313 if pager in ['less','more']:
316 if pager in ['less','more']:
314 if start:
317 if start:
315 start_string = '+' + str(start)
318 start_string = '+' + str(start)
316 else:
319 else:
317 start_string = ''
320 start_string = ''
318 else:
321 else:
319 start_string = ''
322 start_string = ''
320 return start_string
323 return start_string
321
324
322
325
323 # (X)emacs on win32 doesn't like to be bypassed with msvcrt.getch()
326 # (X)emacs on win32 doesn't like to be bypassed with msvcrt.getch()
324 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
327 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
325 import msvcrt
328 import msvcrt
326 def page_more():
329 def page_more():
327 """ Smart pausing between pages
330 """ Smart pausing between pages
328
331
329 @return: True if need print more lines, False if quit
332 @return: True if need print more lines, False if quit
330 """
333 """
331 sys.stdout.write('---Return to continue, q to quit--- ')
334 sys.stdout.write('---Return to continue, q to quit--- ')
332 ans = msvcrt.getwch()
335 ans = msvcrt.getwch()
333 if ans in ("q", "Q"):
336 if ans in ("q", "Q"):
334 result = False
337 result = False
335 else:
338 else:
336 result = True
339 result = True
337 sys.stdout.write("\b"*37 + " "*37 + "\b"*37)
340 sys.stdout.write("\b"*37 + " "*37 + "\b"*37)
338 return result
341 return result
339 else:
342 else:
340 def page_more():
343 def page_more():
341 ans = py3compat.input('---Return to continue, q to quit--- ')
344 ans = py3compat.input('---Return to continue, q to quit--- ')
342 if ans.lower().startswith('q'):
345 if ans.lower().startswith('q'):
343 return False
346 return False
344 else:
347 else:
345 return True
348 return True
@@ -1,70 +1,70 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Tests for IPython.core.application"""
2 """Tests for IPython.core.application"""
3
3
4 import os
4 import os
5 import tempfile
5 import tempfile
6
6
7 from traitlets import Unicode
7 from traitlets import Unicode
8
8
9 from IPython.core.application import BaseIPythonApplication
9 from IPython.core.application import BaseIPythonApplication
10 from IPython.testing import decorators as dec
10 from IPython.testing import decorators as dec
11 from IPython.utils.tempdir import TemporaryDirectory
11 from IPython.utils.tempdir import TemporaryDirectory
12
12
13
13
14 @dec.onlyif_unicode_paths
14 @dec.onlyif_unicode_paths
15 def test_unicode_cwd():
15 def test_unicode_cwd():
16 """Check that IPython starts with non-ascii characters in the path."""
16 """Check that IPython starts with non-ascii characters in the path."""
17 wd = tempfile.mkdtemp(suffix=u"€")
17 wd = tempfile.mkdtemp(suffix=u"€")
18
18
19 old_wd = os.getcwd()
19 old_wd = os.getcwd()
20 os.chdir(wd)
20 os.chdir(wd)
21 #raise Exception(repr(os.getcwd()))
21 #raise Exception(repr(os.getcwd()))
22 try:
22 try:
23 app = BaseIPythonApplication()
23 app = BaseIPythonApplication()
24 # The lines below are copied from Application.initialize()
24 # The lines below are copied from Application.initialize()
25 app.init_profile_dir()
25 app.init_profile_dir()
26 app.init_config_files()
26 app.init_config_files()
27 app.load_config_file(suppress_errors=False)
27 app.load_config_file(suppress_errors=False)
28 finally:
28 finally:
29 os.chdir(old_wd)
29 os.chdir(old_wd)
30
30
31 @dec.onlyif_unicode_paths
31 @dec.onlyif_unicode_paths
32 def test_unicode_ipdir():
32 def test_unicode_ipdir():
33 """Check that IPython starts with non-ascii characters in the IP dir."""
33 """Check that IPython starts with non-ascii characters in the IP dir."""
34 ipdir = tempfile.mkdtemp(suffix=u"€")
34 ipdir = tempfile.mkdtemp(suffix=u"€")
35
35
36 # Create the config file, so it tries to load it.
36 # Create the config file, so it tries to load it.
37 with open(os.path.join(ipdir, 'ipython_config.py'), "w", encoding='utf-8') as f:
37 with open(os.path.join(ipdir, "ipython_config.py"), "w", encoding="utf-8") as f:
38 pass
38 pass
39
39
40 old_ipdir1 = os.environ.pop("IPYTHONDIR", None)
40 old_ipdir1 = os.environ.pop("IPYTHONDIR", None)
41 old_ipdir2 = os.environ.pop("IPYTHON_DIR", None)
41 old_ipdir2 = os.environ.pop("IPYTHON_DIR", None)
42 os.environ["IPYTHONDIR"] = ipdir
42 os.environ["IPYTHONDIR"] = ipdir
43 try:
43 try:
44 app = BaseIPythonApplication()
44 app = BaseIPythonApplication()
45 # The lines below are copied from Application.initialize()
45 # The lines below are copied from Application.initialize()
46 app.init_profile_dir()
46 app.init_profile_dir()
47 app.init_config_files()
47 app.init_config_files()
48 app.load_config_file(suppress_errors=False)
48 app.load_config_file(suppress_errors=False)
49 finally:
49 finally:
50 if old_ipdir1:
50 if old_ipdir1:
51 os.environ["IPYTHONDIR"] = old_ipdir1
51 os.environ["IPYTHONDIR"] = old_ipdir1
52 if old_ipdir2:
52 if old_ipdir2:
53 os.environ["IPYTHONDIR"] = old_ipdir2
53 os.environ["IPYTHONDIR"] = old_ipdir2
54
54
55 def test_cli_priority():
55 def test_cli_priority():
56 with TemporaryDirectory() as td:
56 with TemporaryDirectory() as td:
57
57
58 class TestApp(BaseIPythonApplication):
58 class TestApp(BaseIPythonApplication):
59 test = Unicode().tag(config=True)
59 test = Unicode().tag(config=True)
60
60
61 # Create the config file, so it tries to load it.
61 # Create the config file, so it tries to load it.
62 with open(os.path.join(td, 'ipython_config.py'), "w", encoding='utf-8') as f:
62 with open(os.path.join(td, "ipython_config.py"), "w", encoding="utf-8") as f:
63 f.write("c.TestApp.test = 'config file'")
63 f.write("c.TestApp.test = 'config file'")
64
64
65 app = TestApp()
65 app = TestApp()
66 app.initialize(["--profile-dir", td])
66 app.initialize(["--profile-dir", td])
67 assert app.test == "config file"
67 assert app.test == "config file"
68 app = TestApp()
68 app = TestApp()
69 app.initialize(["--profile-dir", td, "--TestApp.test=cli"])
69 app.initialize(["--profile-dir", td, "--TestApp.test=cli"])
70 assert app.test == "cli"
70 assert app.test == "cli"
@@ -1,1264 +1,1264 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for the IPython tab-completion machinery."""
2 """Tests for the IPython tab-completion machinery."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import os
7 import os
8 import pytest
8 import pytest
9 import sys
9 import sys
10 import textwrap
10 import textwrap
11 import unittest
11 import unittest
12
12
13 from contextlib import contextmanager
13 from contextlib import contextmanager
14
14
15 from traitlets.config.loader import Config
15 from traitlets.config.loader import Config
16 from IPython import get_ipython
16 from IPython import get_ipython
17 from IPython.core import completer
17 from IPython.core import completer
18 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
18 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
19 from IPython.utils.generics import complete_object
19 from IPython.utils.generics import complete_object
20 from IPython.testing import decorators as dec
20 from IPython.testing import decorators as dec
21
21
22 from IPython.core.completer import (
22 from IPython.core.completer import (
23 Completion,
23 Completion,
24 provisionalcompleter,
24 provisionalcompleter,
25 match_dict_keys,
25 match_dict_keys,
26 _deduplicate_completions,
26 _deduplicate_completions,
27 )
27 )
28
28
29 # -----------------------------------------------------------------------------
29 # -----------------------------------------------------------------------------
30 # Test functions
30 # Test functions
31 # -----------------------------------------------------------------------------
31 # -----------------------------------------------------------------------------
32
32
33 def recompute_unicode_ranges():
33 def recompute_unicode_ranges():
34 """
34 """
35 utility to recompute the largest unicode range without any characters
35 utility to recompute the largest unicode range without any characters
36
36
37 use to recompute the gap in the global _UNICODE_RANGES of completer.py
37 use to recompute the gap in the global _UNICODE_RANGES of completer.py
38 """
38 """
39 import itertools
39 import itertools
40 import unicodedata
40 import unicodedata
41 valid = []
41 valid = []
42 for c in range(0,0x10FFFF + 1):
42 for c in range(0,0x10FFFF + 1):
43 try:
43 try:
44 unicodedata.name(chr(c))
44 unicodedata.name(chr(c))
45 except ValueError:
45 except ValueError:
46 continue
46 continue
47 valid.append(c)
47 valid.append(c)
48
48
49 def ranges(i):
49 def ranges(i):
50 for a, b in itertools.groupby(enumerate(i), lambda pair: pair[1] - pair[0]):
50 for a, b in itertools.groupby(enumerate(i), lambda pair: pair[1] - pair[0]):
51 b = list(b)
51 b = list(b)
52 yield b[0][1], b[-1][1]
52 yield b[0][1], b[-1][1]
53
53
54 rg = list(ranges(valid))
54 rg = list(ranges(valid))
55 lens = []
55 lens = []
56 gap_lens = []
56 gap_lens = []
57 pstart, pstop = 0,0
57 pstart, pstop = 0,0
58 for start, stop in rg:
58 for start, stop in rg:
59 lens.append(stop-start)
59 lens.append(stop-start)
60 gap_lens.append((start - pstop, hex(pstop), hex(start), f'{round((start - pstop)/0xe01f0*100)}%'))
60 gap_lens.append((start - pstop, hex(pstop), hex(start), f'{round((start - pstop)/0xe01f0*100)}%'))
61 pstart, pstop = start, stop
61 pstart, pstop = start, stop
62
62
63 return sorted(gap_lens)[-1]
63 return sorted(gap_lens)[-1]
64
64
65
65
66
66
67 def test_unicode_range():
67 def test_unicode_range():
68 """
68 """
69 Test that the ranges we test for unicode names give the same number of
69 Test that the ranges we test for unicode names give the same number of
70 results than testing the full length.
70 results than testing the full length.
71 """
71 """
72 from IPython.core.completer import _unicode_name_compute, _UNICODE_RANGES
72 from IPython.core.completer import _unicode_name_compute, _UNICODE_RANGES
73
73
74 expected_list = _unicode_name_compute([(0, 0x110000)])
74 expected_list = _unicode_name_compute([(0, 0x110000)])
75 test = _unicode_name_compute(_UNICODE_RANGES)
75 test = _unicode_name_compute(_UNICODE_RANGES)
76 len_exp = len(expected_list)
76 len_exp = len(expected_list)
77 len_test = len(test)
77 len_test = len(test)
78
78
79 # do not inline the len() or on error pytest will try to print the 130 000 +
79 # do not inline the len() or on error pytest will try to print the 130 000 +
80 # elements.
80 # elements.
81 message = None
81 message = None
82 if len_exp != len_test or len_exp > 131808:
82 if len_exp != len_test or len_exp > 131808:
83 size, start, stop, prct = recompute_unicode_ranges()
83 size, start, stop, prct = recompute_unicode_ranges()
84 message = f"""_UNICODE_RANGES likely wrong and need updating. This is
84 message = f"""_UNICODE_RANGES likely wrong and need updating. This is
85 likely due to a new release of Python. We've find that the biggest gap
85 likely due to a new release of Python. We've find that the biggest gap
86 in unicode characters has reduces in size to be {size} characters
86 in unicode characters has reduces in size to be {size} characters
87 ({prct}), from {start}, to {stop}. In completer.py likely update to
87 ({prct}), from {start}, to {stop}. In completer.py likely update to
88
88
89 _UNICODE_RANGES = [(32, {start}), ({stop}, 0xe01f0)]
89 _UNICODE_RANGES = [(32, {start}), ({stop}, 0xe01f0)]
90
90
91 And update the assertion below to use
91 And update the assertion below to use
92
92
93 len_exp <= {len_exp}
93 len_exp <= {len_exp}
94 """
94 """
95 assert len_exp == len_test, message
95 assert len_exp == len_test, message
96
96
97 # fail if new unicode symbols have been added.
97 # fail if new unicode symbols have been added.
98 assert len_exp <= 138552, message
98 assert len_exp <= 138552, message
99
99
100
100
101 @contextmanager
101 @contextmanager
102 def greedy_completion():
102 def greedy_completion():
103 ip = get_ipython()
103 ip = get_ipython()
104 greedy_original = ip.Completer.greedy
104 greedy_original = ip.Completer.greedy
105 try:
105 try:
106 ip.Completer.greedy = True
106 ip.Completer.greedy = True
107 yield
107 yield
108 finally:
108 finally:
109 ip.Completer.greedy = greedy_original
109 ip.Completer.greedy = greedy_original
110
110
111
111
112 def test_protect_filename():
112 def test_protect_filename():
113 if sys.platform == "win32":
113 if sys.platform == "win32":
114 pairs = [
114 pairs = [
115 ("abc", "abc"),
115 ("abc", "abc"),
116 (" abc", '" abc"'),
116 (" abc", '" abc"'),
117 ("a bc", '"a bc"'),
117 ("a bc", '"a bc"'),
118 ("a bc", '"a bc"'),
118 ("a bc", '"a bc"'),
119 (" bc", '" bc"'),
119 (" bc", '" bc"'),
120 ]
120 ]
121 else:
121 else:
122 pairs = [
122 pairs = [
123 ("abc", "abc"),
123 ("abc", "abc"),
124 (" abc", r"\ abc"),
124 (" abc", r"\ abc"),
125 ("a bc", r"a\ bc"),
125 ("a bc", r"a\ bc"),
126 ("a bc", r"a\ \ bc"),
126 ("a bc", r"a\ \ bc"),
127 (" bc", r"\ \ bc"),
127 (" bc", r"\ \ bc"),
128 # On posix, we also protect parens and other special characters.
128 # On posix, we also protect parens and other special characters.
129 ("a(bc", r"a\(bc"),
129 ("a(bc", r"a\(bc"),
130 ("a)bc", r"a\)bc"),
130 ("a)bc", r"a\)bc"),
131 ("a( )bc", r"a\(\ \)bc"),
131 ("a( )bc", r"a\(\ \)bc"),
132 ("a[1]bc", r"a\[1\]bc"),
132 ("a[1]bc", r"a\[1\]bc"),
133 ("a{1}bc", r"a\{1\}bc"),
133 ("a{1}bc", r"a\{1\}bc"),
134 ("a#bc", r"a\#bc"),
134 ("a#bc", r"a\#bc"),
135 ("a?bc", r"a\?bc"),
135 ("a?bc", r"a\?bc"),
136 ("a=bc", r"a\=bc"),
136 ("a=bc", r"a\=bc"),
137 ("a\\bc", r"a\\bc"),
137 ("a\\bc", r"a\\bc"),
138 ("a|bc", r"a\|bc"),
138 ("a|bc", r"a\|bc"),
139 ("a;bc", r"a\;bc"),
139 ("a;bc", r"a\;bc"),
140 ("a:bc", r"a\:bc"),
140 ("a:bc", r"a\:bc"),
141 ("a'bc", r"a\'bc"),
141 ("a'bc", r"a\'bc"),
142 ("a*bc", r"a\*bc"),
142 ("a*bc", r"a\*bc"),
143 ('a"bc', r"a\"bc"),
143 ('a"bc', r"a\"bc"),
144 ("a^bc", r"a\^bc"),
144 ("a^bc", r"a\^bc"),
145 ("a&bc", r"a\&bc"),
145 ("a&bc", r"a\&bc"),
146 ]
146 ]
147 # run the actual tests
147 # run the actual tests
148 for s1, s2 in pairs:
148 for s1, s2 in pairs:
149 s1p = completer.protect_filename(s1)
149 s1p = completer.protect_filename(s1)
150 assert s1p == s2
150 assert s1p == s2
151
151
152
152
153 def check_line_split(splitter, test_specs):
153 def check_line_split(splitter, test_specs):
154 for part1, part2, split in test_specs:
154 for part1, part2, split in test_specs:
155 cursor_pos = len(part1)
155 cursor_pos = len(part1)
156 line = part1 + part2
156 line = part1 + part2
157 out = splitter.split_line(line, cursor_pos)
157 out = splitter.split_line(line, cursor_pos)
158 assert out == split
158 assert out == split
159
159
160
160
161 def test_line_split():
161 def test_line_split():
162 """Basic line splitter test with default specs."""
162 """Basic line splitter test with default specs."""
163 sp = completer.CompletionSplitter()
163 sp = completer.CompletionSplitter()
164 # The format of the test specs is: part1, part2, expected answer. Parts 1
164 # The format of the test specs is: part1, part2, expected answer. Parts 1
165 # and 2 are joined into the 'line' sent to the splitter, as if the cursor
165 # and 2 are joined into the 'line' sent to the splitter, as if the cursor
166 # was at the end of part1. So an empty part2 represents someone hitting
166 # was at the end of part1. So an empty part2 represents someone hitting
167 # tab at the end of the line, the most common case.
167 # tab at the end of the line, the most common case.
168 t = [
168 t = [
169 ("run some/scrip", "", "some/scrip"),
169 ("run some/scrip", "", "some/scrip"),
170 ("run scripts/er", "ror.py foo", "scripts/er"),
170 ("run scripts/er", "ror.py foo", "scripts/er"),
171 ("echo $HOM", "", "HOM"),
171 ("echo $HOM", "", "HOM"),
172 ("print sys.pa", "", "sys.pa"),
172 ("print sys.pa", "", "sys.pa"),
173 ("print(sys.pa", "", "sys.pa"),
173 ("print(sys.pa", "", "sys.pa"),
174 ("execfile('scripts/er", "", "scripts/er"),
174 ("execfile('scripts/er", "", "scripts/er"),
175 ("a[x.", "", "x."),
175 ("a[x.", "", "x."),
176 ("a[x.", "y", "x."),
176 ("a[x.", "y", "x."),
177 ('cd "some_file/', "", "some_file/"),
177 ('cd "some_file/', "", "some_file/"),
178 ]
178 ]
179 check_line_split(sp, t)
179 check_line_split(sp, t)
180 # Ensure splitting works OK with unicode by re-running the tests with
180 # Ensure splitting works OK with unicode by re-running the tests with
181 # all inputs turned into unicode
181 # all inputs turned into unicode
182 check_line_split(sp, [map(str, p) for p in t])
182 check_line_split(sp, [map(str, p) for p in t])
183
183
184
184
185 class NamedInstanceClass:
185 class NamedInstanceClass:
186 instances = {}
186 instances = {}
187
187
188 def __init__(self, name):
188 def __init__(self, name):
189 self.instances[name] = self
189 self.instances[name] = self
190
190
191 @classmethod
191 @classmethod
192 def _ipython_key_completions_(cls):
192 def _ipython_key_completions_(cls):
193 return cls.instances.keys()
193 return cls.instances.keys()
194
194
195
195
196 class KeyCompletable:
196 class KeyCompletable:
197 def __init__(self, things=()):
197 def __init__(self, things=()):
198 self.things = things
198 self.things = things
199
199
200 def _ipython_key_completions_(self):
200 def _ipython_key_completions_(self):
201 return list(self.things)
201 return list(self.things)
202
202
203
203
204 class TestCompleter(unittest.TestCase):
204 class TestCompleter(unittest.TestCase):
205 def setUp(self):
205 def setUp(self):
206 """
206 """
207 We want to silence all PendingDeprecationWarning when testing the completer
207 We want to silence all PendingDeprecationWarning when testing the completer
208 """
208 """
209 self._assertwarns = self.assertWarns(PendingDeprecationWarning)
209 self._assertwarns = self.assertWarns(PendingDeprecationWarning)
210 self._assertwarns.__enter__()
210 self._assertwarns.__enter__()
211
211
212 def tearDown(self):
212 def tearDown(self):
213 try:
213 try:
214 self._assertwarns.__exit__(None, None, None)
214 self._assertwarns.__exit__(None, None, None)
215 except AssertionError:
215 except AssertionError:
216 pass
216 pass
217
217
218 def test_custom_completion_error(self):
218 def test_custom_completion_error(self):
219 """Test that errors from custom attribute completers are silenced."""
219 """Test that errors from custom attribute completers are silenced."""
220 ip = get_ipython()
220 ip = get_ipython()
221
221
222 class A:
222 class A:
223 pass
223 pass
224
224
225 ip.user_ns["x"] = A()
225 ip.user_ns["x"] = A()
226
226
227 @complete_object.register(A)
227 @complete_object.register(A)
228 def complete_A(a, existing_completions):
228 def complete_A(a, existing_completions):
229 raise TypeError("this should be silenced")
229 raise TypeError("this should be silenced")
230
230
231 ip.complete("x.")
231 ip.complete("x.")
232
232
233 def test_custom_completion_ordering(self):
233 def test_custom_completion_ordering(self):
234 """Test that errors from custom attribute completers are silenced."""
234 """Test that errors from custom attribute completers are silenced."""
235 ip = get_ipython()
235 ip = get_ipython()
236
236
237 _, matches = ip.complete('in')
237 _, matches = ip.complete('in')
238 assert matches.index('input') < matches.index('int')
238 assert matches.index('input') < matches.index('int')
239
239
240 def complete_example(a):
240 def complete_example(a):
241 return ['example2', 'example1']
241 return ['example2', 'example1']
242
242
243 ip.Completer.custom_completers.add_re('ex*', complete_example)
243 ip.Completer.custom_completers.add_re('ex*', complete_example)
244 _, matches = ip.complete('ex')
244 _, matches = ip.complete('ex')
245 assert matches.index('example2') < matches.index('example1')
245 assert matches.index('example2') < matches.index('example1')
246
246
247 def test_unicode_completions(self):
247 def test_unicode_completions(self):
248 ip = get_ipython()
248 ip = get_ipython()
249 # Some strings that trigger different types of completion. Check them both
249 # Some strings that trigger different types of completion. Check them both
250 # in str and unicode forms
250 # in str and unicode forms
251 s = ["ru", "%ru", "cd /", "floa", "float(x)/"]
251 s = ["ru", "%ru", "cd /", "floa", "float(x)/"]
252 for t in s + list(map(str, s)):
252 for t in s + list(map(str, s)):
253 # We don't need to check exact completion values (they may change
253 # We don't need to check exact completion values (they may change
254 # depending on the state of the namespace, but at least no exceptions
254 # depending on the state of the namespace, but at least no exceptions
255 # should be thrown and the return value should be a pair of text, list
255 # should be thrown and the return value should be a pair of text, list
256 # values.
256 # values.
257 text, matches = ip.complete(t)
257 text, matches = ip.complete(t)
258 self.assertIsInstance(text, str)
258 self.assertIsInstance(text, str)
259 self.assertIsInstance(matches, list)
259 self.assertIsInstance(matches, list)
260
260
261 def test_latex_completions(self):
261 def test_latex_completions(self):
262 from IPython.core.latex_symbols import latex_symbols
262 from IPython.core.latex_symbols import latex_symbols
263 import random
263 import random
264
264
265 ip = get_ipython()
265 ip = get_ipython()
266 # Test some random unicode symbols
266 # Test some random unicode symbols
267 keys = random.sample(sorted(latex_symbols), 10)
267 keys = random.sample(sorted(latex_symbols), 10)
268 for k in keys:
268 for k in keys:
269 text, matches = ip.complete(k)
269 text, matches = ip.complete(k)
270 self.assertEqual(text, k)
270 self.assertEqual(text, k)
271 self.assertEqual(matches, [latex_symbols[k]])
271 self.assertEqual(matches, [latex_symbols[k]])
272 # Test a more complex line
272 # Test a more complex line
273 text, matches = ip.complete("print(\\alpha")
273 text, matches = ip.complete("print(\\alpha")
274 self.assertEqual(text, "\\alpha")
274 self.assertEqual(text, "\\alpha")
275 self.assertEqual(matches[0], latex_symbols["\\alpha"])
275 self.assertEqual(matches[0], latex_symbols["\\alpha"])
276 # Test multiple matching latex symbols
276 # Test multiple matching latex symbols
277 text, matches = ip.complete("\\al")
277 text, matches = ip.complete("\\al")
278 self.assertIn("\\alpha", matches)
278 self.assertIn("\\alpha", matches)
279 self.assertIn("\\aleph", matches)
279 self.assertIn("\\aleph", matches)
280
280
281 def test_latex_no_results(self):
281 def test_latex_no_results(self):
282 """
282 """
283 forward latex should really return nothing in either field if nothing is found.
283 forward latex should really return nothing in either field if nothing is found.
284 """
284 """
285 ip = get_ipython()
285 ip = get_ipython()
286 text, matches = ip.Completer.latex_matches("\\really_i_should_match_nothing")
286 text, matches = ip.Completer.latex_matches("\\really_i_should_match_nothing")
287 self.assertEqual(text, "")
287 self.assertEqual(text, "")
288 self.assertEqual(matches, ())
288 self.assertEqual(matches, ())
289
289
290 def test_back_latex_completion(self):
290 def test_back_latex_completion(self):
291 ip = get_ipython()
291 ip = get_ipython()
292
292
293 # do not return more than 1 matches for \beta, only the latex one.
293 # do not return more than 1 matches for \beta, only the latex one.
294 name, matches = ip.complete("\\β")
294 name, matches = ip.complete("\\β")
295 self.assertEqual(matches, ["\\beta"])
295 self.assertEqual(matches, ["\\beta"])
296
296
297 def test_back_unicode_completion(self):
297 def test_back_unicode_completion(self):
298 ip = get_ipython()
298 ip = get_ipython()
299
299
300 name, matches = ip.complete("\\Ⅴ")
300 name, matches = ip.complete("\\Ⅴ")
301 self.assertEqual(matches, ("\\ROMAN NUMERAL FIVE",))
301 self.assertEqual(matches, ("\\ROMAN NUMERAL FIVE",))
302
302
303 def test_forward_unicode_completion(self):
303 def test_forward_unicode_completion(self):
304 ip = get_ipython()
304 ip = get_ipython()
305
305
306 name, matches = ip.complete("\\ROMAN NUMERAL FIVE")
306 name, matches = ip.complete("\\ROMAN NUMERAL FIVE")
307 self.assertEqual(matches, ["Ⅴ"]) # This is not a V
307 self.assertEqual(matches, ["Ⅴ"]) # This is not a V
308 self.assertEqual(matches, ["\u2164"]) # same as above but explicit.
308 self.assertEqual(matches, ["\u2164"]) # same as above but explicit.
309
309
310 def test_delim_setting(self):
310 def test_delim_setting(self):
311 sp = completer.CompletionSplitter()
311 sp = completer.CompletionSplitter()
312 sp.delims = " "
312 sp.delims = " "
313 self.assertEqual(sp.delims, " ")
313 self.assertEqual(sp.delims, " ")
314 self.assertEqual(sp._delim_expr, r"[\ ]")
314 self.assertEqual(sp._delim_expr, r"[\ ]")
315
315
316 def test_spaces(self):
316 def test_spaces(self):
317 """Test with only spaces as split chars."""
317 """Test with only spaces as split chars."""
318 sp = completer.CompletionSplitter()
318 sp = completer.CompletionSplitter()
319 sp.delims = " "
319 sp.delims = " "
320 t = [("foo", "", "foo"), ("run foo", "", "foo"), ("run foo", "bar", "foo")]
320 t = [("foo", "", "foo"), ("run foo", "", "foo"), ("run foo", "bar", "foo")]
321 check_line_split(sp, t)
321 check_line_split(sp, t)
322
322
323 def test_has_open_quotes1(self):
323 def test_has_open_quotes1(self):
324 for s in ["'", "'''", "'hi' '"]:
324 for s in ["'", "'''", "'hi' '"]:
325 self.assertEqual(completer.has_open_quotes(s), "'")
325 self.assertEqual(completer.has_open_quotes(s), "'")
326
326
327 def test_has_open_quotes2(self):
327 def test_has_open_quotes2(self):
328 for s in ['"', '"""', '"hi" "']:
328 for s in ['"', '"""', '"hi" "']:
329 self.assertEqual(completer.has_open_quotes(s), '"')
329 self.assertEqual(completer.has_open_quotes(s), '"')
330
330
331 def test_has_open_quotes3(self):
331 def test_has_open_quotes3(self):
332 for s in ["''", "''' '''", "'hi' 'ipython'"]:
332 for s in ["''", "''' '''", "'hi' 'ipython'"]:
333 self.assertFalse(completer.has_open_quotes(s))
333 self.assertFalse(completer.has_open_quotes(s))
334
334
335 def test_has_open_quotes4(self):
335 def test_has_open_quotes4(self):
336 for s in ['""', '""" """', '"hi" "ipython"']:
336 for s in ['""', '""" """', '"hi" "ipython"']:
337 self.assertFalse(completer.has_open_quotes(s))
337 self.assertFalse(completer.has_open_quotes(s))
338
338
339 @pytest.mark.xfail(
339 @pytest.mark.xfail(
340 sys.platform == "win32", reason="abspath completions fail on Windows"
340 sys.platform == "win32", reason="abspath completions fail on Windows"
341 )
341 )
342 def test_abspath_file_completions(self):
342 def test_abspath_file_completions(self):
343 ip = get_ipython()
343 ip = get_ipython()
344 with TemporaryDirectory() as tmpdir:
344 with TemporaryDirectory() as tmpdir:
345 prefix = os.path.join(tmpdir, "foo")
345 prefix = os.path.join(tmpdir, "foo")
346 suffixes = ["1", "2"]
346 suffixes = ["1", "2"]
347 names = [prefix + s for s in suffixes]
347 names = [prefix + s for s in suffixes]
348 for n in names:
348 for n in names:
349 open(n, "w", encoding='utf-8').close()
349 open(n, "w", encoding="utf-8").close()
350
350
351 # Check simple completion
351 # Check simple completion
352 c = ip.complete(prefix)[1]
352 c = ip.complete(prefix)[1]
353 self.assertEqual(c, names)
353 self.assertEqual(c, names)
354
354
355 # Now check with a function call
355 # Now check with a function call
356 cmd = 'a = f("%s' % prefix
356 cmd = 'a = f("%s' % prefix
357 c = ip.complete(prefix, cmd)[1]
357 c = ip.complete(prefix, cmd)[1]
358 comp = [prefix + s for s in suffixes]
358 comp = [prefix + s for s in suffixes]
359 self.assertEqual(c, comp)
359 self.assertEqual(c, comp)
360
360
361 def test_local_file_completions(self):
361 def test_local_file_completions(self):
362 ip = get_ipython()
362 ip = get_ipython()
363 with TemporaryWorkingDirectory():
363 with TemporaryWorkingDirectory():
364 prefix = "./foo"
364 prefix = "./foo"
365 suffixes = ["1", "2"]
365 suffixes = ["1", "2"]
366 names = [prefix + s for s in suffixes]
366 names = [prefix + s for s in suffixes]
367 for n in names:
367 for n in names:
368 open(n, "w", encoding='utf-8').close()
368 open(n, "w", encoding="utf-8").close()
369
369
370 # Check simple completion
370 # Check simple completion
371 c = ip.complete(prefix)[1]
371 c = ip.complete(prefix)[1]
372 self.assertEqual(c, names)
372 self.assertEqual(c, names)
373
373
374 # Now check with a function call
374 # Now check with a function call
375 cmd = 'a = f("%s' % prefix
375 cmd = 'a = f("%s' % prefix
376 c = ip.complete(prefix, cmd)[1]
376 c = ip.complete(prefix, cmd)[1]
377 comp = {prefix + s for s in suffixes}
377 comp = {prefix + s for s in suffixes}
378 self.assertTrue(comp.issubset(set(c)))
378 self.assertTrue(comp.issubset(set(c)))
379
379
380 def test_quoted_file_completions(self):
380 def test_quoted_file_completions(self):
381 ip = get_ipython()
381 ip = get_ipython()
382 with TemporaryWorkingDirectory():
382 with TemporaryWorkingDirectory():
383 name = "foo'bar"
383 name = "foo'bar"
384 open(name, "w", encoding='utf-8').close()
384 open(name, "w", encoding="utf-8").close()
385
385
386 # Don't escape Windows
386 # Don't escape Windows
387 escaped = name if sys.platform == "win32" else "foo\\'bar"
387 escaped = name if sys.platform == "win32" else "foo\\'bar"
388
388
389 # Single quote matches embedded single quote
389 # Single quote matches embedded single quote
390 text = "open('foo"
390 text = "open('foo"
391 c = ip.Completer._complete(
391 c = ip.Completer._complete(
392 cursor_line=0, cursor_pos=len(text), full_text=text
392 cursor_line=0, cursor_pos=len(text), full_text=text
393 )[1]
393 )[1]
394 self.assertEqual(c, [escaped])
394 self.assertEqual(c, [escaped])
395
395
396 # Double quote requires no escape
396 # Double quote requires no escape
397 text = 'open("foo'
397 text = 'open("foo'
398 c = ip.Completer._complete(
398 c = ip.Completer._complete(
399 cursor_line=0, cursor_pos=len(text), full_text=text
399 cursor_line=0, cursor_pos=len(text), full_text=text
400 )[1]
400 )[1]
401 self.assertEqual(c, [name])
401 self.assertEqual(c, [name])
402
402
403 # No quote requires an escape
403 # No quote requires an escape
404 text = "%ls foo"
404 text = "%ls foo"
405 c = ip.Completer._complete(
405 c = ip.Completer._complete(
406 cursor_line=0, cursor_pos=len(text), full_text=text
406 cursor_line=0, cursor_pos=len(text), full_text=text
407 )[1]
407 )[1]
408 self.assertEqual(c, [escaped])
408 self.assertEqual(c, [escaped])
409
409
410 def test_all_completions_dups(self):
410 def test_all_completions_dups(self):
411 """
411 """
412 Make sure the output of `IPCompleter.all_completions` does not have
412 Make sure the output of `IPCompleter.all_completions` does not have
413 duplicated prefixes.
413 duplicated prefixes.
414 """
414 """
415 ip = get_ipython()
415 ip = get_ipython()
416 c = ip.Completer
416 c = ip.Completer
417 ip.ex("class TestClass():\n\ta=1\n\ta1=2")
417 ip.ex("class TestClass():\n\ta=1\n\ta1=2")
418 for jedi_status in [True, False]:
418 for jedi_status in [True, False]:
419 with provisionalcompleter():
419 with provisionalcompleter():
420 ip.Completer.use_jedi = jedi_status
420 ip.Completer.use_jedi = jedi_status
421 matches = c.all_completions("TestCl")
421 matches = c.all_completions("TestCl")
422 assert matches == ["TestClass"], (jedi_status, matches)
422 assert matches == ["TestClass"], (jedi_status, matches)
423 matches = c.all_completions("TestClass.")
423 matches = c.all_completions("TestClass.")
424 assert len(matches) > 2, (jedi_status, matches)
424 assert len(matches) > 2, (jedi_status, matches)
425 matches = c.all_completions("TestClass.a")
425 matches = c.all_completions("TestClass.a")
426 assert matches == ['TestClass.a', 'TestClass.a1'], jedi_status
426 assert matches == ['TestClass.a', 'TestClass.a1'], jedi_status
427
427
428 def test_jedi(self):
428 def test_jedi(self):
429 """
429 """
430 A couple of issue we had with Jedi
430 A couple of issue we had with Jedi
431 """
431 """
432 ip = get_ipython()
432 ip = get_ipython()
433
433
434 def _test_complete(reason, s, comp, start=None, end=None):
434 def _test_complete(reason, s, comp, start=None, end=None):
435 l = len(s)
435 l = len(s)
436 start = start if start is not None else l
436 start = start if start is not None else l
437 end = end if end is not None else l
437 end = end if end is not None else l
438 with provisionalcompleter():
438 with provisionalcompleter():
439 ip.Completer.use_jedi = True
439 ip.Completer.use_jedi = True
440 completions = set(ip.Completer.completions(s, l))
440 completions = set(ip.Completer.completions(s, l))
441 ip.Completer.use_jedi = False
441 ip.Completer.use_jedi = False
442 assert Completion(start, end, comp) in completions, reason
442 assert Completion(start, end, comp) in completions, reason
443
443
444 def _test_not_complete(reason, s, comp):
444 def _test_not_complete(reason, s, comp):
445 l = len(s)
445 l = len(s)
446 with provisionalcompleter():
446 with provisionalcompleter():
447 ip.Completer.use_jedi = True
447 ip.Completer.use_jedi = True
448 completions = set(ip.Completer.completions(s, l))
448 completions = set(ip.Completer.completions(s, l))
449 ip.Completer.use_jedi = False
449 ip.Completer.use_jedi = False
450 assert Completion(l, l, comp) not in completions, reason
450 assert Completion(l, l, comp) not in completions, reason
451
451
452 import jedi
452 import jedi
453
453
454 jedi_version = tuple(int(i) for i in jedi.__version__.split(".")[:3])
454 jedi_version = tuple(int(i) for i in jedi.__version__.split(".")[:3])
455 if jedi_version > (0, 10):
455 if jedi_version > (0, 10):
456 _test_complete("jedi >0.9 should complete and not crash", "a=1;a.", "real")
456 _test_complete("jedi >0.9 should complete and not crash", "a=1;a.", "real")
457 _test_complete("can infer first argument", 'a=(1,"foo");a[0].', "real")
457 _test_complete("can infer first argument", 'a=(1,"foo");a[0].', "real")
458 _test_complete("can infer second argument", 'a=(1,"foo");a[1].', "capitalize")
458 _test_complete("can infer second argument", 'a=(1,"foo");a[1].', "capitalize")
459 _test_complete("cover duplicate completions", "im", "import", 0, 2)
459 _test_complete("cover duplicate completions", "im", "import", 0, 2)
460
460
461 _test_not_complete("does not mix types", 'a=(1,"foo");a[0].', "capitalize")
461 _test_not_complete("does not mix types", 'a=(1,"foo");a[0].', "capitalize")
462
462
463 def test_completion_have_signature(self):
463 def test_completion_have_signature(self):
464 """
464 """
465 Lets make sure jedi is capable of pulling out the signature of the function we are completing.
465 Lets make sure jedi is capable of pulling out the signature of the function we are completing.
466 """
466 """
467 ip = get_ipython()
467 ip = get_ipython()
468 with provisionalcompleter():
468 with provisionalcompleter():
469 ip.Completer.use_jedi = True
469 ip.Completer.use_jedi = True
470 completions = ip.Completer.completions("ope", 3)
470 completions = ip.Completer.completions("ope", 3)
471 c = next(completions) # should be `open`
471 c = next(completions) # should be `open`
472 ip.Completer.use_jedi = False
472 ip.Completer.use_jedi = False
473 assert "file" in c.signature, "Signature of function was not found by completer"
473 assert "file" in c.signature, "Signature of function was not found by completer"
474 assert (
474 assert (
475 "encoding" in c.signature
475 "encoding" in c.signature
476 ), "Signature of function was not found by completer"
476 ), "Signature of function was not found by completer"
477
477
478 @pytest.mark.xfail(reason="Known failure on jedi<=0.18.0")
478 @pytest.mark.xfail(reason="Known failure on jedi<=0.18.0")
479 def test_deduplicate_completions(self):
479 def test_deduplicate_completions(self):
480 """
480 """
481 Test that completions are correctly deduplicated (even if ranges are not the same)
481 Test that completions are correctly deduplicated (even if ranges are not the same)
482 """
482 """
483 ip = get_ipython()
483 ip = get_ipython()
484 ip.ex(
484 ip.ex(
485 textwrap.dedent(
485 textwrap.dedent(
486 """
486 """
487 class Z:
487 class Z:
488 zoo = 1
488 zoo = 1
489 """
489 """
490 )
490 )
491 )
491 )
492 with provisionalcompleter():
492 with provisionalcompleter():
493 ip.Completer.use_jedi = True
493 ip.Completer.use_jedi = True
494 l = list(
494 l = list(
495 _deduplicate_completions("Z.z", ip.Completer.completions("Z.z", 3))
495 _deduplicate_completions("Z.z", ip.Completer.completions("Z.z", 3))
496 )
496 )
497 ip.Completer.use_jedi = False
497 ip.Completer.use_jedi = False
498
498
499 assert len(l) == 1, "Completions (Z.z<tab>) correctly deduplicate: %s " % l
499 assert len(l) == 1, "Completions (Z.z<tab>) correctly deduplicate: %s " % l
500 assert l[0].text == "zoo" # and not `it.accumulate`
500 assert l[0].text == "zoo" # and not `it.accumulate`
501
501
502 def test_greedy_completions(self):
502 def test_greedy_completions(self):
503 """
503 """
504 Test the capability of the Greedy completer.
504 Test the capability of the Greedy completer.
505
505
506 Most of the test here does not really show off the greedy completer, for proof
506 Most of the test here does not really show off the greedy completer, for proof
507 each of the text below now pass with Jedi. The greedy completer is capable of more.
507 each of the text below now pass with Jedi. The greedy completer is capable of more.
508
508
509 See the :any:`test_dict_key_completion_contexts`
509 See the :any:`test_dict_key_completion_contexts`
510
510
511 """
511 """
512 ip = get_ipython()
512 ip = get_ipython()
513 ip.ex("a=list(range(5))")
513 ip.ex("a=list(range(5))")
514 _, c = ip.complete(".", line="a[0].")
514 _, c = ip.complete(".", line="a[0].")
515 self.assertFalse(".real" in c, "Shouldn't have completed on a[0]: %s" % c)
515 self.assertFalse(".real" in c, "Shouldn't have completed on a[0]: %s" % c)
516
516
517 def _(line, cursor_pos, expect, message, completion):
517 def _(line, cursor_pos, expect, message, completion):
518 with greedy_completion(), provisionalcompleter():
518 with greedy_completion(), provisionalcompleter():
519 ip.Completer.use_jedi = False
519 ip.Completer.use_jedi = False
520 _, c = ip.complete(".", line=line, cursor_pos=cursor_pos)
520 _, c = ip.complete(".", line=line, cursor_pos=cursor_pos)
521 self.assertIn(expect, c, message % c)
521 self.assertIn(expect, c, message % c)
522
522
523 ip.Completer.use_jedi = True
523 ip.Completer.use_jedi = True
524 with provisionalcompleter():
524 with provisionalcompleter():
525 completions = ip.Completer.completions(line, cursor_pos)
525 completions = ip.Completer.completions(line, cursor_pos)
526 self.assertIn(completion, completions)
526 self.assertIn(completion, completions)
527
527
528 with provisionalcompleter():
528 with provisionalcompleter():
529 _(
529 _(
530 "a[0].",
530 "a[0].",
531 5,
531 5,
532 "a[0].real",
532 "a[0].real",
533 "Should have completed on a[0].: %s",
533 "Should have completed on a[0].: %s",
534 Completion(5, 5, "real"),
534 Completion(5, 5, "real"),
535 )
535 )
536 _(
536 _(
537 "a[0].r",
537 "a[0].r",
538 6,
538 6,
539 "a[0].real",
539 "a[0].real",
540 "Should have completed on a[0].r: %s",
540 "Should have completed on a[0].r: %s",
541 Completion(5, 6, "real"),
541 Completion(5, 6, "real"),
542 )
542 )
543
543
544 _(
544 _(
545 "a[0].from_",
545 "a[0].from_",
546 10,
546 10,
547 "a[0].from_bytes",
547 "a[0].from_bytes",
548 "Should have completed on a[0].from_: %s",
548 "Should have completed on a[0].from_: %s",
549 Completion(5, 10, "from_bytes"),
549 Completion(5, 10, "from_bytes"),
550 )
550 )
551
551
552 def test_omit__names(self):
552 def test_omit__names(self):
553 # also happens to test IPCompleter as a configurable
553 # also happens to test IPCompleter as a configurable
554 ip = get_ipython()
554 ip = get_ipython()
555 ip._hidden_attr = 1
555 ip._hidden_attr = 1
556 ip._x = {}
556 ip._x = {}
557 c = ip.Completer
557 c = ip.Completer
558 ip.ex("ip=get_ipython()")
558 ip.ex("ip=get_ipython()")
559 cfg = Config()
559 cfg = Config()
560 cfg.IPCompleter.omit__names = 0
560 cfg.IPCompleter.omit__names = 0
561 c.update_config(cfg)
561 c.update_config(cfg)
562 with provisionalcompleter():
562 with provisionalcompleter():
563 c.use_jedi = False
563 c.use_jedi = False
564 s, matches = c.complete("ip.")
564 s, matches = c.complete("ip.")
565 self.assertIn("ip.__str__", matches)
565 self.assertIn("ip.__str__", matches)
566 self.assertIn("ip._hidden_attr", matches)
566 self.assertIn("ip._hidden_attr", matches)
567
567
568 # c.use_jedi = True
568 # c.use_jedi = True
569 # completions = set(c.completions('ip.', 3))
569 # completions = set(c.completions('ip.', 3))
570 # self.assertIn(Completion(3, 3, '__str__'), completions)
570 # self.assertIn(Completion(3, 3, '__str__'), completions)
571 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
571 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
572
572
573 cfg = Config()
573 cfg = Config()
574 cfg.IPCompleter.omit__names = 1
574 cfg.IPCompleter.omit__names = 1
575 c.update_config(cfg)
575 c.update_config(cfg)
576 with provisionalcompleter():
576 with provisionalcompleter():
577 c.use_jedi = False
577 c.use_jedi = False
578 s, matches = c.complete("ip.")
578 s, matches = c.complete("ip.")
579 self.assertNotIn("ip.__str__", matches)
579 self.assertNotIn("ip.__str__", matches)
580 # self.assertIn('ip._hidden_attr', matches)
580 # self.assertIn('ip._hidden_attr', matches)
581
581
582 # c.use_jedi = True
582 # c.use_jedi = True
583 # completions = set(c.completions('ip.', 3))
583 # completions = set(c.completions('ip.', 3))
584 # self.assertNotIn(Completion(3,3,'__str__'), completions)
584 # self.assertNotIn(Completion(3,3,'__str__'), completions)
585 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
585 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
586
586
587 cfg = Config()
587 cfg = Config()
588 cfg.IPCompleter.omit__names = 2
588 cfg.IPCompleter.omit__names = 2
589 c.update_config(cfg)
589 c.update_config(cfg)
590 with provisionalcompleter():
590 with provisionalcompleter():
591 c.use_jedi = False
591 c.use_jedi = False
592 s, matches = c.complete("ip.")
592 s, matches = c.complete("ip.")
593 self.assertNotIn("ip.__str__", matches)
593 self.assertNotIn("ip.__str__", matches)
594 self.assertNotIn("ip._hidden_attr", matches)
594 self.assertNotIn("ip._hidden_attr", matches)
595
595
596 # c.use_jedi = True
596 # c.use_jedi = True
597 # completions = set(c.completions('ip.', 3))
597 # completions = set(c.completions('ip.', 3))
598 # self.assertNotIn(Completion(3,3,'__str__'), completions)
598 # self.assertNotIn(Completion(3,3,'__str__'), completions)
599 # self.assertNotIn(Completion(3,3, "_hidden_attr"), completions)
599 # self.assertNotIn(Completion(3,3, "_hidden_attr"), completions)
600
600
601 with provisionalcompleter():
601 with provisionalcompleter():
602 c.use_jedi = False
602 c.use_jedi = False
603 s, matches = c.complete("ip._x.")
603 s, matches = c.complete("ip._x.")
604 self.assertIn("ip._x.keys", matches)
604 self.assertIn("ip._x.keys", matches)
605
605
606 # c.use_jedi = True
606 # c.use_jedi = True
607 # completions = set(c.completions('ip._x.', 6))
607 # completions = set(c.completions('ip._x.', 6))
608 # self.assertIn(Completion(6,6, "keys"), completions)
608 # self.assertIn(Completion(6,6, "keys"), completions)
609
609
610 del ip._hidden_attr
610 del ip._hidden_attr
611 del ip._x
611 del ip._x
612
612
613 def test_limit_to__all__False_ok(self):
613 def test_limit_to__all__False_ok(self):
614 """
614 """
615 Limit to all is deprecated, once we remove it this test can go away.
615 Limit to all is deprecated, once we remove it this test can go away.
616 """
616 """
617 ip = get_ipython()
617 ip = get_ipython()
618 c = ip.Completer
618 c = ip.Completer
619 c.use_jedi = False
619 c.use_jedi = False
620 ip.ex("class D: x=24")
620 ip.ex("class D: x=24")
621 ip.ex("d=D()")
621 ip.ex("d=D()")
622 cfg = Config()
622 cfg = Config()
623 cfg.IPCompleter.limit_to__all__ = False
623 cfg.IPCompleter.limit_to__all__ = False
624 c.update_config(cfg)
624 c.update_config(cfg)
625 s, matches = c.complete("d.")
625 s, matches = c.complete("d.")
626 self.assertIn("d.x", matches)
626 self.assertIn("d.x", matches)
627
627
628 def test_get__all__entries_ok(self):
628 def test_get__all__entries_ok(self):
629 class A:
629 class A:
630 __all__ = ["x", 1]
630 __all__ = ["x", 1]
631
631
632 words = completer.get__all__entries(A())
632 words = completer.get__all__entries(A())
633 self.assertEqual(words, ["x"])
633 self.assertEqual(words, ["x"])
634
634
635 def test_get__all__entries_no__all__ok(self):
635 def test_get__all__entries_no__all__ok(self):
636 class A:
636 class A:
637 pass
637 pass
638
638
639 words = completer.get__all__entries(A())
639 words = completer.get__all__entries(A())
640 self.assertEqual(words, [])
640 self.assertEqual(words, [])
641
641
642 def test_func_kw_completions(self):
642 def test_func_kw_completions(self):
643 ip = get_ipython()
643 ip = get_ipython()
644 c = ip.Completer
644 c = ip.Completer
645 c.use_jedi = False
645 c.use_jedi = False
646 ip.ex("def myfunc(a=1,b=2): return a+b")
646 ip.ex("def myfunc(a=1,b=2): return a+b")
647 s, matches = c.complete(None, "myfunc(1,b")
647 s, matches = c.complete(None, "myfunc(1,b")
648 self.assertIn("b=", matches)
648 self.assertIn("b=", matches)
649 # Simulate completing with cursor right after b (pos==10):
649 # Simulate completing with cursor right after b (pos==10):
650 s, matches = c.complete(None, "myfunc(1,b)", 10)
650 s, matches = c.complete(None, "myfunc(1,b)", 10)
651 self.assertIn("b=", matches)
651 self.assertIn("b=", matches)
652 s, matches = c.complete(None, 'myfunc(a="escaped\\")string",b')
652 s, matches = c.complete(None, 'myfunc(a="escaped\\")string",b')
653 self.assertIn("b=", matches)
653 self.assertIn("b=", matches)
654 # builtin function
654 # builtin function
655 s, matches = c.complete(None, "min(k, k")
655 s, matches = c.complete(None, "min(k, k")
656 self.assertIn("key=", matches)
656 self.assertIn("key=", matches)
657
657
658 def test_default_arguments_from_docstring(self):
658 def test_default_arguments_from_docstring(self):
659 ip = get_ipython()
659 ip = get_ipython()
660 c = ip.Completer
660 c = ip.Completer
661 kwd = c._default_arguments_from_docstring("min(iterable[, key=func]) -> value")
661 kwd = c._default_arguments_from_docstring("min(iterable[, key=func]) -> value")
662 self.assertEqual(kwd, ["key"])
662 self.assertEqual(kwd, ["key"])
663 # with cython type etc
663 # with cython type etc
664 kwd = c._default_arguments_from_docstring(
664 kwd = c._default_arguments_from_docstring(
665 "Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
665 "Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
666 )
666 )
667 self.assertEqual(kwd, ["ncall", "resume", "nsplit"])
667 self.assertEqual(kwd, ["ncall", "resume", "nsplit"])
668 # white spaces
668 # white spaces
669 kwd = c._default_arguments_from_docstring(
669 kwd = c._default_arguments_from_docstring(
670 "\n Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
670 "\n Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
671 )
671 )
672 self.assertEqual(kwd, ["ncall", "resume", "nsplit"])
672 self.assertEqual(kwd, ["ncall", "resume", "nsplit"])
673
673
674 def test_line_magics(self):
674 def test_line_magics(self):
675 ip = get_ipython()
675 ip = get_ipython()
676 c = ip.Completer
676 c = ip.Completer
677 s, matches = c.complete(None, "lsmag")
677 s, matches = c.complete(None, "lsmag")
678 self.assertIn("%lsmagic", matches)
678 self.assertIn("%lsmagic", matches)
679 s, matches = c.complete(None, "%lsmag")
679 s, matches = c.complete(None, "%lsmag")
680 self.assertIn("%lsmagic", matches)
680 self.assertIn("%lsmagic", matches)
681
681
682 def test_cell_magics(self):
682 def test_cell_magics(self):
683 from IPython.core.magic import register_cell_magic
683 from IPython.core.magic import register_cell_magic
684
684
685 @register_cell_magic
685 @register_cell_magic
686 def _foo_cellm(line, cell):
686 def _foo_cellm(line, cell):
687 pass
687 pass
688
688
689 ip = get_ipython()
689 ip = get_ipython()
690 c = ip.Completer
690 c = ip.Completer
691
691
692 s, matches = c.complete(None, "_foo_ce")
692 s, matches = c.complete(None, "_foo_ce")
693 self.assertIn("%%_foo_cellm", matches)
693 self.assertIn("%%_foo_cellm", matches)
694 s, matches = c.complete(None, "%%_foo_ce")
694 s, matches = c.complete(None, "%%_foo_ce")
695 self.assertIn("%%_foo_cellm", matches)
695 self.assertIn("%%_foo_cellm", matches)
696
696
697 def test_line_cell_magics(self):
697 def test_line_cell_magics(self):
698 from IPython.core.magic import register_line_cell_magic
698 from IPython.core.magic import register_line_cell_magic
699
699
700 @register_line_cell_magic
700 @register_line_cell_magic
701 def _bar_cellm(line, cell):
701 def _bar_cellm(line, cell):
702 pass
702 pass
703
703
704 ip = get_ipython()
704 ip = get_ipython()
705 c = ip.Completer
705 c = ip.Completer
706
706
707 # The policy here is trickier, see comments in completion code. The
707 # The policy here is trickier, see comments in completion code. The
708 # returned values depend on whether the user passes %% or not explicitly,
708 # returned values depend on whether the user passes %% or not explicitly,
709 # and this will show a difference if the same name is both a line and cell
709 # and this will show a difference if the same name is both a line and cell
710 # magic.
710 # magic.
711 s, matches = c.complete(None, "_bar_ce")
711 s, matches = c.complete(None, "_bar_ce")
712 self.assertIn("%_bar_cellm", matches)
712 self.assertIn("%_bar_cellm", matches)
713 self.assertIn("%%_bar_cellm", matches)
713 self.assertIn("%%_bar_cellm", matches)
714 s, matches = c.complete(None, "%_bar_ce")
714 s, matches = c.complete(None, "%_bar_ce")
715 self.assertIn("%_bar_cellm", matches)
715 self.assertIn("%_bar_cellm", matches)
716 self.assertIn("%%_bar_cellm", matches)
716 self.assertIn("%%_bar_cellm", matches)
717 s, matches = c.complete(None, "%%_bar_ce")
717 s, matches = c.complete(None, "%%_bar_ce")
718 self.assertNotIn("%_bar_cellm", matches)
718 self.assertNotIn("%_bar_cellm", matches)
719 self.assertIn("%%_bar_cellm", matches)
719 self.assertIn("%%_bar_cellm", matches)
720
720
721 def test_magic_completion_order(self):
721 def test_magic_completion_order(self):
722 ip = get_ipython()
722 ip = get_ipython()
723 c = ip.Completer
723 c = ip.Completer
724
724
725 # Test ordering of line and cell magics.
725 # Test ordering of line and cell magics.
726 text, matches = c.complete("timeit")
726 text, matches = c.complete("timeit")
727 self.assertEqual(matches, ["%timeit", "%%timeit"])
727 self.assertEqual(matches, ["%timeit", "%%timeit"])
728
728
729 def test_magic_completion_shadowing(self):
729 def test_magic_completion_shadowing(self):
730 ip = get_ipython()
730 ip = get_ipython()
731 c = ip.Completer
731 c = ip.Completer
732 c.use_jedi = False
732 c.use_jedi = False
733
733
734 # Before importing matplotlib, %matplotlib magic should be the only option.
734 # Before importing matplotlib, %matplotlib magic should be the only option.
735 text, matches = c.complete("mat")
735 text, matches = c.complete("mat")
736 self.assertEqual(matches, ["%matplotlib"])
736 self.assertEqual(matches, ["%matplotlib"])
737
737
738 # The newly introduced name should shadow the magic.
738 # The newly introduced name should shadow the magic.
739 ip.run_cell("matplotlib = 1")
739 ip.run_cell("matplotlib = 1")
740 text, matches = c.complete("mat")
740 text, matches = c.complete("mat")
741 self.assertEqual(matches, ["matplotlib"])
741 self.assertEqual(matches, ["matplotlib"])
742
742
743 # After removing matplotlib from namespace, the magic should again be
743 # After removing matplotlib from namespace, the magic should again be
744 # the only option.
744 # the only option.
745 del ip.user_ns["matplotlib"]
745 del ip.user_ns["matplotlib"]
746 text, matches = c.complete("mat")
746 text, matches = c.complete("mat")
747 self.assertEqual(matches, ["%matplotlib"])
747 self.assertEqual(matches, ["%matplotlib"])
748
748
749 def test_magic_completion_shadowing_explicit(self):
749 def test_magic_completion_shadowing_explicit(self):
750 """
750 """
751 If the user try to complete a shadowed magic, and explicit % start should
751 If the user try to complete a shadowed magic, and explicit % start should
752 still return the completions.
752 still return the completions.
753 """
753 """
754 ip = get_ipython()
754 ip = get_ipython()
755 c = ip.Completer
755 c = ip.Completer
756
756
757 # Before importing matplotlib, %matplotlib magic should be the only option.
757 # Before importing matplotlib, %matplotlib magic should be the only option.
758 text, matches = c.complete("%mat")
758 text, matches = c.complete("%mat")
759 self.assertEqual(matches, ["%matplotlib"])
759 self.assertEqual(matches, ["%matplotlib"])
760
760
761 ip.run_cell("matplotlib = 1")
761 ip.run_cell("matplotlib = 1")
762
762
763 # After removing matplotlib from namespace, the magic should still be
763 # After removing matplotlib from namespace, the magic should still be
764 # the only option.
764 # the only option.
765 text, matches = c.complete("%mat")
765 text, matches = c.complete("%mat")
766 self.assertEqual(matches, ["%matplotlib"])
766 self.assertEqual(matches, ["%matplotlib"])
767
767
768 def test_magic_config(self):
768 def test_magic_config(self):
769 ip = get_ipython()
769 ip = get_ipython()
770 c = ip.Completer
770 c = ip.Completer
771
771
772 s, matches = c.complete(None, "conf")
772 s, matches = c.complete(None, "conf")
773 self.assertIn("%config", matches)
773 self.assertIn("%config", matches)
774 s, matches = c.complete(None, "conf")
774 s, matches = c.complete(None, "conf")
775 self.assertNotIn("AliasManager", matches)
775 self.assertNotIn("AliasManager", matches)
776 s, matches = c.complete(None, "config ")
776 s, matches = c.complete(None, "config ")
777 self.assertIn("AliasManager", matches)
777 self.assertIn("AliasManager", matches)
778 s, matches = c.complete(None, "%config ")
778 s, matches = c.complete(None, "%config ")
779 self.assertIn("AliasManager", matches)
779 self.assertIn("AliasManager", matches)
780 s, matches = c.complete(None, "config Ali")
780 s, matches = c.complete(None, "config Ali")
781 self.assertListEqual(["AliasManager"], matches)
781 self.assertListEqual(["AliasManager"], matches)
782 s, matches = c.complete(None, "%config Ali")
782 s, matches = c.complete(None, "%config Ali")
783 self.assertListEqual(["AliasManager"], matches)
783 self.assertListEqual(["AliasManager"], matches)
784 s, matches = c.complete(None, "config AliasManager")
784 s, matches = c.complete(None, "config AliasManager")
785 self.assertListEqual(["AliasManager"], matches)
785 self.assertListEqual(["AliasManager"], matches)
786 s, matches = c.complete(None, "%config AliasManager")
786 s, matches = c.complete(None, "%config AliasManager")
787 self.assertListEqual(["AliasManager"], matches)
787 self.assertListEqual(["AliasManager"], matches)
788 s, matches = c.complete(None, "config AliasManager.")
788 s, matches = c.complete(None, "config AliasManager.")
789 self.assertIn("AliasManager.default_aliases", matches)
789 self.assertIn("AliasManager.default_aliases", matches)
790 s, matches = c.complete(None, "%config AliasManager.")
790 s, matches = c.complete(None, "%config AliasManager.")
791 self.assertIn("AliasManager.default_aliases", matches)
791 self.assertIn("AliasManager.default_aliases", matches)
792 s, matches = c.complete(None, "config AliasManager.de")
792 s, matches = c.complete(None, "config AliasManager.de")
793 self.assertListEqual(["AliasManager.default_aliases"], matches)
793 self.assertListEqual(["AliasManager.default_aliases"], matches)
794 s, matches = c.complete(None, "config AliasManager.de")
794 s, matches = c.complete(None, "config AliasManager.de")
795 self.assertListEqual(["AliasManager.default_aliases"], matches)
795 self.assertListEqual(["AliasManager.default_aliases"], matches)
796
796
797 def test_magic_color(self):
797 def test_magic_color(self):
798 ip = get_ipython()
798 ip = get_ipython()
799 c = ip.Completer
799 c = ip.Completer
800
800
801 s, matches = c.complete(None, "colo")
801 s, matches = c.complete(None, "colo")
802 self.assertIn("%colors", matches)
802 self.assertIn("%colors", matches)
803 s, matches = c.complete(None, "colo")
803 s, matches = c.complete(None, "colo")
804 self.assertNotIn("NoColor", matches)
804 self.assertNotIn("NoColor", matches)
805 s, matches = c.complete(None, "%colors") # No trailing space
805 s, matches = c.complete(None, "%colors") # No trailing space
806 self.assertNotIn("NoColor", matches)
806 self.assertNotIn("NoColor", matches)
807 s, matches = c.complete(None, "colors ")
807 s, matches = c.complete(None, "colors ")
808 self.assertIn("NoColor", matches)
808 self.assertIn("NoColor", matches)
809 s, matches = c.complete(None, "%colors ")
809 s, matches = c.complete(None, "%colors ")
810 self.assertIn("NoColor", matches)
810 self.assertIn("NoColor", matches)
811 s, matches = c.complete(None, "colors NoCo")
811 s, matches = c.complete(None, "colors NoCo")
812 self.assertListEqual(["NoColor"], matches)
812 self.assertListEqual(["NoColor"], matches)
813 s, matches = c.complete(None, "%colors NoCo")
813 s, matches = c.complete(None, "%colors NoCo")
814 self.assertListEqual(["NoColor"], matches)
814 self.assertListEqual(["NoColor"], matches)
815
815
816 def test_match_dict_keys(self):
816 def test_match_dict_keys(self):
817 """
817 """
818 Test that match_dict_keys works on a couple of use case does return what
818 Test that match_dict_keys works on a couple of use case does return what
819 expected, and does not crash
819 expected, and does not crash
820 """
820 """
821 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
821 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
822
822
823 keys = ["foo", b"far"]
823 keys = ["foo", b"far"]
824 assert match_dict_keys(keys, "b'", delims=delims) == ("'", 2, ["far"])
824 assert match_dict_keys(keys, "b'", delims=delims) == ("'", 2, ["far"])
825 assert match_dict_keys(keys, "b'f", delims=delims) == ("'", 2, ["far"])
825 assert match_dict_keys(keys, "b'f", delims=delims) == ("'", 2, ["far"])
826 assert match_dict_keys(keys, 'b"', delims=delims) == ('"', 2, ["far"])
826 assert match_dict_keys(keys, 'b"', delims=delims) == ('"', 2, ["far"])
827 assert match_dict_keys(keys, 'b"f', delims=delims) == ('"', 2, ["far"])
827 assert match_dict_keys(keys, 'b"f', delims=delims) == ('"', 2, ["far"])
828
828
829 assert match_dict_keys(keys, "'", delims=delims) == ("'", 1, ["foo"])
829 assert match_dict_keys(keys, "'", delims=delims) == ("'", 1, ["foo"])
830 assert match_dict_keys(keys, "'f", delims=delims) == ("'", 1, ["foo"])
830 assert match_dict_keys(keys, "'f", delims=delims) == ("'", 1, ["foo"])
831 assert match_dict_keys(keys, '"', delims=delims) == ('"', 1, ["foo"])
831 assert match_dict_keys(keys, '"', delims=delims) == ('"', 1, ["foo"])
832 assert match_dict_keys(keys, '"f', delims=delims) == ('"', 1, ["foo"])
832 assert match_dict_keys(keys, '"f', delims=delims) == ('"', 1, ["foo"])
833
833
834 match_dict_keys
834 match_dict_keys
835
835
836 def test_match_dict_keys_tuple(self):
836 def test_match_dict_keys_tuple(self):
837 """
837 """
838 Test that match_dict_keys called with extra prefix works on a couple of use case,
838 Test that match_dict_keys called with extra prefix works on a couple of use case,
839 does return what expected, and does not crash.
839 does return what expected, and does not crash.
840 """
840 """
841 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
841 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
842
842
843 keys = [("foo", "bar"), ("foo", "oof"), ("foo", b"bar"), ('other', 'test')]
843 keys = [("foo", "bar"), ("foo", "oof"), ("foo", b"bar"), ('other', 'test')]
844
844
845 # Completion on first key == "foo"
845 # Completion on first key == "foo"
846 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["bar", "oof"])
846 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["bar", "oof"])
847 assert match_dict_keys(keys, "\"", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["bar", "oof"])
847 assert match_dict_keys(keys, "\"", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["bar", "oof"])
848 assert match_dict_keys(keys, "'o", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["oof"])
848 assert match_dict_keys(keys, "'o", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["oof"])
849 assert match_dict_keys(keys, "\"o", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["oof"])
849 assert match_dict_keys(keys, "\"o", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["oof"])
850 assert match_dict_keys(keys, "b'", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"])
850 assert match_dict_keys(keys, "b'", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"])
851 assert match_dict_keys(keys, "b\"", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"])
851 assert match_dict_keys(keys, "b\"", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"])
852 assert match_dict_keys(keys, "b'b", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"])
852 assert match_dict_keys(keys, "b'b", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"])
853 assert match_dict_keys(keys, "b\"b", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"])
853 assert match_dict_keys(keys, "b\"b", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"])
854
854
855 # No Completion
855 # No Completion
856 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("no_foo",)) == ("'", 1, [])
856 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("no_foo",)) == ("'", 1, [])
857 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("fo",)) == ("'", 1, [])
857 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("fo",)) == ("'", 1, [])
858
858
859 keys = [('foo1', 'foo2', 'foo3', 'foo4'), ('foo1', 'foo2', 'bar', 'foo4')]
859 keys = [('foo1', 'foo2', 'foo3', 'foo4'), ('foo1', 'foo2', 'bar', 'foo4')]
860 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1',)) == ("'", 1, ["foo2", "foo2"])
860 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1',)) == ("'", 1, ["foo2", "foo2"])
861 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2')) == ("'", 1, ["foo3"])
861 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2')) == ("'", 1, ["foo3"])
862 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3')) == ("'", 1, ["foo4"])
862 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3')) == ("'", 1, ["foo4"])
863 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3', 'foo4')) == ("'", 1, [])
863 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3', 'foo4')) == ("'", 1, [])
864
864
865 def test_dict_key_completion_string(self):
865 def test_dict_key_completion_string(self):
866 """Test dictionary key completion for string keys"""
866 """Test dictionary key completion for string keys"""
867 ip = get_ipython()
867 ip = get_ipython()
868 complete = ip.Completer.complete
868 complete = ip.Completer.complete
869
869
870 ip.user_ns["d"] = {"abc": None}
870 ip.user_ns["d"] = {"abc": None}
871
871
872 # check completion at different stages
872 # check completion at different stages
873 _, matches = complete(line_buffer="d[")
873 _, matches = complete(line_buffer="d[")
874 self.assertIn("'abc'", matches)
874 self.assertIn("'abc'", matches)
875 self.assertNotIn("'abc']", matches)
875 self.assertNotIn("'abc']", matches)
876
876
877 _, matches = complete(line_buffer="d['")
877 _, matches = complete(line_buffer="d['")
878 self.assertIn("abc", matches)
878 self.assertIn("abc", matches)
879 self.assertNotIn("abc']", matches)
879 self.assertNotIn("abc']", matches)
880
880
881 _, matches = complete(line_buffer="d['a")
881 _, matches = complete(line_buffer="d['a")
882 self.assertIn("abc", matches)
882 self.assertIn("abc", matches)
883 self.assertNotIn("abc']", matches)
883 self.assertNotIn("abc']", matches)
884
884
885 # check use of different quoting
885 # check use of different quoting
886 _, matches = complete(line_buffer='d["')
886 _, matches = complete(line_buffer='d["')
887 self.assertIn("abc", matches)
887 self.assertIn("abc", matches)
888 self.assertNotIn('abc"]', matches)
888 self.assertNotIn('abc"]', matches)
889
889
890 _, matches = complete(line_buffer='d["a')
890 _, matches = complete(line_buffer='d["a')
891 self.assertIn("abc", matches)
891 self.assertIn("abc", matches)
892 self.assertNotIn('abc"]', matches)
892 self.assertNotIn('abc"]', matches)
893
893
894 # check sensitivity to following context
894 # check sensitivity to following context
895 _, matches = complete(line_buffer="d[]", cursor_pos=2)
895 _, matches = complete(line_buffer="d[]", cursor_pos=2)
896 self.assertIn("'abc'", matches)
896 self.assertIn("'abc'", matches)
897
897
898 _, matches = complete(line_buffer="d['']", cursor_pos=3)
898 _, matches = complete(line_buffer="d['']", cursor_pos=3)
899 self.assertIn("abc", matches)
899 self.assertIn("abc", matches)
900 self.assertNotIn("abc'", matches)
900 self.assertNotIn("abc'", matches)
901 self.assertNotIn("abc']", matches)
901 self.assertNotIn("abc']", matches)
902
902
903 # check multiple solutions are correctly returned and that noise is not
903 # check multiple solutions are correctly returned and that noise is not
904 ip.user_ns["d"] = {
904 ip.user_ns["d"] = {
905 "abc": None,
905 "abc": None,
906 "abd": None,
906 "abd": None,
907 "bad": None,
907 "bad": None,
908 object(): None,
908 object(): None,
909 5: None,
909 5: None,
910 ("abe", None): None,
910 ("abe", None): None,
911 (None, "abf"): None
911 (None, "abf"): None
912 }
912 }
913
913
914 _, matches = complete(line_buffer="d['a")
914 _, matches = complete(line_buffer="d['a")
915 self.assertIn("abc", matches)
915 self.assertIn("abc", matches)
916 self.assertIn("abd", matches)
916 self.assertIn("abd", matches)
917 self.assertNotIn("bad", matches)
917 self.assertNotIn("bad", matches)
918 self.assertNotIn("abe", matches)
918 self.assertNotIn("abe", matches)
919 self.assertNotIn("abf", matches)
919 self.assertNotIn("abf", matches)
920 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
920 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
921
921
922 # check escaping and whitespace
922 # check escaping and whitespace
923 ip.user_ns["d"] = {"a\nb": None, "a'b": None, 'a"b': None, "a word": None}
923 ip.user_ns["d"] = {"a\nb": None, "a'b": None, 'a"b': None, "a word": None}
924 _, matches = complete(line_buffer="d['a")
924 _, matches = complete(line_buffer="d['a")
925 self.assertIn("a\\nb", matches)
925 self.assertIn("a\\nb", matches)
926 self.assertIn("a\\'b", matches)
926 self.assertIn("a\\'b", matches)
927 self.assertIn('a"b', matches)
927 self.assertIn('a"b', matches)
928 self.assertIn("a word", matches)
928 self.assertIn("a word", matches)
929 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
929 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
930
930
931 # - can complete on non-initial word of the string
931 # - can complete on non-initial word of the string
932 _, matches = complete(line_buffer="d['a w")
932 _, matches = complete(line_buffer="d['a w")
933 self.assertIn("word", matches)
933 self.assertIn("word", matches)
934
934
935 # - understands quote escaping
935 # - understands quote escaping
936 _, matches = complete(line_buffer="d['a\\'")
936 _, matches = complete(line_buffer="d['a\\'")
937 self.assertIn("b", matches)
937 self.assertIn("b", matches)
938
938
939 # - default quoting should work like repr
939 # - default quoting should work like repr
940 _, matches = complete(line_buffer="d[")
940 _, matches = complete(line_buffer="d[")
941 self.assertIn('"a\'b"', matches)
941 self.assertIn('"a\'b"', matches)
942
942
943 # - when opening quote with ", possible to match with unescaped apostrophe
943 # - when opening quote with ", possible to match with unescaped apostrophe
944 _, matches = complete(line_buffer="d[\"a'")
944 _, matches = complete(line_buffer="d[\"a'")
945 self.assertIn("b", matches)
945 self.assertIn("b", matches)
946
946
947 # need to not split at delims that readline won't split at
947 # need to not split at delims that readline won't split at
948 if "-" not in ip.Completer.splitter.delims:
948 if "-" not in ip.Completer.splitter.delims:
949 ip.user_ns["d"] = {"before-after": None}
949 ip.user_ns["d"] = {"before-after": None}
950 _, matches = complete(line_buffer="d['before-af")
950 _, matches = complete(line_buffer="d['before-af")
951 self.assertIn("before-after", matches)
951 self.assertIn("before-after", matches)
952
952
953 # check completion on tuple-of-string keys at different stage - on first key
953 # check completion on tuple-of-string keys at different stage - on first key
954 ip.user_ns["d"] = {('foo', 'bar'): None}
954 ip.user_ns["d"] = {('foo', 'bar'): None}
955 _, matches = complete(line_buffer="d[")
955 _, matches = complete(line_buffer="d[")
956 self.assertIn("'foo'", matches)
956 self.assertIn("'foo'", matches)
957 self.assertNotIn("'foo']", matches)
957 self.assertNotIn("'foo']", matches)
958 self.assertNotIn("'bar'", matches)
958 self.assertNotIn("'bar'", matches)
959 self.assertNotIn("foo", matches)
959 self.assertNotIn("foo", matches)
960 self.assertNotIn("bar", matches)
960 self.assertNotIn("bar", matches)
961
961
962 # - match the prefix
962 # - match the prefix
963 _, matches = complete(line_buffer="d['f")
963 _, matches = complete(line_buffer="d['f")
964 self.assertIn("foo", matches)
964 self.assertIn("foo", matches)
965 self.assertNotIn("foo']", matches)
965 self.assertNotIn("foo']", matches)
966 self.assertNotIn('foo"]', matches)
966 self.assertNotIn('foo"]', matches)
967 _, matches = complete(line_buffer="d['foo")
967 _, matches = complete(line_buffer="d['foo")
968 self.assertIn("foo", matches)
968 self.assertIn("foo", matches)
969
969
970 # - can complete on second key
970 # - can complete on second key
971 _, matches = complete(line_buffer="d['foo', ")
971 _, matches = complete(line_buffer="d['foo', ")
972 self.assertIn("'bar'", matches)
972 self.assertIn("'bar'", matches)
973 _, matches = complete(line_buffer="d['foo', 'b")
973 _, matches = complete(line_buffer="d['foo', 'b")
974 self.assertIn("bar", matches)
974 self.assertIn("bar", matches)
975 self.assertNotIn("foo", matches)
975 self.assertNotIn("foo", matches)
976
976
977 # - does not propose missing keys
977 # - does not propose missing keys
978 _, matches = complete(line_buffer="d['foo', 'f")
978 _, matches = complete(line_buffer="d['foo', 'f")
979 self.assertNotIn("bar", matches)
979 self.assertNotIn("bar", matches)
980 self.assertNotIn("foo", matches)
980 self.assertNotIn("foo", matches)
981
981
982 # check sensitivity to following context
982 # check sensitivity to following context
983 _, matches = complete(line_buffer="d['foo',]", cursor_pos=8)
983 _, matches = complete(line_buffer="d['foo',]", cursor_pos=8)
984 self.assertIn("'bar'", matches)
984 self.assertIn("'bar'", matches)
985 self.assertNotIn("bar", matches)
985 self.assertNotIn("bar", matches)
986 self.assertNotIn("'foo'", matches)
986 self.assertNotIn("'foo'", matches)
987 self.assertNotIn("foo", matches)
987 self.assertNotIn("foo", matches)
988
988
989 _, matches = complete(line_buffer="d['']", cursor_pos=3)
989 _, matches = complete(line_buffer="d['']", cursor_pos=3)
990 self.assertIn("foo", matches)
990 self.assertIn("foo", matches)
991 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
991 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
992
992
993 _, matches = complete(line_buffer='d[""]', cursor_pos=3)
993 _, matches = complete(line_buffer='d[""]', cursor_pos=3)
994 self.assertIn("foo", matches)
994 self.assertIn("foo", matches)
995 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
995 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
996
996
997 _, matches = complete(line_buffer='d["foo","]', cursor_pos=9)
997 _, matches = complete(line_buffer='d["foo","]', cursor_pos=9)
998 self.assertIn("bar", matches)
998 self.assertIn("bar", matches)
999 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
999 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1000
1000
1001 _, matches = complete(line_buffer='d["foo",]', cursor_pos=8)
1001 _, matches = complete(line_buffer='d["foo",]', cursor_pos=8)
1002 self.assertIn("'bar'", matches)
1002 self.assertIn("'bar'", matches)
1003 self.assertNotIn("bar", matches)
1003 self.assertNotIn("bar", matches)
1004
1004
1005 # Can complete with longer tuple keys
1005 # Can complete with longer tuple keys
1006 ip.user_ns["d"] = {('foo', 'bar', 'foobar'): None}
1006 ip.user_ns["d"] = {('foo', 'bar', 'foobar'): None}
1007
1007
1008 # - can complete second key
1008 # - can complete second key
1009 _, matches = complete(line_buffer="d['foo', 'b")
1009 _, matches = complete(line_buffer="d['foo', 'b")
1010 self.assertIn("bar", matches)
1010 self.assertIn("bar", matches)
1011 self.assertNotIn("foo", matches)
1011 self.assertNotIn("foo", matches)
1012 self.assertNotIn("foobar", matches)
1012 self.assertNotIn("foobar", matches)
1013
1013
1014 # - can complete third key
1014 # - can complete third key
1015 _, matches = complete(line_buffer="d['foo', 'bar', 'fo")
1015 _, matches = complete(line_buffer="d['foo', 'bar', 'fo")
1016 self.assertIn("foobar", matches)
1016 self.assertIn("foobar", matches)
1017 self.assertNotIn("foo", matches)
1017 self.assertNotIn("foo", matches)
1018 self.assertNotIn("bar", matches)
1018 self.assertNotIn("bar", matches)
1019
1019
1020 def test_dict_key_completion_contexts(self):
1020 def test_dict_key_completion_contexts(self):
1021 """Test expression contexts in which dict key completion occurs"""
1021 """Test expression contexts in which dict key completion occurs"""
1022 ip = get_ipython()
1022 ip = get_ipython()
1023 complete = ip.Completer.complete
1023 complete = ip.Completer.complete
1024 d = {"abc": None}
1024 d = {"abc": None}
1025 ip.user_ns["d"] = d
1025 ip.user_ns["d"] = d
1026
1026
1027 class C:
1027 class C:
1028 data = d
1028 data = d
1029
1029
1030 ip.user_ns["C"] = C
1030 ip.user_ns["C"] = C
1031 ip.user_ns["get"] = lambda: d
1031 ip.user_ns["get"] = lambda: d
1032
1032
1033 def assert_no_completion(**kwargs):
1033 def assert_no_completion(**kwargs):
1034 _, matches = complete(**kwargs)
1034 _, matches = complete(**kwargs)
1035 self.assertNotIn("abc", matches)
1035 self.assertNotIn("abc", matches)
1036 self.assertNotIn("abc'", matches)
1036 self.assertNotIn("abc'", matches)
1037 self.assertNotIn("abc']", matches)
1037 self.assertNotIn("abc']", matches)
1038 self.assertNotIn("'abc'", matches)
1038 self.assertNotIn("'abc'", matches)
1039 self.assertNotIn("'abc']", matches)
1039 self.assertNotIn("'abc']", matches)
1040
1040
1041 def assert_completion(**kwargs):
1041 def assert_completion(**kwargs):
1042 _, matches = complete(**kwargs)
1042 _, matches = complete(**kwargs)
1043 self.assertIn("'abc'", matches)
1043 self.assertIn("'abc'", matches)
1044 self.assertNotIn("'abc']", matches)
1044 self.assertNotIn("'abc']", matches)
1045
1045
1046 # no completion after string closed, even if reopened
1046 # no completion after string closed, even if reopened
1047 assert_no_completion(line_buffer="d['a'")
1047 assert_no_completion(line_buffer="d['a'")
1048 assert_no_completion(line_buffer='d["a"')
1048 assert_no_completion(line_buffer='d["a"')
1049 assert_no_completion(line_buffer="d['a' + ")
1049 assert_no_completion(line_buffer="d['a' + ")
1050 assert_no_completion(line_buffer="d['a' + '")
1050 assert_no_completion(line_buffer="d['a' + '")
1051
1051
1052 # completion in non-trivial expressions
1052 # completion in non-trivial expressions
1053 assert_completion(line_buffer="+ d[")
1053 assert_completion(line_buffer="+ d[")
1054 assert_completion(line_buffer="(d[")
1054 assert_completion(line_buffer="(d[")
1055 assert_completion(line_buffer="C.data[")
1055 assert_completion(line_buffer="C.data[")
1056
1056
1057 # greedy flag
1057 # greedy flag
1058 def assert_completion(**kwargs):
1058 def assert_completion(**kwargs):
1059 _, matches = complete(**kwargs)
1059 _, matches = complete(**kwargs)
1060 self.assertIn("get()['abc']", matches)
1060 self.assertIn("get()['abc']", matches)
1061
1061
1062 assert_no_completion(line_buffer="get()[")
1062 assert_no_completion(line_buffer="get()[")
1063 with greedy_completion():
1063 with greedy_completion():
1064 assert_completion(line_buffer="get()[")
1064 assert_completion(line_buffer="get()[")
1065 assert_completion(line_buffer="get()['")
1065 assert_completion(line_buffer="get()['")
1066 assert_completion(line_buffer="get()['a")
1066 assert_completion(line_buffer="get()['a")
1067 assert_completion(line_buffer="get()['ab")
1067 assert_completion(line_buffer="get()['ab")
1068 assert_completion(line_buffer="get()['abc")
1068 assert_completion(line_buffer="get()['abc")
1069
1069
1070 def test_dict_key_completion_bytes(self):
1070 def test_dict_key_completion_bytes(self):
1071 """Test handling of bytes in dict key completion"""
1071 """Test handling of bytes in dict key completion"""
1072 ip = get_ipython()
1072 ip = get_ipython()
1073 complete = ip.Completer.complete
1073 complete = ip.Completer.complete
1074
1074
1075 ip.user_ns["d"] = {"abc": None, b"abd": None}
1075 ip.user_ns["d"] = {"abc": None, b"abd": None}
1076
1076
1077 _, matches = complete(line_buffer="d[")
1077 _, matches = complete(line_buffer="d[")
1078 self.assertIn("'abc'", matches)
1078 self.assertIn("'abc'", matches)
1079 self.assertIn("b'abd'", matches)
1079 self.assertIn("b'abd'", matches)
1080
1080
1081 if False: # not currently implemented
1081 if False: # not currently implemented
1082 _, matches = complete(line_buffer="d[b")
1082 _, matches = complete(line_buffer="d[b")
1083 self.assertIn("b'abd'", matches)
1083 self.assertIn("b'abd'", matches)
1084 self.assertNotIn("b'abc'", matches)
1084 self.assertNotIn("b'abc'", matches)
1085
1085
1086 _, matches = complete(line_buffer="d[b'")
1086 _, matches = complete(line_buffer="d[b'")
1087 self.assertIn("abd", matches)
1087 self.assertIn("abd", matches)
1088 self.assertNotIn("abc", matches)
1088 self.assertNotIn("abc", matches)
1089
1089
1090 _, matches = complete(line_buffer="d[B'")
1090 _, matches = complete(line_buffer="d[B'")
1091 self.assertIn("abd", matches)
1091 self.assertIn("abd", matches)
1092 self.assertNotIn("abc", matches)
1092 self.assertNotIn("abc", matches)
1093
1093
1094 _, matches = complete(line_buffer="d['")
1094 _, matches = complete(line_buffer="d['")
1095 self.assertIn("abc", matches)
1095 self.assertIn("abc", matches)
1096 self.assertNotIn("abd", matches)
1096 self.assertNotIn("abd", matches)
1097
1097
1098 def test_dict_key_completion_unicode_py3(self):
1098 def test_dict_key_completion_unicode_py3(self):
1099 """Test handling of unicode in dict key completion"""
1099 """Test handling of unicode in dict key completion"""
1100 ip = get_ipython()
1100 ip = get_ipython()
1101 complete = ip.Completer.complete
1101 complete = ip.Completer.complete
1102
1102
1103 ip.user_ns["d"] = {"a\u05d0": None}
1103 ip.user_ns["d"] = {"a\u05d0": None}
1104
1104
1105 # query using escape
1105 # query using escape
1106 if sys.platform != "win32":
1106 if sys.platform != "win32":
1107 # Known failure on Windows
1107 # Known failure on Windows
1108 _, matches = complete(line_buffer="d['a\\u05d0")
1108 _, matches = complete(line_buffer="d['a\\u05d0")
1109 self.assertIn("u05d0", matches) # tokenized after \\
1109 self.assertIn("u05d0", matches) # tokenized after \\
1110
1110
1111 # query using character
1111 # query using character
1112 _, matches = complete(line_buffer="d['a\u05d0")
1112 _, matches = complete(line_buffer="d['a\u05d0")
1113 self.assertIn("a\u05d0", matches)
1113 self.assertIn("a\u05d0", matches)
1114
1114
1115 with greedy_completion():
1115 with greedy_completion():
1116 # query using escape
1116 # query using escape
1117 _, matches = complete(line_buffer="d['a\\u05d0")
1117 _, matches = complete(line_buffer="d['a\\u05d0")
1118 self.assertIn("d['a\\u05d0']", matches) # tokenized after \\
1118 self.assertIn("d['a\\u05d0']", matches) # tokenized after \\
1119
1119
1120 # query using character
1120 # query using character
1121 _, matches = complete(line_buffer="d['a\u05d0")
1121 _, matches = complete(line_buffer="d['a\u05d0")
1122 self.assertIn("d['a\u05d0']", matches)
1122 self.assertIn("d['a\u05d0']", matches)
1123
1123
1124 @dec.skip_without("numpy")
1124 @dec.skip_without("numpy")
1125 def test_struct_array_key_completion(self):
1125 def test_struct_array_key_completion(self):
1126 """Test dict key completion applies to numpy struct arrays"""
1126 """Test dict key completion applies to numpy struct arrays"""
1127 import numpy
1127 import numpy
1128
1128
1129 ip = get_ipython()
1129 ip = get_ipython()
1130 complete = ip.Completer.complete
1130 complete = ip.Completer.complete
1131 ip.user_ns["d"] = numpy.array([], dtype=[("hello", "f"), ("world", "f")])
1131 ip.user_ns["d"] = numpy.array([], dtype=[("hello", "f"), ("world", "f")])
1132 _, matches = complete(line_buffer="d['")
1132 _, matches = complete(line_buffer="d['")
1133 self.assertIn("hello", matches)
1133 self.assertIn("hello", matches)
1134 self.assertIn("world", matches)
1134 self.assertIn("world", matches)
1135 # complete on the numpy struct itself
1135 # complete on the numpy struct itself
1136 dt = numpy.dtype(
1136 dt = numpy.dtype(
1137 [("my_head", [("my_dt", ">u4"), ("my_df", ">u4")]), ("my_data", ">f4", 5)]
1137 [("my_head", [("my_dt", ">u4"), ("my_df", ">u4")]), ("my_data", ">f4", 5)]
1138 )
1138 )
1139 x = numpy.zeros(2, dtype=dt)
1139 x = numpy.zeros(2, dtype=dt)
1140 ip.user_ns["d"] = x[1]
1140 ip.user_ns["d"] = x[1]
1141 _, matches = complete(line_buffer="d['")
1141 _, matches = complete(line_buffer="d['")
1142 self.assertIn("my_head", matches)
1142 self.assertIn("my_head", matches)
1143 self.assertIn("my_data", matches)
1143 self.assertIn("my_data", matches)
1144 # complete on a nested level
1144 # complete on a nested level
1145 with greedy_completion():
1145 with greedy_completion():
1146 ip.user_ns["d"] = numpy.zeros(2, dtype=dt)
1146 ip.user_ns["d"] = numpy.zeros(2, dtype=dt)
1147 _, matches = complete(line_buffer="d[1]['my_head']['")
1147 _, matches = complete(line_buffer="d[1]['my_head']['")
1148 self.assertTrue(any(["my_dt" in m for m in matches]))
1148 self.assertTrue(any(["my_dt" in m for m in matches]))
1149 self.assertTrue(any(["my_df" in m for m in matches]))
1149 self.assertTrue(any(["my_df" in m for m in matches]))
1150
1150
1151 @dec.skip_without("pandas")
1151 @dec.skip_without("pandas")
1152 def test_dataframe_key_completion(self):
1152 def test_dataframe_key_completion(self):
1153 """Test dict key completion applies to pandas DataFrames"""
1153 """Test dict key completion applies to pandas DataFrames"""
1154 import pandas
1154 import pandas
1155
1155
1156 ip = get_ipython()
1156 ip = get_ipython()
1157 complete = ip.Completer.complete
1157 complete = ip.Completer.complete
1158 ip.user_ns["d"] = pandas.DataFrame({"hello": [1], "world": [2]})
1158 ip.user_ns["d"] = pandas.DataFrame({"hello": [1], "world": [2]})
1159 _, matches = complete(line_buffer="d['")
1159 _, matches = complete(line_buffer="d['")
1160 self.assertIn("hello", matches)
1160 self.assertIn("hello", matches)
1161 self.assertIn("world", matches)
1161 self.assertIn("world", matches)
1162
1162
1163 def test_dict_key_completion_invalids(self):
1163 def test_dict_key_completion_invalids(self):
1164 """Smoke test cases dict key completion can't handle"""
1164 """Smoke test cases dict key completion can't handle"""
1165 ip = get_ipython()
1165 ip = get_ipython()
1166 complete = ip.Completer.complete
1166 complete = ip.Completer.complete
1167
1167
1168 ip.user_ns["no_getitem"] = None
1168 ip.user_ns["no_getitem"] = None
1169 ip.user_ns["no_keys"] = []
1169 ip.user_ns["no_keys"] = []
1170 ip.user_ns["cant_call_keys"] = dict
1170 ip.user_ns["cant_call_keys"] = dict
1171 ip.user_ns["empty"] = {}
1171 ip.user_ns["empty"] = {}
1172 ip.user_ns["d"] = {"abc": 5}
1172 ip.user_ns["d"] = {"abc": 5}
1173
1173
1174 _, matches = complete(line_buffer="no_getitem['")
1174 _, matches = complete(line_buffer="no_getitem['")
1175 _, matches = complete(line_buffer="no_keys['")
1175 _, matches = complete(line_buffer="no_keys['")
1176 _, matches = complete(line_buffer="cant_call_keys['")
1176 _, matches = complete(line_buffer="cant_call_keys['")
1177 _, matches = complete(line_buffer="empty['")
1177 _, matches = complete(line_buffer="empty['")
1178 _, matches = complete(line_buffer="name_error['")
1178 _, matches = complete(line_buffer="name_error['")
1179 _, matches = complete(line_buffer="d['\\") # incomplete escape
1179 _, matches = complete(line_buffer="d['\\") # incomplete escape
1180
1180
1181 def test_object_key_completion(self):
1181 def test_object_key_completion(self):
1182 ip = get_ipython()
1182 ip = get_ipython()
1183 ip.user_ns["key_completable"] = KeyCompletable(["qwerty", "qwick"])
1183 ip.user_ns["key_completable"] = KeyCompletable(["qwerty", "qwick"])
1184
1184
1185 _, matches = ip.Completer.complete(line_buffer="key_completable['qw")
1185 _, matches = ip.Completer.complete(line_buffer="key_completable['qw")
1186 self.assertIn("qwerty", matches)
1186 self.assertIn("qwerty", matches)
1187 self.assertIn("qwick", matches)
1187 self.assertIn("qwick", matches)
1188
1188
1189 def test_class_key_completion(self):
1189 def test_class_key_completion(self):
1190 ip = get_ipython()
1190 ip = get_ipython()
1191 NamedInstanceClass("qwerty")
1191 NamedInstanceClass("qwerty")
1192 NamedInstanceClass("qwick")
1192 NamedInstanceClass("qwick")
1193 ip.user_ns["named_instance_class"] = NamedInstanceClass
1193 ip.user_ns["named_instance_class"] = NamedInstanceClass
1194
1194
1195 _, matches = ip.Completer.complete(line_buffer="named_instance_class['qw")
1195 _, matches = ip.Completer.complete(line_buffer="named_instance_class['qw")
1196 self.assertIn("qwerty", matches)
1196 self.assertIn("qwerty", matches)
1197 self.assertIn("qwick", matches)
1197 self.assertIn("qwick", matches)
1198
1198
1199 def test_tryimport(self):
1199 def test_tryimport(self):
1200 """
1200 """
1201 Test that try-import don't crash on trailing dot, and import modules before
1201 Test that try-import don't crash on trailing dot, and import modules before
1202 """
1202 """
1203 from IPython.core.completerlib import try_import
1203 from IPython.core.completerlib import try_import
1204
1204
1205 assert try_import("IPython.")
1205 assert try_import("IPython.")
1206
1206
1207 def test_aimport_module_completer(self):
1207 def test_aimport_module_completer(self):
1208 ip = get_ipython()
1208 ip = get_ipython()
1209 _, matches = ip.complete("i", "%aimport i")
1209 _, matches = ip.complete("i", "%aimport i")
1210 self.assertIn("io", matches)
1210 self.assertIn("io", matches)
1211 self.assertNotIn("int", matches)
1211 self.assertNotIn("int", matches)
1212
1212
1213 def test_nested_import_module_completer(self):
1213 def test_nested_import_module_completer(self):
1214 ip = get_ipython()
1214 ip = get_ipython()
1215 _, matches = ip.complete(None, "import IPython.co", 17)
1215 _, matches = ip.complete(None, "import IPython.co", 17)
1216 self.assertIn("IPython.core", matches)
1216 self.assertIn("IPython.core", matches)
1217 self.assertNotIn("import IPython.core", matches)
1217 self.assertNotIn("import IPython.core", matches)
1218 self.assertNotIn("IPython.display", matches)
1218 self.assertNotIn("IPython.display", matches)
1219
1219
1220 def test_import_module_completer(self):
1220 def test_import_module_completer(self):
1221 ip = get_ipython()
1221 ip = get_ipython()
1222 _, matches = ip.complete("i", "import i")
1222 _, matches = ip.complete("i", "import i")
1223 self.assertIn("io", matches)
1223 self.assertIn("io", matches)
1224 self.assertNotIn("int", matches)
1224 self.assertNotIn("int", matches)
1225
1225
1226 def test_from_module_completer(self):
1226 def test_from_module_completer(self):
1227 ip = get_ipython()
1227 ip = get_ipython()
1228 _, matches = ip.complete("B", "from io import B", 16)
1228 _, matches = ip.complete("B", "from io import B", 16)
1229 self.assertIn("BytesIO", matches)
1229 self.assertIn("BytesIO", matches)
1230 self.assertNotIn("BaseException", matches)
1230 self.assertNotIn("BaseException", matches)
1231
1231
1232 def test_snake_case_completion(self):
1232 def test_snake_case_completion(self):
1233 ip = get_ipython()
1233 ip = get_ipython()
1234 ip.Completer.use_jedi = False
1234 ip.Completer.use_jedi = False
1235 ip.user_ns["some_three"] = 3
1235 ip.user_ns["some_three"] = 3
1236 ip.user_ns["some_four"] = 4
1236 ip.user_ns["some_four"] = 4
1237 _, matches = ip.complete("s_", "print(s_f")
1237 _, matches = ip.complete("s_", "print(s_f")
1238 self.assertIn("some_three", matches)
1238 self.assertIn("some_three", matches)
1239 self.assertIn("some_four", matches)
1239 self.assertIn("some_four", matches)
1240
1240
1241 def test_mix_terms(self):
1241 def test_mix_terms(self):
1242 ip = get_ipython()
1242 ip = get_ipython()
1243 from textwrap import dedent
1243 from textwrap import dedent
1244
1244
1245 ip.Completer.use_jedi = False
1245 ip.Completer.use_jedi = False
1246 ip.ex(
1246 ip.ex(
1247 dedent(
1247 dedent(
1248 """
1248 """
1249 class Test:
1249 class Test:
1250 def meth(self, meth_arg1):
1250 def meth(self, meth_arg1):
1251 print("meth")
1251 print("meth")
1252
1252
1253 def meth_1(self, meth1_arg1, meth1_arg2):
1253 def meth_1(self, meth1_arg1, meth1_arg2):
1254 print("meth1")
1254 print("meth1")
1255
1255
1256 def meth_2(self, meth2_arg1, meth2_arg2):
1256 def meth_2(self, meth2_arg1, meth2_arg2):
1257 print("meth2")
1257 print("meth2")
1258 test = Test()
1258 test = Test()
1259 """
1259 """
1260 )
1260 )
1261 )
1261 )
1262 _, matches = ip.complete(None, "test.meth(")
1262 _, matches = ip.complete(None, "test.meth(")
1263 self.assertIn("meth_arg1=", matches)
1263 self.assertIn("meth_arg1=", matches)
1264 self.assertNotIn("meth2_arg1=", matches)
1264 self.assertNotIn("meth2_arg1=", matches)
@@ -1,192 +1,192 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for completerlib.
2 """Tests for completerlib.
3
3
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Imports
7 # Imports
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 import os
10 import os
11 import shutil
11 import shutil
12 import sys
12 import sys
13 import tempfile
13 import tempfile
14 import unittest
14 import unittest
15 from os.path import join
15 from os.path import join
16
16
17 from IPython.core.completerlib import magic_run_completer, module_completion, try_import
17 from IPython.core.completerlib import magic_run_completer, module_completion, try_import
18 from IPython.utils.tempdir import TemporaryDirectory
18 from IPython.utils.tempdir import TemporaryDirectory
19 from IPython.testing.decorators import onlyif_unicode_paths
19 from IPython.testing.decorators import onlyif_unicode_paths
20
20
21
21
22 class MockEvent(object):
22 class MockEvent(object):
23 def __init__(self, line):
23 def __init__(self, line):
24 self.line = line
24 self.line = line
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Test functions begin
27 # Test functions begin
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 class Test_magic_run_completer(unittest.TestCase):
29 class Test_magic_run_completer(unittest.TestCase):
30 files = [u"aao.py", u"a.py", u"b.py", u"aao.txt"]
30 files = [u"aao.py", u"a.py", u"b.py", u"aao.txt"]
31 dirs = [u"adir/", "bdir/"]
31 dirs = [u"adir/", "bdir/"]
32
32
33 def setUp(self):
33 def setUp(self):
34 self.BASETESTDIR = tempfile.mkdtemp()
34 self.BASETESTDIR = tempfile.mkdtemp()
35 for fil in self.files:
35 for fil in self.files:
36 with open(join(self.BASETESTDIR, fil), "w", encoding='utf-8') as sfile:
36 with open(join(self.BASETESTDIR, fil), "w", encoding="utf-8") as sfile:
37 sfile.write("pass\n")
37 sfile.write("pass\n")
38 for d in self.dirs:
38 for d in self.dirs:
39 os.mkdir(join(self.BASETESTDIR, d))
39 os.mkdir(join(self.BASETESTDIR, d))
40
40
41 self.oldpath = os.getcwd()
41 self.oldpath = os.getcwd()
42 os.chdir(self.BASETESTDIR)
42 os.chdir(self.BASETESTDIR)
43
43
44 def tearDown(self):
44 def tearDown(self):
45 os.chdir(self.oldpath)
45 os.chdir(self.oldpath)
46 shutil.rmtree(self.BASETESTDIR)
46 shutil.rmtree(self.BASETESTDIR)
47
47
48 def test_1(self):
48 def test_1(self):
49 """Test magic_run_completer, should match two alternatives
49 """Test magic_run_completer, should match two alternatives
50 """
50 """
51 event = MockEvent(u"%run a")
51 event = MockEvent(u"%run a")
52 mockself = None
52 mockself = None
53 match = set(magic_run_completer(mockself, event))
53 match = set(magic_run_completer(mockself, event))
54 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
54 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
55
55
56 def test_2(self):
56 def test_2(self):
57 """Test magic_run_completer, should match one alternative
57 """Test magic_run_completer, should match one alternative
58 """
58 """
59 event = MockEvent(u"%run aa")
59 event = MockEvent(u"%run aa")
60 mockself = None
60 mockself = None
61 match = set(magic_run_completer(mockself, event))
61 match = set(magic_run_completer(mockself, event))
62 self.assertEqual(match, {u"aao.py"})
62 self.assertEqual(match, {u"aao.py"})
63
63
64 def test_3(self):
64 def test_3(self):
65 """Test magic_run_completer with unterminated " """
65 """Test magic_run_completer with unterminated " """
66 event = MockEvent(u'%run "a')
66 event = MockEvent(u'%run "a')
67 mockself = None
67 mockself = None
68 match = set(magic_run_completer(mockself, event))
68 match = set(magic_run_completer(mockself, event))
69 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
69 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
70
70
71 def test_completion_more_args(self):
71 def test_completion_more_args(self):
72 event = MockEvent(u'%run a.py ')
72 event = MockEvent(u'%run a.py ')
73 match = set(magic_run_completer(None, event))
73 match = set(magic_run_completer(None, event))
74 self.assertEqual(match, set(self.files + self.dirs))
74 self.assertEqual(match, set(self.files + self.dirs))
75
75
76 def test_completion_in_dir(self):
76 def test_completion_in_dir(self):
77 # Github issue #3459
77 # Github issue #3459
78 event = MockEvent(u'%run a.py {}'.format(join(self.BASETESTDIR, 'a')))
78 event = MockEvent(u'%run a.py {}'.format(join(self.BASETESTDIR, 'a')))
79 print(repr(event.line))
79 print(repr(event.line))
80 match = set(magic_run_completer(None, event))
80 match = set(magic_run_completer(None, event))
81 # We specifically use replace here rather than normpath, because
81 # We specifically use replace here rather than normpath, because
82 # at one point there were duplicates 'adir' and 'adir/', and normpath
82 # at one point there were duplicates 'adir' and 'adir/', and normpath
83 # would hide the failure for that.
83 # would hide the failure for that.
84 self.assertEqual(match, {join(self.BASETESTDIR, f).replace('\\','/')
84 self.assertEqual(match, {join(self.BASETESTDIR, f).replace('\\','/')
85 for f in (u'a.py', u'aao.py', u'aao.txt', u'adir/')})
85 for f in (u'a.py', u'aao.py', u'aao.txt', u'adir/')})
86
86
87 class Test_magic_run_completer_nonascii(unittest.TestCase):
87 class Test_magic_run_completer_nonascii(unittest.TestCase):
88 @onlyif_unicode_paths
88 @onlyif_unicode_paths
89 def setUp(self):
89 def setUp(self):
90 self.BASETESTDIR = tempfile.mkdtemp()
90 self.BASETESTDIR = tempfile.mkdtemp()
91 for fil in [u"aaø.py", u"a.py", u"b.py"]:
91 for fil in [u"aaø.py", u"a.py", u"b.py"]:
92 with open(join(self.BASETESTDIR, fil), "w", encoding='utf-8') as sfile:
92 with open(join(self.BASETESTDIR, fil), "w", encoding="utf-8") as sfile:
93 sfile.write("pass\n")
93 sfile.write("pass\n")
94 self.oldpath = os.getcwd()
94 self.oldpath = os.getcwd()
95 os.chdir(self.BASETESTDIR)
95 os.chdir(self.BASETESTDIR)
96
96
97 def tearDown(self):
97 def tearDown(self):
98 os.chdir(self.oldpath)
98 os.chdir(self.oldpath)
99 shutil.rmtree(self.BASETESTDIR)
99 shutil.rmtree(self.BASETESTDIR)
100
100
101 @onlyif_unicode_paths
101 @onlyif_unicode_paths
102 def test_1(self):
102 def test_1(self):
103 """Test magic_run_completer, should match two alternatives
103 """Test magic_run_completer, should match two alternatives
104 """
104 """
105 event = MockEvent(u"%run a")
105 event = MockEvent(u"%run a")
106 mockself = None
106 mockself = None
107 match = set(magic_run_completer(mockself, event))
107 match = set(magic_run_completer(mockself, event))
108 self.assertEqual(match, {u"a.py", u"aaø.py"})
108 self.assertEqual(match, {u"a.py", u"aaø.py"})
109
109
110 @onlyif_unicode_paths
110 @onlyif_unicode_paths
111 def test_2(self):
111 def test_2(self):
112 """Test magic_run_completer, should match one alternative
112 """Test magic_run_completer, should match one alternative
113 """
113 """
114 event = MockEvent(u"%run aa")
114 event = MockEvent(u"%run aa")
115 mockself = None
115 mockself = None
116 match = set(magic_run_completer(mockself, event))
116 match = set(magic_run_completer(mockself, event))
117 self.assertEqual(match, {u"aaø.py"})
117 self.assertEqual(match, {u"aaø.py"})
118
118
119 @onlyif_unicode_paths
119 @onlyif_unicode_paths
120 def test_3(self):
120 def test_3(self):
121 """Test magic_run_completer with unterminated " """
121 """Test magic_run_completer with unterminated " """
122 event = MockEvent(u'%run "a')
122 event = MockEvent(u'%run "a')
123 mockself = None
123 mockself = None
124 match = set(magic_run_completer(mockself, event))
124 match = set(magic_run_completer(mockself, event))
125 self.assertEqual(match, {u"a.py", u"aaø.py"})
125 self.assertEqual(match, {u"a.py", u"aaø.py"})
126
126
127 # module_completer:
127 # module_completer:
128
128
129 def test_import_invalid_module():
129 def test_import_invalid_module():
130 """Testing of issue https://github.com/ipython/ipython/issues/1107"""
130 """Testing of issue https://github.com/ipython/ipython/issues/1107"""
131 invalid_module_names = {'foo-bar', 'foo:bar', '10foo'}
131 invalid_module_names = {'foo-bar', 'foo:bar', '10foo'}
132 valid_module_names = {'foobar'}
132 valid_module_names = {'foobar'}
133 with TemporaryDirectory() as tmpdir:
133 with TemporaryDirectory() as tmpdir:
134 sys.path.insert( 0, tmpdir )
134 sys.path.insert( 0, tmpdir )
135 for name in invalid_module_names | valid_module_names:
135 for name in invalid_module_names | valid_module_names:
136 filename = os.path.join(tmpdir, name + '.py')
136 filename = os.path.join(tmpdir, name + ".py")
137 open(filename, 'w', encoding='utf-8').close()
137 open(filename, "w", encoding="utf-8").close()
138
138
139 s = set( module_completion('import foo') )
139 s = set( module_completion('import foo') )
140 intersection = s.intersection(invalid_module_names)
140 intersection = s.intersection(invalid_module_names)
141 assert intersection == set()
141 assert intersection == set()
142
142
143 assert valid_module_names.issubset(s), valid_module_names.intersection(s)
143 assert valid_module_names.issubset(s), valid_module_names.intersection(s)
144
144
145
145
146 def test_bad_module_all():
146 def test_bad_module_all():
147 """Test module with invalid __all__
147 """Test module with invalid __all__
148
148
149 https://github.com/ipython/ipython/issues/9678
149 https://github.com/ipython/ipython/issues/9678
150 """
150 """
151 testsdir = os.path.dirname(__file__)
151 testsdir = os.path.dirname(__file__)
152 sys.path.insert(0, testsdir)
152 sys.path.insert(0, testsdir)
153 try:
153 try:
154 results = module_completion("from bad_all import ")
154 results = module_completion("from bad_all import ")
155 assert "puppies" in results
155 assert "puppies" in results
156 for r in results:
156 for r in results:
157 assert isinstance(r, str)
157 assert isinstance(r, str)
158
158
159 # bad_all doesn't contain submodules, but this completion
159 # bad_all doesn't contain submodules, but this completion
160 # should finish without raising an exception:
160 # should finish without raising an exception:
161 results = module_completion("import bad_all.")
161 results = module_completion("import bad_all.")
162 assert results == []
162 assert results == []
163 finally:
163 finally:
164 sys.path.remove(testsdir)
164 sys.path.remove(testsdir)
165
165
166
166
167 def test_module_without_init():
167 def test_module_without_init():
168 """
168 """
169 Test module without __init__.py.
169 Test module without __init__.py.
170
170
171 https://github.com/ipython/ipython/issues/11226
171 https://github.com/ipython/ipython/issues/11226
172 """
172 """
173 fake_module_name = "foo"
173 fake_module_name = "foo"
174 with TemporaryDirectory() as tmpdir:
174 with TemporaryDirectory() as tmpdir:
175 sys.path.insert(0, tmpdir)
175 sys.path.insert(0, tmpdir)
176 try:
176 try:
177 os.makedirs(os.path.join(tmpdir, fake_module_name))
177 os.makedirs(os.path.join(tmpdir, fake_module_name))
178 s = try_import(mod=fake_module_name)
178 s = try_import(mod=fake_module_name)
179 assert s == []
179 assert s == []
180 finally:
180 finally:
181 sys.path.remove(tmpdir)
181 sys.path.remove(tmpdir)
182
182
183
183
184 def test_valid_exported_submodules():
184 def test_valid_exported_submodules():
185 """
185 """
186 Test checking exported (__all__) objects are submodules
186 Test checking exported (__all__) objects are submodules
187 """
187 """
188 results = module_completion("import os.pa")
188 results = module_completion("import os.pa")
189 # ensure we get a valid submodule:
189 # ensure we get a valid submodule:
190 assert "os.path" in results
190 assert "os.path" in results
191 # ensure we don't get objects that aren't submodules:
191 # ensure we don't get objects that aren't submodules:
192 assert "os.pathconf" not in results
192 assert "os.pathconf" not in results
@@ -1,94 +1,94 b''
1 import os.path
1 import os.path
2
2
3 import IPython.testing.tools as tt
3 import IPython.testing.tools as tt
4 from IPython.utils.syspathcontext import prepended_to_syspath
4 from IPython.utils.syspathcontext import prepended_to_syspath
5 from IPython.utils.tempdir import TemporaryDirectory
5 from IPython.utils.tempdir import TemporaryDirectory
6
6
7 ext1_content = """
7 ext1_content = """
8 def load_ipython_extension(ip):
8 def load_ipython_extension(ip):
9 print("Running ext1 load")
9 print("Running ext1 load")
10
10
11 def unload_ipython_extension(ip):
11 def unload_ipython_extension(ip):
12 print("Running ext1 unload")
12 print("Running ext1 unload")
13 """
13 """
14
14
15 ext2_content = """
15 ext2_content = """
16 def load_ipython_extension(ip):
16 def load_ipython_extension(ip):
17 print("Running ext2 load")
17 print("Running ext2 load")
18 """
18 """
19
19
20 ext3_content = """
20 ext3_content = """
21 def load_ipython_extension(ip):
21 def load_ipython_extension(ip):
22 ip2 = get_ipython()
22 ip2 = get_ipython()
23 print(ip is ip2)
23 print(ip is ip2)
24 """
24 """
25
25
26 def test_extension_loading():
26 def test_extension_loading():
27 em = get_ipython().extension_manager
27 em = get_ipython().extension_manager
28 with TemporaryDirectory() as td:
28 with TemporaryDirectory() as td:
29 ext1 = os.path.join(td, 'ext1.py')
29 ext1 = os.path.join(td, "ext1.py")
30 with open(ext1, 'w', encoding='utf-8') as f:
30 with open(ext1, "w", encoding="utf-8") as f:
31 f.write(ext1_content)
31 f.write(ext1_content)
32
32
33 ext2 = os.path.join(td, 'ext2.py')
33 ext2 = os.path.join(td, "ext2.py")
34 with open(ext2, 'w', encoding='utf-8') as f:
34 with open(ext2, "w", encoding="utf-8") as f:
35 f.write(ext2_content)
35 f.write(ext2_content)
36
36
37 with prepended_to_syspath(td):
37 with prepended_to_syspath(td):
38 assert 'ext1' not in em.loaded
38 assert 'ext1' not in em.loaded
39 assert 'ext2' not in em.loaded
39 assert 'ext2' not in em.loaded
40
40
41 # Load extension
41 # Load extension
42 with tt.AssertPrints("Running ext1 load"):
42 with tt.AssertPrints("Running ext1 load"):
43 assert em.load_extension('ext1') is None
43 assert em.load_extension('ext1') is None
44 assert 'ext1' in em.loaded
44 assert 'ext1' in em.loaded
45
45
46 # Should refuse to load it again
46 # Should refuse to load it again
47 with tt.AssertNotPrints("Running ext1 load"):
47 with tt.AssertNotPrints("Running ext1 load"):
48 assert em.load_extension('ext1') == 'already loaded'
48 assert em.load_extension('ext1') == 'already loaded'
49
49
50 # Reload
50 # Reload
51 with tt.AssertPrints("Running ext1 unload"):
51 with tt.AssertPrints("Running ext1 unload"):
52 with tt.AssertPrints("Running ext1 load", suppress=False):
52 with tt.AssertPrints("Running ext1 load", suppress=False):
53 em.reload_extension('ext1')
53 em.reload_extension('ext1')
54
54
55 # Unload
55 # Unload
56 with tt.AssertPrints("Running ext1 unload"):
56 with tt.AssertPrints("Running ext1 unload"):
57 assert em.unload_extension('ext1') is None
57 assert em.unload_extension('ext1') is None
58
58
59 # Can't unload again
59 # Can't unload again
60 with tt.AssertNotPrints("Running ext1 unload"):
60 with tt.AssertNotPrints("Running ext1 unload"):
61 assert em.unload_extension('ext1') == 'not loaded'
61 assert em.unload_extension('ext1') == 'not loaded'
62 assert em.unload_extension('ext2') == 'not loaded'
62 assert em.unload_extension('ext2') == 'not loaded'
63
63
64 # Load extension 2
64 # Load extension 2
65 with tt.AssertPrints("Running ext2 load"):
65 with tt.AssertPrints("Running ext2 load"):
66 assert em.load_extension('ext2') is None
66 assert em.load_extension('ext2') is None
67
67
68 # Can't unload this
68 # Can't unload this
69 assert em.unload_extension('ext2') == 'no unload function'
69 assert em.unload_extension('ext2') == 'no unload function'
70
70
71 # But can reload it
71 # But can reload it
72 with tt.AssertPrints("Running ext2 load"):
72 with tt.AssertPrints("Running ext2 load"):
73 em.reload_extension('ext2')
73 em.reload_extension('ext2')
74
74
75
75
76 def test_extension_builtins():
76 def test_extension_builtins():
77 em = get_ipython().extension_manager
77 em = get_ipython().extension_manager
78 with TemporaryDirectory() as td:
78 with TemporaryDirectory() as td:
79 ext3 = os.path.join(td, 'ext3.py')
79 ext3 = os.path.join(td, "ext3.py")
80 with open(ext3, 'w', encoding='utf-8') as f:
80 with open(ext3, "w", encoding="utf-8") as f:
81 f.write(ext3_content)
81 f.write(ext3_content)
82
82
83 assert 'ext3' not in em.loaded
83 assert 'ext3' not in em.loaded
84
84
85 with prepended_to_syspath(td):
85 with prepended_to_syspath(td):
86 # Load extension
86 # Load extension
87 with tt.AssertPrints("True"):
87 with tt.AssertPrints("True"):
88 assert em.load_extension('ext3') is None
88 assert em.load_extension('ext3') is None
89 assert 'ext3' in em.loaded
89 assert 'ext3' in em.loaded
90
90
91
91
92 def test_non_extension():
92 def test_non_extension():
93 em = get_ipython().extension_manager
93 em = get_ipython().extension_manager
94 assert em.load_extension("sys") == "no load function"
94 assert em.load_extension("sys") == "no load function"
@@ -1,1098 +1,1100 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for the key interactiveshell module.
2 """Tests for the key interactiveshell module.
3
3
4 Historically the main classes in interactiveshell have been under-tested. This
4 Historically the main classes in interactiveshell have been under-tested. This
5 module should grow as many single-method tests as possible to trap many of the
5 module should grow as many single-method tests as possible to trap many of the
6 recurring bugs we seem to encounter with high-level interaction.
6 recurring bugs we seem to encounter with high-level interaction.
7 """
7 """
8
8
9 # Copyright (c) IPython Development Team.
9 # Copyright (c) IPython Development Team.
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11
11
12 import asyncio
12 import asyncio
13 import ast
13 import ast
14 import os
14 import os
15 import signal
15 import signal
16 import shutil
16 import shutil
17 import sys
17 import sys
18 import tempfile
18 import tempfile
19 import unittest
19 import unittest
20 from unittest import mock
20 from unittest import mock
21
21
22 from os.path import join
22 from os.path import join
23
23
24 from IPython.core.error import InputRejected
24 from IPython.core.error import InputRejected
25 from IPython.core.inputtransformer import InputTransformer
25 from IPython.core.inputtransformer import InputTransformer
26 from IPython.core import interactiveshell
26 from IPython.core import interactiveshell
27 from IPython.testing.decorators import (
27 from IPython.testing.decorators import (
28 skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist,
28 skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist,
29 )
29 )
30 from IPython.testing import tools as tt
30 from IPython.testing import tools as tt
31 from IPython.utils.process import find_cmd
31 from IPython.utils.process import find_cmd
32
32
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34 # Globals
34 # Globals
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # This is used by every single test, no point repeating it ad nauseam
36 # This is used by every single test, no point repeating it ad nauseam
37
37
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39 # Tests
39 # Tests
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41
41
42 class DerivedInterrupt(KeyboardInterrupt):
42 class DerivedInterrupt(KeyboardInterrupt):
43 pass
43 pass
44
44
45 class InteractiveShellTestCase(unittest.TestCase):
45 class InteractiveShellTestCase(unittest.TestCase):
46 def test_naked_string_cells(self):
46 def test_naked_string_cells(self):
47 """Test that cells with only naked strings are fully executed"""
47 """Test that cells with only naked strings are fully executed"""
48 # First, single-line inputs
48 # First, single-line inputs
49 ip.run_cell('"a"\n')
49 ip.run_cell('"a"\n')
50 self.assertEqual(ip.user_ns['_'], 'a')
50 self.assertEqual(ip.user_ns['_'], 'a')
51 # And also multi-line cells
51 # And also multi-line cells
52 ip.run_cell('"""a\nb"""\n')
52 ip.run_cell('"""a\nb"""\n')
53 self.assertEqual(ip.user_ns['_'], 'a\nb')
53 self.assertEqual(ip.user_ns['_'], 'a\nb')
54
54
55 def test_run_empty_cell(self):
55 def test_run_empty_cell(self):
56 """Just make sure we don't get a horrible error with a blank
56 """Just make sure we don't get a horrible error with a blank
57 cell of input. Yes, I did overlook that."""
57 cell of input. Yes, I did overlook that."""
58 old_xc = ip.execution_count
58 old_xc = ip.execution_count
59 res = ip.run_cell('')
59 res = ip.run_cell('')
60 self.assertEqual(ip.execution_count, old_xc)
60 self.assertEqual(ip.execution_count, old_xc)
61 self.assertEqual(res.execution_count, None)
61 self.assertEqual(res.execution_count, None)
62
62
63 def test_run_cell_multiline(self):
63 def test_run_cell_multiline(self):
64 """Multi-block, multi-line cells must execute correctly.
64 """Multi-block, multi-line cells must execute correctly.
65 """
65 """
66 src = '\n'.join(["x=1",
66 src = '\n'.join(["x=1",
67 "y=2",
67 "y=2",
68 "if 1:",
68 "if 1:",
69 " x += 1",
69 " x += 1",
70 " y += 1",])
70 " y += 1",])
71 res = ip.run_cell(src)
71 res = ip.run_cell(src)
72 self.assertEqual(ip.user_ns['x'], 2)
72 self.assertEqual(ip.user_ns['x'], 2)
73 self.assertEqual(ip.user_ns['y'], 3)
73 self.assertEqual(ip.user_ns['y'], 3)
74 self.assertEqual(res.success, True)
74 self.assertEqual(res.success, True)
75 self.assertEqual(res.result, None)
75 self.assertEqual(res.result, None)
76
76
77 def test_multiline_string_cells(self):
77 def test_multiline_string_cells(self):
78 "Code sprinkled with multiline strings should execute (GH-306)"
78 "Code sprinkled with multiline strings should execute (GH-306)"
79 ip.run_cell('tmp=0')
79 ip.run_cell('tmp=0')
80 self.assertEqual(ip.user_ns['tmp'], 0)
80 self.assertEqual(ip.user_ns['tmp'], 0)
81 res = ip.run_cell('tmp=1;"""a\nb"""\n')
81 res = ip.run_cell('tmp=1;"""a\nb"""\n')
82 self.assertEqual(ip.user_ns['tmp'], 1)
82 self.assertEqual(ip.user_ns['tmp'], 1)
83 self.assertEqual(res.success, True)
83 self.assertEqual(res.success, True)
84 self.assertEqual(res.result, "a\nb")
84 self.assertEqual(res.result, "a\nb")
85
85
86 def test_dont_cache_with_semicolon(self):
86 def test_dont_cache_with_semicolon(self):
87 "Ending a line with semicolon should not cache the returned object (GH-307)"
87 "Ending a line with semicolon should not cache the returned object (GH-307)"
88 oldlen = len(ip.user_ns['Out'])
88 oldlen = len(ip.user_ns['Out'])
89 for cell in ['1;', '1;1;']:
89 for cell in ['1;', '1;1;']:
90 res = ip.run_cell(cell, store_history=True)
90 res = ip.run_cell(cell, store_history=True)
91 newlen = len(ip.user_ns['Out'])
91 newlen = len(ip.user_ns['Out'])
92 self.assertEqual(oldlen, newlen)
92 self.assertEqual(oldlen, newlen)
93 self.assertIsNone(res.result)
93 self.assertIsNone(res.result)
94 i = 0
94 i = 0
95 #also test the default caching behavior
95 #also test the default caching behavior
96 for cell in ['1', '1;1']:
96 for cell in ['1', '1;1']:
97 ip.run_cell(cell, store_history=True)
97 ip.run_cell(cell, store_history=True)
98 newlen = len(ip.user_ns['Out'])
98 newlen = len(ip.user_ns['Out'])
99 i += 1
99 i += 1
100 self.assertEqual(oldlen+i, newlen)
100 self.assertEqual(oldlen+i, newlen)
101
101
102 def test_syntax_error(self):
102 def test_syntax_error(self):
103 res = ip.run_cell("raise = 3")
103 res = ip.run_cell("raise = 3")
104 self.assertIsInstance(res.error_before_exec, SyntaxError)
104 self.assertIsInstance(res.error_before_exec, SyntaxError)
105
105
106 def test_In_variable(self):
106 def test_In_variable(self):
107 "Verify that In variable grows with user input (GH-284)"
107 "Verify that In variable grows with user input (GH-284)"
108 oldlen = len(ip.user_ns['In'])
108 oldlen = len(ip.user_ns['In'])
109 ip.run_cell('1;', store_history=True)
109 ip.run_cell('1;', store_history=True)
110 newlen = len(ip.user_ns['In'])
110 newlen = len(ip.user_ns['In'])
111 self.assertEqual(oldlen+1, newlen)
111 self.assertEqual(oldlen+1, newlen)
112 self.assertEqual(ip.user_ns['In'][-1],'1;')
112 self.assertEqual(ip.user_ns['In'][-1],'1;')
113
113
114 def test_magic_names_in_string(self):
114 def test_magic_names_in_string(self):
115 ip.run_cell('a = """\n%exit\n"""')
115 ip.run_cell('a = """\n%exit\n"""')
116 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
116 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
117
117
118 def test_trailing_newline(self):
118 def test_trailing_newline(self):
119 """test that running !(command) does not raise a SyntaxError"""
119 """test that running !(command) does not raise a SyntaxError"""
120 ip.run_cell('!(true)\n', False)
120 ip.run_cell('!(true)\n', False)
121 ip.run_cell('!(true)\n\n\n', False)
121 ip.run_cell('!(true)\n\n\n', False)
122
122
123 def test_gh_597(self):
123 def test_gh_597(self):
124 """Pretty-printing lists of objects with non-ascii reprs may cause
124 """Pretty-printing lists of objects with non-ascii reprs may cause
125 problems."""
125 problems."""
126 class Spam(object):
126 class Spam(object):
127 def __repr__(self):
127 def __repr__(self):
128 return "\xe9"*50
128 return "\xe9"*50
129 import IPython.core.formatters
129 import IPython.core.formatters
130 f = IPython.core.formatters.PlainTextFormatter()
130 f = IPython.core.formatters.PlainTextFormatter()
131 f([Spam(),Spam()])
131 f([Spam(),Spam()])
132
132
133
133
134 def test_future_flags(self):
134 def test_future_flags(self):
135 """Check that future flags are used for parsing code (gh-777)"""
135 """Check that future flags are used for parsing code (gh-777)"""
136 ip.run_cell('from __future__ import barry_as_FLUFL')
136 ip.run_cell('from __future__ import barry_as_FLUFL')
137 try:
137 try:
138 ip.run_cell('prfunc_return_val = 1 <> 2')
138 ip.run_cell('prfunc_return_val = 1 <> 2')
139 assert 'prfunc_return_val' in ip.user_ns
139 assert 'prfunc_return_val' in ip.user_ns
140 finally:
140 finally:
141 # Reset compiler flags so we don't mess up other tests.
141 # Reset compiler flags so we don't mess up other tests.
142 ip.compile.reset_compiler_flags()
142 ip.compile.reset_compiler_flags()
143
143
144 def test_can_pickle(self):
144 def test_can_pickle(self):
145 "Can we pickle objects defined interactively (GH-29)"
145 "Can we pickle objects defined interactively (GH-29)"
146 ip = get_ipython()
146 ip = get_ipython()
147 ip.reset()
147 ip.reset()
148 ip.run_cell(("class Mylist(list):\n"
148 ip.run_cell(("class Mylist(list):\n"
149 " def __init__(self,x=[]):\n"
149 " def __init__(self,x=[]):\n"
150 " list.__init__(self,x)"))
150 " list.__init__(self,x)"))
151 ip.run_cell("w=Mylist([1,2,3])")
151 ip.run_cell("w=Mylist([1,2,3])")
152
152
153 from pickle import dumps
153 from pickle import dumps
154
154
155 # We need to swap in our main module - this is only necessary
155 # We need to swap in our main module - this is only necessary
156 # inside the test framework, because IPython puts the interactive module
156 # inside the test framework, because IPython puts the interactive module
157 # in place (but the test framework undoes this).
157 # in place (but the test framework undoes this).
158 _main = sys.modules['__main__']
158 _main = sys.modules['__main__']
159 sys.modules['__main__'] = ip.user_module
159 sys.modules['__main__'] = ip.user_module
160 try:
160 try:
161 res = dumps(ip.user_ns["w"])
161 res = dumps(ip.user_ns["w"])
162 finally:
162 finally:
163 sys.modules['__main__'] = _main
163 sys.modules['__main__'] = _main
164 self.assertTrue(isinstance(res, bytes))
164 self.assertTrue(isinstance(res, bytes))
165
165
166 def test_global_ns(self):
166 def test_global_ns(self):
167 "Code in functions must be able to access variables outside them."
167 "Code in functions must be able to access variables outside them."
168 ip = get_ipython()
168 ip = get_ipython()
169 ip.run_cell("a = 10")
169 ip.run_cell("a = 10")
170 ip.run_cell(("def f(x):\n"
170 ip.run_cell(("def f(x):\n"
171 " return x + a"))
171 " return x + a"))
172 ip.run_cell("b = f(12)")
172 ip.run_cell("b = f(12)")
173 self.assertEqual(ip.user_ns["b"], 22)
173 self.assertEqual(ip.user_ns["b"], 22)
174
174
175 def test_bad_custom_tb(self):
175 def test_bad_custom_tb(self):
176 """Check that InteractiveShell is protected from bad custom exception handlers"""
176 """Check that InteractiveShell is protected from bad custom exception handlers"""
177 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
177 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
178 self.assertEqual(ip.custom_exceptions, (IOError,))
178 self.assertEqual(ip.custom_exceptions, (IOError,))
179 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
179 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
180 ip.run_cell(u'raise IOError("foo")')
180 ip.run_cell(u'raise IOError("foo")')
181 self.assertEqual(ip.custom_exceptions, ())
181 self.assertEqual(ip.custom_exceptions, ())
182
182
183 def test_bad_custom_tb_return(self):
183 def test_bad_custom_tb_return(self):
184 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
184 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
185 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
185 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
186 self.assertEqual(ip.custom_exceptions, (NameError,))
186 self.assertEqual(ip.custom_exceptions, (NameError,))
187 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
187 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
188 ip.run_cell(u'a=abracadabra')
188 ip.run_cell(u'a=abracadabra')
189 self.assertEqual(ip.custom_exceptions, ())
189 self.assertEqual(ip.custom_exceptions, ())
190
190
191 def test_drop_by_id(self):
191 def test_drop_by_id(self):
192 myvars = {"a":object(), "b":object(), "c": object()}
192 myvars = {"a":object(), "b":object(), "c": object()}
193 ip.push(myvars, interactive=False)
193 ip.push(myvars, interactive=False)
194 for name in myvars:
194 for name in myvars:
195 assert name in ip.user_ns, name
195 assert name in ip.user_ns, name
196 assert name in ip.user_ns_hidden, name
196 assert name in ip.user_ns_hidden, name
197 ip.user_ns['b'] = 12
197 ip.user_ns['b'] = 12
198 ip.drop_by_id(myvars)
198 ip.drop_by_id(myvars)
199 for name in ["a", "c"]:
199 for name in ["a", "c"]:
200 assert name not in ip.user_ns, name
200 assert name not in ip.user_ns, name
201 assert name not in ip.user_ns_hidden, name
201 assert name not in ip.user_ns_hidden, name
202 assert ip.user_ns['b'] == 12
202 assert ip.user_ns['b'] == 12
203 ip.reset()
203 ip.reset()
204
204
205 def test_var_expand(self):
205 def test_var_expand(self):
206 ip.user_ns['f'] = u'Ca\xf1o'
206 ip.user_ns['f'] = u'Ca\xf1o'
207 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
207 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
208 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
208 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
209 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
209 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
210 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
210 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
211
211
212 self.assertEqual(ip.var_expand(u"grep x | awk '{print $1}'"), u"grep x | awk '{print $1}'")
212 self.assertEqual(ip.var_expand(u"grep x | awk '{print $1}'"), u"grep x | awk '{print $1}'")
213
213
214 ip.user_ns['f'] = b'Ca\xc3\xb1o'
214 ip.user_ns['f'] = b'Ca\xc3\xb1o'
215 # This should not raise any exception:
215 # This should not raise any exception:
216 ip.var_expand(u'echo $f')
216 ip.var_expand(u'echo $f')
217
217
218 def test_var_expand_local(self):
218 def test_var_expand_local(self):
219 """Test local variable expansion in !system and %magic calls"""
219 """Test local variable expansion in !system and %magic calls"""
220 # !system
220 # !system
221 ip.run_cell(
221 ip.run_cell(
222 "def test():\n"
222 "def test():\n"
223 ' lvar = "ttt"\n'
223 ' lvar = "ttt"\n'
224 " ret = !echo {lvar}\n"
224 " ret = !echo {lvar}\n"
225 " return ret[0]\n"
225 " return ret[0]\n"
226 )
226 )
227 res = ip.user_ns["test"]()
227 res = ip.user_ns["test"]()
228 self.assertIn("ttt", res)
228 self.assertIn("ttt", res)
229
229
230 # %magic
230 # %magic
231 ip.run_cell(
231 ip.run_cell(
232 "def makemacro():\n"
232 "def makemacro():\n"
233 ' macroname = "macro_var_expand_locals"\n'
233 ' macroname = "macro_var_expand_locals"\n'
234 " %macro {macroname} codestr\n"
234 " %macro {macroname} codestr\n"
235 )
235 )
236 ip.user_ns["codestr"] = "str(12)"
236 ip.user_ns["codestr"] = "str(12)"
237 ip.run_cell("makemacro()")
237 ip.run_cell("makemacro()")
238 self.assertIn("macro_var_expand_locals", ip.user_ns)
238 self.assertIn("macro_var_expand_locals", ip.user_ns)
239
239
240 def test_var_expand_self(self):
240 def test_var_expand_self(self):
241 """Test variable expansion with the name 'self', which was failing.
241 """Test variable expansion with the name 'self', which was failing.
242
242
243 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
243 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
244 """
244 """
245 ip.run_cell(
245 ip.run_cell(
246 "class cTest:\n"
246 "class cTest:\n"
247 ' classvar="see me"\n'
247 ' classvar="see me"\n'
248 " def test(self):\n"
248 " def test(self):\n"
249 " res = !echo Variable: {self.classvar}\n"
249 " res = !echo Variable: {self.classvar}\n"
250 " return res[0]\n"
250 " return res[0]\n"
251 )
251 )
252 self.assertIn("see me", ip.user_ns["cTest"]().test())
252 self.assertIn("see me", ip.user_ns["cTest"]().test())
253
253
254 def test_bad_var_expand(self):
254 def test_bad_var_expand(self):
255 """var_expand on invalid formats shouldn't raise"""
255 """var_expand on invalid formats shouldn't raise"""
256 # SyntaxError
256 # SyntaxError
257 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
257 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
258 # NameError
258 # NameError
259 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
259 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
260 # ZeroDivisionError
260 # ZeroDivisionError
261 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
261 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
262
262
263 def test_silent_postexec(self):
263 def test_silent_postexec(self):
264 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
264 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
265 pre_explicit = mock.Mock()
265 pre_explicit = mock.Mock()
266 pre_always = mock.Mock()
266 pre_always = mock.Mock()
267 post_explicit = mock.Mock()
267 post_explicit = mock.Mock()
268 post_always = mock.Mock()
268 post_always = mock.Mock()
269 all_mocks = [pre_explicit, pre_always, post_explicit, post_always]
269 all_mocks = [pre_explicit, pre_always, post_explicit, post_always]
270
270
271 ip.events.register('pre_run_cell', pre_explicit)
271 ip.events.register('pre_run_cell', pre_explicit)
272 ip.events.register('pre_execute', pre_always)
272 ip.events.register('pre_execute', pre_always)
273 ip.events.register('post_run_cell', post_explicit)
273 ip.events.register('post_run_cell', post_explicit)
274 ip.events.register('post_execute', post_always)
274 ip.events.register('post_execute', post_always)
275
275
276 try:
276 try:
277 ip.run_cell("1", silent=True)
277 ip.run_cell("1", silent=True)
278 assert pre_always.called
278 assert pre_always.called
279 assert not pre_explicit.called
279 assert not pre_explicit.called
280 assert post_always.called
280 assert post_always.called
281 assert not post_explicit.called
281 assert not post_explicit.called
282 # double-check that non-silent exec did what we expected
282 # double-check that non-silent exec did what we expected
283 # silent to avoid
283 # silent to avoid
284 ip.run_cell("1")
284 ip.run_cell("1")
285 assert pre_explicit.called
285 assert pre_explicit.called
286 assert post_explicit.called
286 assert post_explicit.called
287 info, = pre_explicit.call_args[0]
287 info, = pre_explicit.call_args[0]
288 result, = post_explicit.call_args[0]
288 result, = post_explicit.call_args[0]
289 self.assertEqual(info, result.info)
289 self.assertEqual(info, result.info)
290 # check that post hooks are always called
290 # check that post hooks are always called
291 [m.reset_mock() for m in all_mocks]
291 [m.reset_mock() for m in all_mocks]
292 ip.run_cell("syntax error")
292 ip.run_cell("syntax error")
293 assert pre_always.called
293 assert pre_always.called
294 assert pre_explicit.called
294 assert pre_explicit.called
295 assert post_always.called
295 assert post_always.called
296 assert post_explicit.called
296 assert post_explicit.called
297 info, = pre_explicit.call_args[0]
297 info, = pre_explicit.call_args[0]
298 result, = post_explicit.call_args[0]
298 result, = post_explicit.call_args[0]
299 self.assertEqual(info, result.info)
299 self.assertEqual(info, result.info)
300 finally:
300 finally:
301 # remove post-exec
301 # remove post-exec
302 ip.events.unregister('pre_run_cell', pre_explicit)
302 ip.events.unregister('pre_run_cell', pre_explicit)
303 ip.events.unregister('pre_execute', pre_always)
303 ip.events.unregister('pre_execute', pre_always)
304 ip.events.unregister('post_run_cell', post_explicit)
304 ip.events.unregister('post_run_cell', post_explicit)
305 ip.events.unregister('post_execute', post_always)
305 ip.events.unregister('post_execute', post_always)
306
306
307 def test_silent_noadvance(self):
307 def test_silent_noadvance(self):
308 """run_cell(silent=True) doesn't advance execution_count"""
308 """run_cell(silent=True) doesn't advance execution_count"""
309 ec = ip.execution_count
309 ec = ip.execution_count
310 # silent should force store_history=False
310 # silent should force store_history=False
311 ip.run_cell("1", store_history=True, silent=True)
311 ip.run_cell("1", store_history=True, silent=True)
312
312
313 self.assertEqual(ec, ip.execution_count)
313 self.assertEqual(ec, ip.execution_count)
314 # double-check that non-silent exec did what we expected
314 # double-check that non-silent exec did what we expected
315 # silent to avoid
315 # silent to avoid
316 ip.run_cell("1", store_history=True)
316 ip.run_cell("1", store_history=True)
317 self.assertEqual(ec+1, ip.execution_count)
317 self.assertEqual(ec+1, ip.execution_count)
318
318
319 def test_silent_nodisplayhook(self):
319 def test_silent_nodisplayhook(self):
320 """run_cell(silent=True) doesn't trigger displayhook"""
320 """run_cell(silent=True) doesn't trigger displayhook"""
321 d = dict(called=False)
321 d = dict(called=False)
322
322
323 trap = ip.display_trap
323 trap = ip.display_trap
324 save_hook = trap.hook
324 save_hook = trap.hook
325
325
326 def failing_hook(*args, **kwargs):
326 def failing_hook(*args, **kwargs):
327 d['called'] = True
327 d['called'] = True
328
328
329 try:
329 try:
330 trap.hook = failing_hook
330 trap.hook = failing_hook
331 res = ip.run_cell("1", silent=True)
331 res = ip.run_cell("1", silent=True)
332 self.assertFalse(d['called'])
332 self.assertFalse(d['called'])
333 self.assertIsNone(res.result)
333 self.assertIsNone(res.result)
334 # double-check that non-silent exec did what we expected
334 # double-check that non-silent exec did what we expected
335 # silent to avoid
335 # silent to avoid
336 ip.run_cell("1")
336 ip.run_cell("1")
337 self.assertTrue(d['called'])
337 self.assertTrue(d['called'])
338 finally:
338 finally:
339 trap.hook = save_hook
339 trap.hook = save_hook
340
340
341 def test_ofind_line_magic(self):
341 def test_ofind_line_magic(self):
342 from IPython.core.magic import register_line_magic
342 from IPython.core.magic import register_line_magic
343
343
344 @register_line_magic
344 @register_line_magic
345 def lmagic(line):
345 def lmagic(line):
346 "A line magic"
346 "A line magic"
347
347
348 # Get info on line magic
348 # Get info on line magic
349 lfind = ip._ofind("lmagic")
349 lfind = ip._ofind("lmagic")
350 info = dict(
350 info = dict(
351 found=True,
351 found=True,
352 isalias=False,
352 isalias=False,
353 ismagic=True,
353 ismagic=True,
354 namespace="IPython internal",
354 namespace="IPython internal",
355 obj=lmagic,
355 obj=lmagic,
356 parent=None,
356 parent=None,
357 )
357 )
358 self.assertEqual(lfind, info)
358 self.assertEqual(lfind, info)
359
359
360 def test_ofind_cell_magic(self):
360 def test_ofind_cell_magic(self):
361 from IPython.core.magic import register_cell_magic
361 from IPython.core.magic import register_cell_magic
362
362
363 @register_cell_magic
363 @register_cell_magic
364 def cmagic(line, cell):
364 def cmagic(line, cell):
365 "A cell magic"
365 "A cell magic"
366
366
367 # Get info on cell magic
367 # Get info on cell magic
368 find = ip._ofind("cmagic")
368 find = ip._ofind("cmagic")
369 info = dict(
369 info = dict(
370 found=True,
370 found=True,
371 isalias=False,
371 isalias=False,
372 ismagic=True,
372 ismagic=True,
373 namespace="IPython internal",
373 namespace="IPython internal",
374 obj=cmagic,
374 obj=cmagic,
375 parent=None,
375 parent=None,
376 )
376 )
377 self.assertEqual(find, info)
377 self.assertEqual(find, info)
378
378
379 def test_ofind_property_with_error(self):
379 def test_ofind_property_with_error(self):
380 class A(object):
380 class A(object):
381 @property
381 @property
382 def foo(self):
382 def foo(self):
383 raise NotImplementedError()
383 raise NotImplementedError()
384 a = A()
384 a = A()
385
385
386 found = ip._ofind('a.foo', [('locals', locals())])
386 found = ip._ofind('a.foo', [('locals', locals())])
387 info = dict(found=True, isalias=False, ismagic=False,
387 info = dict(found=True, isalias=False, ismagic=False,
388 namespace='locals', obj=A.foo, parent=a)
388 namespace='locals', obj=A.foo, parent=a)
389 self.assertEqual(found, info)
389 self.assertEqual(found, info)
390
390
391 def test_ofind_multiple_attribute_lookups(self):
391 def test_ofind_multiple_attribute_lookups(self):
392 class A(object):
392 class A(object):
393 @property
393 @property
394 def foo(self):
394 def foo(self):
395 raise NotImplementedError()
395 raise NotImplementedError()
396
396
397 a = A()
397 a = A()
398 a.a = A()
398 a.a = A()
399 a.a.a = A()
399 a.a.a = A()
400
400
401 found = ip._ofind('a.a.a.foo', [('locals', locals())])
401 found = ip._ofind('a.a.a.foo', [('locals', locals())])
402 info = dict(found=True, isalias=False, ismagic=False,
402 info = dict(found=True, isalias=False, ismagic=False,
403 namespace='locals', obj=A.foo, parent=a.a.a)
403 namespace='locals', obj=A.foo, parent=a.a.a)
404 self.assertEqual(found, info)
404 self.assertEqual(found, info)
405
405
406 def test_ofind_slotted_attributes(self):
406 def test_ofind_slotted_attributes(self):
407 class A(object):
407 class A(object):
408 __slots__ = ['foo']
408 __slots__ = ['foo']
409 def __init__(self):
409 def __init__(self):
410 self.foo = 'bar'
410 self.foo = 'bar'
411
411
412 a = A()
412 a = A()
413 found = ip._ofind('a.foo', [('locals', locals())])
413 found = ip._ofind('a.foo', [('locals', locals())])
414 info = dict(found=True, isalias=False, ismagic=False,
414 info = dict(found=True, isalias=False, ismagic=False,
415 namespace='locals', obj=a.foo, parent=a)
415 namespace='locals', obj=a.foo, parent=a)
416 self.assertEqual(found, info)
416 self.assertEqual(found, info)
417
417
418 found = ip._ofind('a.bar', [('locals', locals())])
418 found = ip._ofind('a.bar', [('locals', locals())])
419 info = dict(found=False, isalias=False, ismagic=False,
419 info = dict(found=False, isalias=False, ismagic=False,
420 namespace=None, obj=None, parent=a)
420 namespace=None, obj=None, parent=a)
421 self.assertEqual(found, info)
421 self.assertEqual(found, info)
422
422
423 def test_ofind_prefers_property_to_instance_level_attribute(self):
423 def test_ofind_prefers_property_to_instance_level_attribute(self):
424 class A(object):
424 class A(object):
425 @property
425 @property
426 def foo(self):
426 def foo(self):
427 return 'bar'
427 return 'bar'
428 a = A()
428 a = A()
429 a.__dict__["foo"] = "baz"
429 a.__dict__["foo"] = "baz"
430 self.assertEqual(a.foo, "bar")
430 self.assertEqual(a.foo, "bar")
431 found = ip._ofind("a.foo", [("locals", locals())])
431 found = ip._ofind("a.foo", [("locals", locals())])
432 self.assertIs(found["obj"], A.foo)
432 self.assertIs(found["obj"], A.foo)
433
433
434 def test_custom_syntaxerror_exception(self):
434 def test_custom_syntaxerror_exception(self):
435 called = []
435 called = []
436 def my_handler(shell, etype, value, tb, tb_offset=None):
436 def my_handler(shell, etype, value, tb, tb_offset=None):
437 called.append(etype)
437 called.append(etype)
438 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
438 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
439
439
440 ip.set_custom_exc((SyntaxError,), my_handler)
440 ip.set_custom_exc((SyntaxError,), my_handler)
441 try:
441 try:
442 ip.run_cell("1f")
442 ip.run_cell("1f")
443 # Check that this was called, and only once.
443 # Check that this was called, and only once.
444 self.assertEqual(called, [SyntaxError])
444 self.assertEqual(called, [SyntaxError])
445 finally:
445 finally:
446 # Reset the custom exception hook
446 # Reset the custom exception hook
447 ip.set_custom_exc((), None)
447 ip.set_custom_exc((), None)
448
448
449 def test_custom_exception(self):
449 def test_custom_exception(self):
450 called = []
450 called = []
451 def my_handler(shell, etype, value, tb, tb_offset=None):
451 def my_handler(shell, etype, value, tb, tb_offset=None):
452 called.append(etype)
452 called.append(etype)
453 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
453 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
454
454
455 ip.set_custom_exc((ValueError,), my_handler)
455 ip.set_custom_exc((ValueError,), my_handler)
456 try:
456 try:
457 res = ip.run_cell("raise ValueError('test')")
457 res = ip.run_cell("raise ValueError('test')")
458 # Check that this was called, and only once.
458 # Check that this was called, and only once.
459 self.assertEqual(called, [ValueError])
459 self.assertEqual(called, [ValueError])
460 # Check that the error is on the result object
460 # Check that the error is on the result object
461 self.assertIsInstance(res.error_in_exec, ValueError)
461 self.assertIsInstance(res.error_in_exec, ValueError)
462 finally:
462 finally:
463 # Reset the custom exception hook
463 # Reset the custom exception hook
464 ip.set_custom_exc((), None)
464 ip.set_custom_exc((), None)
465
465
466 @mock.patch("builtins.print")
466 @mock.patch("builtins.print")
467 def test_showtraceback_with_surrogates(self, mocked_print):
467 def test_showtraceback_with_surrogates(self, mocked_print):
468 values = []
468 values = []
469
469
470 def mock_print_func(value, sep=" ", end="\n", file=sys.stdout, flush=False):
470 def mock_print_func(value, sep=" ", end="\n", file=sys.stdout, flush=False):
471 values.append(value)
471 values.append(value)
472 if value == chr(0xD8FF):
472 if value == chr(0xD8FF):
473 raise UnicodeEncodeError("utf-8", chr(0xD8FF), 0, 1, "")
473 raise UnicodeEncodeError("utf-8", chr(0xD8FF), 0, 1, "")
474
474
475 # mock builtins.print
475 # mock builtins.print
476 mocked_print.side_effect = mock_print_func
476 mocked_print.side_effect = mock_print_func
477
477
478 # ip._showtraceback() is replaced in globalipapp.py.
478 # ip._showtraceback() is replaced in globalipapp.py.
479 # Call original method to test.
479 # Call original method to test.
480 interactiveshell.InteractiveShell._showtraceback(ip, None, None, chr(0xD8FF))
480 interactiveshell.InteractiveShell._showtraceback(ip, None, None, chr(0xD8FF))
481
481
482 self.assertEqual(mocked_print.call_count, 2)
482 self.assertEqual(mocked_print.call_count, 2)
483 self.assertEqual(values, [chr(0xD8FF), "\\ud8ff"])
483 self.assertEqual(values, [chr(0xD8FF), "\\ud8ff"])
484
484
485 def test_mktempfile(self):
485 def test_mktempfile(self):
486 filename = ip.mktempfile()
486 filename = ip.mktempfile()
487 # Check that we can open the file again on Windows
487 # Check that we can open the file again on Windows
488 with open(filename, 'w', encoding='utf-8') as f:
488 with open(filename, "w", encoding="utf-8") as f:
489 f.write('abc')
489 f.write("abc")
490
490
491 filename = ip.mktempfile(data='blah')
491 filename = ip.mktempfile(data="blah")
492 with open(filename, 'r', encoding='utf-8') as f:
492 with open(filename, "r", encoding="utf-8") as f:
493 self.assertEqual(f.read(), 'blah')
493 self.assertEqual(f.read(), "blah")
494
494
495 def test_new_main_mod(self):
495 def test_new_main_mod(self):
496 # Smoketest to check that this accepts a unicode module name
496 # Smoketest to check that this accepts a unicode module name
497 name = u'jiefmw'
497 name = u'jiefmw'
498 mod = ip.new_main_mod(u'%s.py' % name, name)
498 mod = ip.new_main_mod(u'%s.py' % name, name)
499 self.assertEqual(mod.__name__, name)
499 self.assertEqual(mod.__name__, name)
500
500
501 def test_get_exception_only(self):
501 def test_get_exception_only(self):
502 try:
502 try:
503 raise KeyboardInterrupt
503 raise KeyboardInterrupt
504 except KeyboardInterrupt:
504 except KeyboardInterrupt:
505 msg = ip.get_exception_only()
505 msg = ip.get_exception_only()
506 self.assertEqual(msg, 'KeyboardInterrupt\n')
506 self.assertEqual(msg, 'KeyboardInterrupt\n')
507
507
508 try:
508 try:
509 raise DerivedInterrupt("foo")
509 raise DerivedInterrupt("foo")
510 except KeyboardInterrupt:
510 except KeyboardInterrupt:
511 msg = ip.get_exception_only()
511 msg = ip.get_exception_only()
512 self.assertEqual(msg, 'IPython.core.tests.test_interactiveshell.DerivedInterrupt: foo\n')
512 self.assertEqual(msg, 'IPython.core.tests.test_interactiveshell.DerivedInterrupt: foo\n')
513
513
514 def test_inspect_text(self):
514 def test_inspect_text(self):
515 ip.run_cell('a = 5')
515 ip.run_cell('a = 5')
516 text = ip.object_inspect_text('a')
516 text = ip.object_inspect_text('a')
517 self.assertIsInstance(text, str)
517 self.assertIsInstance(text, str)
518
518
519 def test_last_execution_result(self):
519 def test_last_execution_result(self):
520 """ Check that last execution result gets set correctly (GH-10702) """
520 """ Check that last execution result gets set correctly (GH-10702) """
521 result = ip.run_cell('a = 5; a')
521 result = ip.run_cell('a = 5; a')
522 self.assertTrue(ip.last_execution_succeeded)
522 self.assertTrue(ip.last_execution_succeeded)
523 self.assertEqual(ip.last_execution_result.result, 5)
523 self.assertEqual(ip.last_execution_result.result, 5)
524
524
525 result = ip.run_cell('a = x_invalid_id_x')
525 result = ip.run_cell('a = x_invalid_id_x')
526 self.assertFalse(ip.last_execution_succeeded)
526 self.assertFalse(ip.last_execution_succeeded)
527 self.assertFalse(ip.last_execution_result.success)
527 self.assertFalse(ip.last_execution_result.success)
528 self.assertIsInstance(ip.last_execution_result.error_in_exec, NameError)
528 self.assertIsInstance(ip.last_execution_result.error_in_exec, NameError)
529
529
530 def test_reset_aliasing(self):
530 def test_reset_aliasing(self):
531 """ Check that standard posix aliases work after %reset. """
531 """ Check that standard posix aliases work after %reset. """
532 if os.name != 'posix':
532 if os.name != 'posix':
533 return
533 return
534
534
535 ip.reset()
535 ip.reset()
536 for cmd in ('clear', 'more', 'less', 'man'):
536 for cmd in ('clear', 'more', 'less', 'man'):
537 res = ip.run_cell('%' + cmd)
537 res = ip.run_cell('%' + cmd)
538 self.assertEqual(res.success, True)
538 self.assertEqual(res.success, True)
539
539
540
540
541 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
541 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
542
542
543 @onlyif_unicode_paths
543 @onlyif_unicode_paths
544 def setUp(self):
544 def setUp(self):
545 self.BASETESTDIR = tempfile.mkdtemp()
545 self.BASETESTDIR = tempfile.mkdtemp()
546 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
546 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
547 os.mkdir(self.TESTDIR)
547 os.mkdir(self.TESTDIR)
548 with open(join(self.TESTDIR, u"åäötestscript.py"), "w", encoding='utf-8') as sfile:
548 with open(
549 join(self.TESTDIR, u"åäötestscript.py"), "w", encoding="utf-8"
550 ) as sfile:
549 sfile.write("pass\n")
551 sfile.write("pass\n")
550 self.oldpath = os.getcwd()
552 self.oldpath = os.getcwd()
551 os.chdir(self.TESTDIR)
553 os.chdir(self.TESTDIR)
552 self.fname = u"åäötestscript.py"
554 self.fname = u"åäötestscript.py"
553
555
554 def tearDown(self):
556 def tearDown(self):
555 os.chdir(self.oldpath)
557 os.chdir(self.oldpath)
556 shutil.rmtree(self.BASETESTDIR)
558 shutil.rmtree(self.BASETESTDIR)
557
559
558 @onlyif_unicode_paths
560 @onlyif_unicode_paths
559 def test_1(self):
561 def test_1(self):
560 """Test safe_execfile with non-ascii path
562 """Test safe_execfile with non-ascii path
561 """
563 """
562 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
564 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
563
565
564 class ExitCodeChecks(tt.TempFileMixin):
566 class ExitCodeChecks(tt.TempFileMixin):
565
567
566 def setUp(self):
568 def setUp(self):
567 self.system = ip.system_raw
569 self.system = ip.system_raw
568
570
569 def test_exit_code_ok(self):
571 def test_exit_code_ok(self):
570 self.system('exit 0')
572 self.system('exit 0')
571 self.assertEqual(ip.user_ns['_exit_code'], 0)
573 self.assertEqual(ip.user_ns['_exit_code'], 0)
572
574
573 def test_exit_code_error(self):
575 def test_exit_code_error(self):
574 self.system('exit 1')
576 self.system('exit 1')
575 self.assertEqual(ip.user_ns['_exit_code'], 1)
577 self.assertEqual(ip.user_ns['_exit_code'], 1)
576
578
577 @skipif(not hasattr(signal, 'SIGALRM'))
579 @skipif(not hasattr(signal, 'SIGALRM'))
578 def test_exit_code_signal(self):
580 def test_exit_code_signal(self):
579 self.mktmp("import signal, time\n"
581 self.mktmp("import signal, time\n"
580 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
582 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
581 "time.sleep(1)\n")
583 "time.sleep(1)\n")
582 self.system("%s %s" % (sys.executable, self.fname))
584 self.system("%s %s" % (sys.executable, self.fname))
583 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
585 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
584
586
585 @onlyif_cmds_exist("csh")
587 @onlyif_cmds_exist("csh")
586 def test_exit_code_signal_csh(self):
588 def test_exit_code_signal_csh(self):
587 SHELL = os.environ.get('SHELL', None)
589 SHELL = os.environ.get('SHELL', None)
588 os.environ['SHELL'] = find_cmd("csh")
590 os.environ['SHELL'] = find_cmd("csh")
589 try:
591 try:
590 self.test_exit_code_signal()
592 self.test_exit_code_signal()
591 finally:
593 finally:
592 if SHELL is not None:
594 if SHELL is not None:
593 os.environ['SHELL'] = SHELL
595 os.environ['SHELL'] = SHELL
594 else:
596 else:
595 del os.environ['SHELL']
597 del os.environ['SHELL']
596
598
597
599
598 class TestSystemRaw(ExitCodeChecks):
600 class TestSystemRaw(ExitCodeChecks):
599
601
600 def setUp(self):
602 def setUp(self):
601 super().setUp()
603 super().setUp()
602 self.system = ip.system_raw
604 self.system = ip.system_raw
603
605
604 @onlyif_unicode_paths
606 @onlyif_unicode_paths
605 def test_1(self):
607 def test_1(self):
606 """Test system_raw with non-ascii cmd
608 """Test system_raw with non-ascii cmd
607 """
609 """
608 cmd = u'''python -c "'åäö'" '''
610 cmd = u'''python -c "'åäö'" '''
609 ip.system_raw(cmd)
611 ip.system_raw(cmd)
610
612
611 @mock.patch('subprocess.call', side_effect=KeyboardInterrupt)
613 @mock.patch('subprocess.call', side_effect=KeyboardInterrupt)
612 @mock.patch('os.system', side_effect=KeyboardInterrupt)
614 @mock.patch('os.system', side_effect=KeyboardInterrupt)
613 def test_control_c(self, *mocks):
615 def test_control_c(self, *mocks):
614 try:
616 try:
615 self.system("sleep 1 # wont happen")
617 self.system("sleep 1 # wont happen")
616 except KeyboardInterrupt:
618 except KeyboardInterrupt:
617 self.fail(
619 self.fail(
618 "system call should intercept "
620 "system call should intercept "
619 "keyboard interrupt from subprocess.call"
621 "keyboard interrupt from subprocess.call"
620 )
622 )
621 self.assertEqual(ip.user_ns["_exit_code"], -signal.SIGINT)
623 self.assertEqual(ip.user_ns["_exit_code"], -signal.SIGINT)
622
624
623 def test_magic_warnings(self):
625 def test_magic_warnings(self):
624 for magic_cmd in ("ls", "pip", "conda", "cd"):
626 for magic_cmd in ("ls", "pip", "conda", "cd"):
625 with self.assertWarnsRegex(Warning, "You executed the system command"):
627 with self.assertWarnsRegex(Warning, "You executed the system command"):
626 ip.system_raw(magic_cmd)
628 ip.system_raw(magic_cmd)
627
629
628 # TODO: Exit codes are currently ignored on Windows.
630 # TODO: Exit codes are currently ignored on Windows.
629 class TestSystemPipedExitCode(ExitCodeChecks):
631 class TestSystemPipedExitCode(ExitCodeChecks):
630
632
631 def setUp(self):
633 def setUp(self):
632 super().setUp()
634 super().setUp()
633 self.system = ip.system_piped
635 self.system = ip.system_piped
634
636
635 @skip_win32
637 @skip_win32
636 def test_exit_code_ok(self):
638 def test_exit_code_ok(self):
637 ExitCodeChecks.test_exit_code_ok(self)
639 ExitCodeChecks.test_exit_code_ok(self)
638
640
639 @skip_win32
641 @skip_win32
640 def test_exit_code_error(self):
642 def test_exit_code_error(self):
641 ExitCodeChecks.test_exit_code_error(self)
643 ExitCodeChecks.test_exit_code_error(self)
642
644
643 @skip_win32
645 @skip_win32
644 def test_exit_code_signal(self):
646 def test_exit_code_signal(self):
645 ExitCodeChecks.test_exit_code_signal(self)
647 ExitCodeChecks.test_exit_code_signal(self)
646
648
647 class TestModules(tt.TempFileMixin):
649 class TestModules(tt.TempFileMixin):
648 def test_extraneous_loads(self):
650 def test_extraneous_loads(self):
649 """Test we're not loading modules on startup that we shouldn't.
651 """Test we're not loading modules on startup that we shouldn't.
650 """
652 """
651 self.mktmp("import sys\n"
653 self.mktmp("import sys\n"
652 "print('numpy' in sys.modules)\n"
654 "print('numpy' in sys.modules)\n"
653 "print('ipyparallel' in sys.modules)\n"
655 "print('ipyparallel' in sys.modules)\n"
654 "print('ipykernel' in sys.modules)\n"
656 "print('ipykernel' in sys.modules)\n"
655 )
657 )
656 out = "False\nFalse\nFalse\n"
658 out = "False\nFalse\nFalse\n"
657 tt.ipexec_validate(self.fname, out)
659 tt.ipexec_validate(self.fname, out)
658
660
659 class Negator(ast.NodeTransformer):
661 class Negator(ast.NodeTransformer):
660 """Negates all number literals in an AST."""
662 """Negates all number literals in an AST."""
661
663
662 # for python 3.7 and earlier
664 # for python 3.7 and earlier
663 def visit_Num(self, node):
665 def visit_Num(self, node):
664 node.n = -node.n
666 node.n = -node.n
665 return node
667 return node
666
668
667 # for python 3.8+
669 # for python 3.8+
668 def visit_Constant(self, node):
670 def visit_Constant(self, node):
669 if isinstance(node.value, int):
671 if isinstance(node.value, int):
670 return self.visit_Num(node)
672 return self.visit_Num(node)
671 return node
673 return node
672
674
673 class TestAstTransform(unittest.TestCase):
675 class TestAstTransform(unittest.TestCase):
674 def setUp(self):
676 def setUp(self):
675 self.negator = Negator()
677 self.negator = Negator()
676 ip.ast_transformers.append(self.negator)
678 ip.ast_transformers.append(self.negator)
677
679
678 def tearDown(self):
680 def tearDown(self):
679 ip.ast_transformers.remove(self.negator)
681 ip.ast_transformers.remove(self.negator)
680
682
681 def test_run_cell(self):
683 def test_run_cell(self):
682 with tt.AssertPrints('-34'):
684 with tt.AssertPrints('-34'):
683 ip.run_cell('print (12 + 22)')
685 ip.run_cell('print (12 + 22)')
684
686
685 # A named reference to a number shouldn't be transformed.
687 # A named reference to a number shouldn't be transformed.
686 ip.user_ns['n'] = 55
688 ip.user_ns['n'] = 55
687 with tt.AssertNotPrints('-55'):
689 with tt.AssertNotPrints('-55'):
688 ip.run_cell('print (n)')
690 ip.run_cell('print (n)')
689
691
690 def test_timeit(self):
692 def test_timeit(self):
691 called = set()
693 called = set()
692 def f(x):
694 def f(x):
693 called.add(x)
695 called.add(x)
694 ip.push({'f':f})
696 ip.push({'f':f})
695
697
696 with tt.AssertPrints("std. dev. of"):
698 with tt.AssertPrints("std. dev. of"):
697 ip.run_line_magic("timeit", "-n1 f(1)")
699 ip.run_line_magic("timeit", "-n1 f(1)")
698 self.assertEqual(called, {-1})
700 self.assertEqual(called, {-1})
699 called.clear()
701 called.clear()
700
702
701 with tt.AssertPrints("std. dev. of"):
703 with tt.AssertPrints("std. dev. of"):
702 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
704 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
703 self.assertEqual(called, {-2, -3})
705 self.assertEqual(called, {-2, -3})
704
706
705 def test_time(self):
707 def test_time(self):
706 called = []
708 called = []
707 def f(x):
709 def f(x):
708 called.append(x)
710 called.append(x)
709 ip.push({'f':f})
711 ip.push({'f':f})
710
712
711 # Test with an expression
713 # Test with an expression
712 with tt.AssertPrints("Wall time: "):
714 with tt.AssertPrints("Wall time: "):
713 ip.run_line_magic("time", "f(5+9)")
715 ip.run_line_magic("time", "f(5+9)")
714 self.assertEqual(called, [-14])
716 self.assertEqual(called, [-14])
715 called[:] = []
717 called[:] = []
716
718
717 # Test with a statement (different code path)
719 # Test with a statement (different code path)
718 with tt.AssertPrints("Wall time: "):
720 with tt.AssertPrints("Wall time: "):
719 ip.run_line_magic("time", "a = f(-3 + -2)")
721 ip.run_line_magic("time", "a = f(-3 + -2)")
720 self.assertEqual(called, [5])
722 self.assertEqual(called, [5])
721
723
722 def test_macro(self):
724 def test_macro(self):
723 ip.push({'a':10})
725 ip.push({'a':10})
724 # The AST transformation makes this do a+=-1
726 # The AST transformation makes this do a+=-1
725 ip.define_macro("amacro", "a+=1\nprint(a)")
727 ip.define_macro("amacro", "a+=1\nprint(a)")
726
728
727 with tt.AssertPrints("9"):
729 with tt.AssertPrints("9"):
728 ip.run_cell("amacro")
730 ip.run_cell("amacro")
729 with tt.AssertPrints("8"):
731 with tt.AssertPrints("8"):
730 ip.run_cell("amacro")
732 ip.run_cell("amacro")
731
733
732 class TestMiscTransform(unittest.TestCase):
734 class TestMiscTransform(unittest.TestCase):
733
735
734
736
735 def test_transform_only_once(self):
737 def test_transform_only_once(self):
736 cleanup = 0
738 cleanup = 0
737 line_t = 0
739 line_t = 0
738 def count_cleanup(lines):
740 def count_cleanup(lines):
739 nonlocal cleanup
741 nonlocal cleanup
740 cleanup += 1
742 cleanup += 1
741 return lines
743 return lines
742
744
743 def count_line_t(lines):
745 def count_line_t(lines):
744 nonlocal line_t
746 nonlocal line_t
745 line_t += 1
747 line_t += 1
746 return lines
748 return lines
747
749
748 ip.input_transformer_manager.cleanup_transforms.append(count_cleanup)
750 ip.input_transformer_manager.cleanup_transforms.append(count_cleanup)
749 ip.input_transformer_manager.line_transforms.append(count_line_t)
751 ip.input_transformer_manager.line_transforms.append(count_line_t)
750
752
751 ip.run_cell('1')
753 ip.run_cell('1')
752
754
753 assert cleanup == 1
755 assert cleanup == 1
754 assert line_t == 1
756 assert line_t == 1
755
757
756 class IntegerWrapper(ast.NodeTransformer):
758 class IntegerWrapper(ast.NodeTransformer):
757 """Wraps all integers in a call to Integer()"""
759 """Wraps all integers in a call to Integer()"""
758
760
759 # for Python 3.7 and earlier
761 # for Python 3.7 and earlier
760
762
761 # for Python 3.7 and earlier
763 # for Python 3.7 and earlier
762 def visit_Num(self, node):
764 def visit_Num(self, node):
763 if isinstance(node.n, int):
765 if isinstance(node.n, int):
764 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
766 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
765 args=[node], keywords=[])
767 args=[node], keywords=[])
766 return node
768 return node
767
769
768 # For Python 3.8+
770 # For Python 3.8+
769 def visit_Constant(self, node):
771 def visit_Constant(self, node):
770 if isinstance(node.value, int):
772 if isinstance(node.value, int):
771 return self.visit_Num(node)
773 return self.visit_Num(node)
772 return node
774 return node
773
775
774
776
775 class TestAstTransform2(unittest.TestCase):
777 class TestAstTransform2(unittest.TestCase):
776 def setUp(self):
778 def setUp(self):
777 self.intwrapper = IntegerWrapper()
779 self.intwrapper = IntegerWrapper()
778 ip.ast_transformers.append(self.intwrapper)
780 ip.ast_transformers.append(self.intwrapper)
779
781
780 self.calls = []
782 self.calls = []
781 def Integer(*args):
783 def Integer(*args):
782 self.calls.append(args)
784 self.calls.append(args)
783 return args
785 return args
784 ip.push({"Integer": Integer})
786 ip.push({"Integer": Integer})
785
787
786 def tearDown(self):
788 def tearDown(self):
787 ip.ast_transformers.remove(self.intwrapper)
789 ip.ast_transformers.remove(self.intwrapper)
788 del ip.user_ns['Integer']
790 del ip.user_ns['Integer']
789
791
790 def test_run_cell(self):
792 def test_run_cell(self):
791 ip.run_cell("n = 2")
793 ip.run_cell("n = 2")
792 self.assertEqual(self.calls, [(2,)])
794 self.assertEqual(self.calls, [(2,)])
793
795
794 # This shouldn't throw an error
796 # This shouldn't throw an error
795 ip.run_cell("o = 2.0")
797 ip.run_cell("o = 2.0")
796 self.assertEqual(ip.user_ns['o'], 2.0)
798 self.assertEqual(ip.user_ns['o'], 2.0)
797
799
798 def test_timeit(self):
800 def test_timeit(self):
799 called = set()
801 called = set()
800 def f(x):
802 def f(x):
801 called.add(x)
803 called.add(x)
802 ip.push({'f':f})
804 ip.push({'f':f})
803
805
804 with tt.AssertPrints("std. dev. of"):
806 with tt.AssertPrints("std. dev. of"):
805 ip.run_line_magic("timeit", "-n1 f(1)")
807 ip.run_line_magic("timeit", "-n1 f(1)")
806 self.assertEqual(called, {(1,)})
808 self.assertEqual(called, {(1,)})
807 called.clear()
809 called.clear()
808
810
809 with tt.AssertPrints("std. dev. of"):
811 with tt.AssertPrints("std. dev. of"):
810 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
812 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
811 self.assertEqual(called, {(2,), (3,)})
813 self.assertEqual(called, {(2,), (3,)})
812
814
813 class ErrorTransformer(ast.NodeTransformer):
815 class ErrorTransformer(ast.NodeTransformer):
814 """Throws an error when it sees a number."""
816 """Throws an error when it sees a number."""
815
817
816 # for Python 3.7 and earlier
818 # for Python 3.7 and earlier
817 def visit_Num(self, node):
819 def visit_Num(self, node):
818 raise ValueError("test")
820 raise ValueError("test")
819
821
820 # for Python 3.8+
822 # for Python 3.8+
821 def visit_Constant(self, node):
823 def visit_Constant(self, node):
822 if isinstance(node.value, int):
824 if isinstance(node.value, int):
823 return self.visit_Num(node)
825 return self.visit_Num(node)
824 return node
826 return node
825
827
826
828
827 class TestAstTransformError(unittest.TestCase):
829 class TestAstTransformError(unittest.TestCase):
828 def test_unregistering(self):
830 def test_unregistering(self):
829 err_transformer = ErrorTransformer()
831 err_transformer = ErrorTransformer()
830 ip.ast_transformers.append(err_transformer)
832 ip.ast_transformers.append(err_transformer)
831
833
832 with self.assertWarnsRegex(UserWarning, "It will be unregistered"):
834 with self.assertWarnsRegex(UserWarning, "It will be unregistered"):
833 ip.run_cell("1 + 2")
835 ip.run_cell("1 + 2")
834
836
835 # This should have been removed.
837 # This should have been removed.
836 self.assertNotIn(err_transformer, ip.ast_transformers)
838 self.assertNotIn(err_transformer, ip.ast_transformers)
837
839
838
840
839 class StringRejector(ast.NodeTransformer):
841 class StringRejector(ast.NodeTransformer):
840 """Throws an InputRejected when it sees a string literal.
842 """Throws an InputRejected when it sees a string literal.
841
843
842 Used to verify that NodeTransformers can signal that a piece of code should
844 Used to verify that NodeTransformers can signal that a piece of code should
843 not be executed by throwing an InputRejected.
845 not be executed by throwing an InputRejected.
844 """
846 """
845
847
846 #for python 3.7 and earlier
848 #for python 3.7 and earlier
847 def visit_Str(self, node):
849 def visit_Str(self, node):
848 raise InputRejected("test")
850 raise InputRejected("test")
849
851
850 # 3.8 only
852 # 3.8 only
851 def visit_Constant(self, node):
853 def visit_Constant(self, node):
852 if isinstance(node.value, str):
854 if isinstance(node.value, str):
853 raise InputRejected("test")
855 raise InputRejected("test")
854 return node
856 return node
855
857
856
858
857 class TestAstTransformInputRejection(unittest.TestCase):
859 class TestAstTransformInputRejection(unittest.TestCase):
858
860
859 def setUp(self):
861 def setUp(self):
860 self.transformer = StringRejector()
862 self.transformer = StringRejector()
861 ip.ast_transformers.append(self.transformer)
863 ip.ast_transformers.append(self.transformer)
862
864
863 def tearDown(self):
865 def tearDown(self):
864 ip.ast_transformers.remove(self.transformer)
866 ip.ast_transformers.remove(self.transformer)
865
867
866 def test_input_rejection(self):
868 def test_input_rejection(self):
867 """Check that NodeTransformers can reject input."""
869 """Check that NodeTransformers can reject input."""
868
870
869 expect_exception_tb = tt.AssertPrints("InputRejected: test")
871 expect_exception_tb = tt.AssertPrints("InputRejected: test")
870 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
872 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
871
873
872 # Run the same check twice to verify that the transformer is not
874 # Run the same check twice to verify that the transformer is not
873 # disabled after raising.
875 # disabled after raising.
874 with expect_exception_tb, expect_no_cell_output:
876 with expect_exception_tb, expect_no_cell_output:
875 ip.run_cell("'unsafe'")
877 ip.run_cell("'unsafe'")
876
878
877 with expect_exception_tb, expect_no_cell_output:
879 with expect_exception_tb, expect_no_cell_output:
878 res = ip.run_cell("'unsafe'")
880 res = ip.run_cell("'unsafe'")
879
881
880 self.assertIsInstance(res.error_before_exec, InputRejected)
882 self.assertIsInstance(res.error_before_exec, InputRejected)
881
883
882 def test__IPYTHON__():
884 def test__IPYTHON__():
883 # This shouldn't raise a NameError, that's all
885 # This shouldn't raise a NameError, that's all
884 __IPYTHON__
886 __IPYTHON__
885
887
886
888
887 class DummyRepr(object):
889 class DummyRepr(object):
888 def __repr__(self):
890 def __repr__(self):
889 return "DummyRepr"
891 return "DummyRepr"
890
892
891 def _repr_html_(self):
893 def _repr_html_(self):
892 return "<b>dummy</b>"
894 return "<b>dummy</b>"
893
895
894 def _repr_javascript_(self):
896 def _repr_javascript_(self):
895 return "console.log('hi');", {'key': 'value'}
897 return "console.log('hi');", {'key': 'value'}
896
898
897
899
898 def test_user_variables():
900 def test_user_variables():
899 # enable all formatters
901 # enable all formatters
900 ip.display_formatter.active_types = ip.display_formatter.format_types
902 ip.display_formatter.active_types = ip.display_formatter.format_types
901
903
902 ip.user_ns['dummy'] = d = DummyRepr()
904 ip.user_ns['dummy'] = d = DummyRepr()
903 keys = {'dummy', 'doesnotexist'}
905 keys = {'dummy', 'doesnotexist'}
904 r = ip.user_expressions({ key:key for key in keys})
906 r = ip.user_expressions({ key:key for key in keys})
905
907
906 assert keys == set(r.keys())
908 assert keys == set(r.keys())
907 dummy = r["dummy"]
909 dummy = r["dummy"]
908 assert {"status", "data", "metadata"} == set(dummy.keys())
910 assert {"status", "data", "metadata"} == set(dummy.keys())
909 assert dummy["status"] == "ok"
911 assert dummy["status"] == "ok"
910 data = dummy["data"]
912 data = dummy["data"]
911 metadata = dummy["metadata"]
913 metadata = dummy["metadata"]
912 assert data.get("text/html") == d._repr_html_()
914 assert data.get("text/html") == d._repr_html_()
913 js, jsmd = d._repr_javascript_()
915 js, jsmd = d._repr_javascript_()
914 assert data.get("application/javascript") == js
916 assert data.get("application/javascript") == js
915 assert metadata.get("application/javascript") == jsmd
917 assert metadata.get("application/javascript") == jsmd
916
918
917 dne = r["doesnotexist"]
919 dne = r["doesnotexist"]
918 assert dne["status"] == "error"
920 assert dne["status"] == "error"
919 assert dne["ename"] == "NameError"
921 assert dne["ename"] == "NameError"
920
922
921 # back to text only
923 # back to text only
922 ip.display_formatter.active_types = ['text/plain']
924 ip.display_formatter.active_types = ['text/plain']
923
925
924 def test_user_expression():
926 def test_user_expression():
925 # enable all formatters
927 # enable all formatters
926 ip.display_formatter.active_types = ip.display_formatter.format_types
928 ip.display_formatter.active_types = ip.display_formatter.format_types
927 query = {
929 query = {
928 'a' : '1 + 2',
930 'a' : '1 + 2',
929 'b' : '1/0',
931 'b' : '1/0',
930 }
932 }
931 r = ip.user_expressions(query)
933 r = ip.user_expressions(query)
932 import pprint
934 import pprint
933 pprint.pprint(r)
935 pprint.pprint(r)
934 assert set(r.keys()) == set(query.keys())
936 assert set(r.keys()) == set(query.keys())
935 a = r["a"]
937 a = r["a"]
936 assert {"status", "data", "metadata"} == set(a.keys())
938 assert {"status", "data", "metadata"} == set(a.keys())
937 assert a["status"] == "ok"
939 assert a["status"] == "ok"
938 data = a["data"]
940 data = a["data"]
939 metadata = a["metadata"]
941 metadata = a["metadata"]
940 assert data.get("text/plain") == "3"
942 assert data.get("text/plain") == "3"
941
943
942 b = r["b"]
944 b = r["b"]
943 assert b["status"] == "error"
945 assert b["status"] == "error"
944 assert b["ename"] == "ZeroDivisionError"
946 assert b["ename"] == "ZeroDivisionError"
945
947
946 # back to text only
948 # back to text only
947 ip.display_formatter.active_types = ['text/plain']
949 ip.display_formatter.active_types = ['text/plain']
948
950
949
951
950 class TestSyntaxErrorTransformer(unittest.TestCase):
952 class TestSyntaxErrorTransformer(unittest.TestCase):
951 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
953 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
952
954
953 @staticmethod
955 @staticmethod
954 def transformer(lines):
956 def transformer(lines):
955 for line in lines:
957 for line in lines:
956 pos = line.find('syntaxerror')
958 pos = line.find('syntaxerror')
957 if pos >= 0:
959 if pos >= 0:
958 e = SyntaxError('input contains "syntaxerror"')
960 e = SyntaxError('input contains "syntaxerror"')
959 e.text = line
961 e.text = line
960 e.offset = pos + 1
962 e.offset = pos + 1
961 raise e
963 raise e
962 return lines
964 return lines
963
965
964 def setUp(self):
966 def setUp(self):
965 ip.input_transformers_post.append(self.transformer)
967 ip.input_transformers_post.append(self.transformer)
966
968
967 def tearDown(self):
969 def tearDown(self):
968 ip.input_transformers_post.remove(self.transformer)
970 ip.input_transformers_post.remove(self.transformer)
969
971
970 def test_syntaxerror_input_transformer(self):
972 def test_syntaxerror_input_transformer(self):
971 with tt.AssertPrints('1234'):
973 with tt.AssertPrints('1234'):
972 ip.run_cell('1234')
974 ip.run_cell('1234')
973 with tt.AssertPrints('SyntaxError: invalid syntax'):
975 with tt.AssertPrints('SyntaxError: invalid syntax'):
974 ip.run_cell('1 2 3') # plain python syntax error
976 ip.run_cell('1 2 3') # plain python syntax error
975 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
977 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
976 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
978 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
977 with tt.AssertPrints('3456'):
979 with tt.AssertPrints('3456'):
978 ip.run_cell('3456')
980 ip.run_cell('3456')
979
981
980
982
981 class TestWarningSuppression(unittest.TestCase):
983 class TestWarningSuppression(unittest.TestCase):
982 def test_warning_suppression(self):
984 def test_warning_suppression(self):
983 ip.run_cell("import warnings")
985 ip.run_cell("import warnings")
984 try:
986 try:
985 with self.assertWarnsRegex(UserWarning, "asdf"):
987 with self.assertWarnsRegex(UserWarning, "asdf"):
986 ip.run_cell("warnings.warn('asdf')")
988 ip.run_cell("warnings.warn('asdf')")
987 # Here's the real test -- if we run that again, we should get the
989 # Here's the real test -- if we run that again, we should get the
988 # warning again. Traditionally, each warning was only issued once per
990 # warning again. Traditionally, each warning was only issued once per
989 # IPython session (approximately), even if the user typed in new and
991 # IPython session (approximately), even if the user typed in new and
990 # different code that should have also triggered the warning, leading
992 # different code that should have also triggered the warning, leading
991 # to much confusion.
993 # to much confusion.
992 with self.assertWarnsRegex(UserWarning, "asdf"):
994 with self.assertWarnsRegex(UserWarning, "asdf"):
993 ip.run_cell("warnings.warn('asdf')")
995 ip.run_cell("warnings.warn('asdf')")
994 finally:
996 finally:
995 ip.run_cell("del warnings")
997 ip.run_cell("del warnings")
996
998
997
999
998 def test_deprecation_warning(self):
1000 def test_deprecation_warning(self):
999 ip.run_cell("""
1001 ip.run_cell("""
1000 import warnings
1002 import warnings
1001 def wrn():
1003 def wrn():
1002 warnings.warn(
1004 warnings.warn(
1003 "I AM A WARNING",
1005 "I AM A WARNING",
1004 DeprecationWarning
1006 DeprecationWarning
1005 )
1007 )
1006 """)
1008 """)
1007 try:
1009 try:
1008 with self.assertWarnsRegex(DeprecationWarning, "I AM A WARNING"):
1010 with self.assertWarnsRegex(DeprecationWarning, "I AM A WARNING"):
1009 ip.run_cell("wrn()")
1011 ip.run_cell("wrn()")
1010 finally:
1012 finally:
1011 ip.run_cell("del warnings")
1013 ip.run_cell("del warnings")
1012 ip.run_cell("del wrn")
1014 ip.run_cell("del wrn")
1013
1015
1014
1016
1015 class TestImportNoDeprecate(tt.TempFileMixin):
1017 class TestImportNoDeprecate(tt.TempFileMixin):
1016
1018
1017 def setUp(self):
1019 def setUp(self):
1018 """Make a valid python temp file."""
1020 """Make a valid python temp file."""
1019 self.mktmp("""
1021 self.mktmp("""
1020 import warnings
1022 import warnings
1021 def wrn():
1023 def wrn():
1022 warnings.warn(
1024 warnings.warn(
1023 "I AM A WARNING",
1025 "I AM A WARNING",
1024 DeprecationWarning
1026 DeprecationWarning
1025 )
1027 )
1026 """)
1028 """)
1027 super().setUp()
1029 super().setUp()
1028
1030
1029 def test_no_dep(self):
1031 def test_no_dep(self):
1030 """
1032 """
1031 No deprecation warning should be raised from imported functions
1033 No deprecation warning should be raised from imported functions
1032 """
1034 """
1033 ip.run_cell("from {} import wrn".format(self.fname))
1035 ip.run_cell("from {} import wrn".format(self.fname))
1034
1036
1035 with tt.AssertNotPrints("I AM A WARNING"):
1037 with tt.AssertNotPrints("I AM A WARNING"):
1036 ip.run_cell("wrn()")
1038 ip.run_cell("wrn()")
1037 ip.run_cell("del wrn")
1039 ip.run_cell("del wrn")
1038
1040
1039
1041
1040 def test_custom_exc_count():
1042 def test_custom_exc_count():
1041 hook = mock.Mock(return_value=None)
1043 hook = mock.Mock(return_value=None)
1042 ip.set_custom_exc((SyntaxError,), hook)
1044 ip.set_custom_exc((SyntaxError,), hook)
1043 before = ip.execution_count
1045 before = ip.execution_count
1044 ip.run_cell("def foo()", store_history=True)
1046 ip.run_cell("def foo()", store_history=True)
1045 # restore default excepthook
1047 # restore default excepthook
1046 ip.set_custom_exc((), None)
1048 ip.set_custom_exc((), None)
1047 assert hook.call_count == 1
1049 assert hook.call_count == 1
1048 assert ip.execution_count == before + 1
1050 assert ip.execution_count == before + 1
1049
1051
1050
1052
1051 def test_run_cell_async():
1053 def test_run_cell_async():
1052 ip.run_cell("import asyncio")
1054 ip.run_cell("import asyncio")
1053 coro = ip.run_cell_async("await asyncio.sleep(0.01)\n5")
1055 coro = ip.run_cell_async("await asyncio.sleep(0.01)\n5")
1054 assert asyncio.iscoroutine(coro)
1056 assert asyncio.iscoroutine(coro)
1055 loop = asyncio.new_event_loop()
1057 loop = asyncio.new_event_loop()
1056 result = loop.run_until_complete(coro)
1058 result = loop.run_until_complete(coro)
1057 assert isinstance(result, interactiveshell.ExecutionResult)
1059 assert isinstance(result, interactiveshell.ExecutionResult)
1058 assert result.result == 5
1060 assert result.result == 5
1059
1061
1060
1062
1061 def test_run_cell_await():
1063 def test_run_cell_await():
1062 ip.run_cell("import asyncio")
1064 ip.run_cell("import asyncio")
1063 result = ip.run_cell("await asyncio.sleep(0.01); 10")
1065 result = ip.run_cell("await asyncio.sleep(0.01); 10")
1064 assert ip.user_ns["_"] == 10
1066 assert ip.user_ns["_"] == 10
1065
1067
1066
1068
1067 def test_run_cell_asyncio_run():
1069 def test_run_cell_asyncio_run():
1068 ip.run_cell("import asyncio")
1070 ip.run_cell("import asyncio")
1069 result = ip.run_cell("await asyncio.sleep(0.01); 1")
1071 result = ip.run_cell("await asyncio.sleep(0.01); 1")
1070 assert ip.user_ns["_"] == 1
1072 assert ip.user_ns["_"] == 1
1071 result = ip.run_cell("asyncio.run(asyncio.sleep(0.01)); 2")
1073 result = ip.run_cell("asyncio.run(asyncio.sleep(0.01)); 2")
1072 assert ip.user_ns["_"] == 2
1074 assert ip.user_ns["_"] == 2
1073 result = ip.run_cell("await asyncio.sleep(0.01); 3")
1075 result = ip.run_cell("await asyncio.sleep(0.01); 3")
1074 assert ip.user_ns["_"] == 3
1076 assert ip.user_ns["_"] == 3
1075
1077
1076
1078
1077 def test_should_run_async():
1079 def test_should_run_async():
1078 assert not ip.should_run_async("a = 5")
1080 assert not ip.should_run_async("a = 5")
1079 assert ip.should_run_async("await x")
1081 assert ip.should_run_async("await x")
1080 assert ip.should_run_async("import asyncio; await asyncio.sleep(1)")
1082 assert ip.should_run_async("import asyncio; await asyncio.sleep(1)")
1081
1083
1082
1084
1083 def test_set_custom_completer():
1085 def test_set_custom_completer():
1084 num_completers = len(ip.Completer.matchers)
1086 num_completers = len(ip.Completer.matchers)
1085
1087
1086 def foo(*args, **kwargs):
1088 def foo(*args, **kwargs):
1087 return "I'm a completer!"
1089 return "I'm a completer!"
1088
1090
1089 ip.set_custom_completer(foo, 0)
1091 ip.set_custom_completer(foo, 0)
1090
1092
1091 # check that we've really added a new completer
1093 # check that we've really added a new completer
1092 assert len(ip.Completer.matchers) == num_completers + 1
1094 assert len(ip.Completer.matchers) == num_completers + 1
1093
1095
1094 # check that the first completer is the function we defined
1096 # check that the first completer is the function we defined
1095 assert ip.Completer.matchers[0]() == "I'm a completer!"
1097 assert ip.Completer.matchers[0]() == "I'm a completer!"
1096
1098
1097 # clean up
1099 # clean up
1098 ip.Completer.custom_matchers.pop()
1100 ip.Completer.custom_matchers.pop()
@@ -1,1366 +1,1408 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for various magic functions."""
2 """Tests for various magic functions."""
3
3
4 import asyncio
4 import asyncio
5 import gc
5 import gc
6 import io
6 import io
7 import os
7 import os
8 import re
8 import re
9 import shlex
9 import shlex
10 import sys
10 import sys
11 import warnings
11 import warnings
12 from importlib import invalidate_caches
12 from importlib import invalidate_caches
13 from io import StringIO
13 from io import StringIO
14 from pathlib import Path
14 from pathlib import Path
15 from textwrap import dedent
15 from textwrap import dedent
16 from unittest import TestCase, mock
16 from unittest import TestCase, mock
17
17
18 import pytest
18 import pytest
19
19
20 from IPython import get_ipython
20 from IPython import get_ipython
21 from IPython.core import magic
21 from IPython.core import magic
22 from IPython.core.error import UsageError
22 from IPython.core.error import UsageError
23 from IPython.core.magic import (
23 from IPython.core.magic import (
24 Magics,
24 Magics,
25 cell_magic,
25 cell_magic,
26 line_magic,
26 line_magic,
27 magics_class,
27 magics_class,
28 register_cell_magic,
28 register_cell_magic,
29 register_line_magic,
29 register_line_magic,
30 )
30 )
31 from IPython.core.magics import code, execution, logging, osm, script
31 from IPython.core.magics import code, execution, logging, osm, script
32 from IPython.testing import decorators as dec
32 from IPython.testing import decorators as dec
33 from IPython.testing import tools as tt
33 from IPython.testing import tools as tt
34 from IPython.utils.io import capture_output
34 from IPython.utils.io import capture_output
35 from IPython.utils.process import find_cmd
35 from IPython.utils.process import find_cmd
36 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
36 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
37
37
38 from .test_debugger import PdbTestInput
38 from .test_debugger import PdbTestInput
39
39
40
40
41 @magic.magics_class
41 @magic.magics_class
42 class DummyMagics(magic.Magics): pass
42 class DummyMagics(magic.Magics): pass
43
43
44 def test_extract_code_ranges():
44 def test_extract_code_ranges():
45 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
45 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
46 expected = [
46 expected = [
47 (0, 1),
47 (0, 1),
48 (2, 3),
48 (2, 3),
49 (4, 6),
49 (4, 6),
50 (6, 9),
50 (6, 9),
51 (9, 14),
51 (9, 14),
52 (16, None),
52 (16, None),
53 (None, 9),
53 (None, 9),
54 (9, None),
54 (9, None),
55 (None, 13),
55 (None, 13),
56 (None, None),
56 (None, None),
57 ]
57 ]
58 actual = list(code.extract_code_ranges(instr))
58 actual = list(code.extract_code_ranges(instr))
59 assert actual == expected
59 assert actual == expected
60
60
61 def test_extract_symbols():
61 def test_extract_symbols():
62 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
62 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
63 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
63 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
64 expected = [([], ['a']),
64 expected = [([], ['a']),
65 (["def b():\n return 42\n"], []),
65 (["def b():\n return 42\n"], []),
66 (["class A: pass\n"], []),
66 (["class A: pass\n"], []),
67 (["class A: pass\n", "def b():\n return 42\n"], []),
67 (["class A: pass\n", "def b():\n return 42\n"], []),
68 (["class A: pass\n"], ['a']),
68 (["class A: pass\n"], ['a']),
69 ([], ['z'])]
69 ([], ['z'])]
70 for symbols, exp in zip(symbols_args, expected):
70 for symbols, exp in zip(symbols_args, expected):
71 assert code.extract_symbols(source, symbols) == exp
71 assert code.extract_symbols(source, symbols) == exp
72
72
73
73
74 def test_extract_symbols_raises_exception_with_non_python_code():
74 def test_extract_symbols_raises_exception_with_non_python_code():
75 source = ("=begin A Ruby program :)=end\n"
75 source = ("=begin A Ruby program :)=end\n"
76 "def hello\n"
76 "def hello\n"
77 "puts 'Hello world'\n"
77 "puts 'Hello world'\n"
78 "end")
78 "end")
79 with pytest.raises(SyntaxError):
79 with pytest.raises(SyntaxError):
80 code.extract_symbols(source, "hello")
80 code.extract_symbols(source, "hello")
81
81
82
82
83 def test_magic_not_found():
83 def test_magic_not_found():
84 # magic not found raises UsageError
84 # magic not found raises UsageError
85 with pytest.raises(UsageError):
85 with pytest.raises(UsageError):
86 _ip.magic('doesntexist')
86 _ip.magic('doesntexist')
87
87
88 # ensure result isn't success when a magic isn't found
88 # ensure result isn't success when a magic isn't found
89 result = _ip.run_cell('%doesntexist')
89 result = _ip.run_cell('%doesntexist')
90 assert isinstance(result.error_in_exec, UsageError)
90 assert isinstance(result.error_in_exec, UsageError)
91
91
92
92
93 def test_cell_magic_not_found():
93 def test_cell_magic_not_found():
94 # magic not found raises UsageError
94 # magic not found raises UsageError
95 with pytest.raises(UsageError):
95 with pytest.raises(UsageError):
96 _ip.run_cell_magic('doesntexist', 'line', 'cell')
96 _ip.run_cell_magic('doesntexist', 'line', 'cell')
97
97
98 # ensure result isn't success when a magic isn't found
98 # ensure result isn't success when a magic isn't found
99 result = _ip.run_cell('%%doesntexist')
99 result = _ip.run_cell('%%doesntexist')
100 assert isinstance(result.error_in_exec, UsageError)
100 assert isinstance(result.error_in_exec, UsageError)
101
101
102
102
103 def test_magic_error_status():
103 def test_magic_error_status():
104 def fail(shell):
104 def fail(shell):
105 1/0
105 1/0
106 _ip.register_magic_function(fail)
106 _ip.register_magic_function(fail)
107 result = _ip.run_cell('%fail')
107 result = _ip.run_cell('%fail')
108 assert isinstance(result.error_in_exec, ZeroDivisionError)
108 assert isinstance(result.error_in_exec, ZeroDivisionError)
109
109
110
110
111 def test_config():
111 def test_config():
112 """ test that config magic does not raise
112 """ test that config magic does not raise
113 can happen if Configurable init is moved too early into
113 can happen if Configurable init is moved too early into
114 Magics.__init__ as then a Config object will be registered as a
114 Magics.__init__ as then a Config object will be registered as a
115 magic.
115 magic.
116 """
116 """
117 ## should not raise.
117 ## should not raise.
118 _ip.magic('config')
118 _ip.magic('config')
119
119
120 def test_config_available_configs():
120 def test_config_available_configs():
121 """ test that config magic prints available configs in unique and
121 """ test that config magic prints available configs in unique and
122 sorted order. """
122 sorted order. """
123 with capture_output() as captured:
123 with capture_output() as captured:
124 _ip.magic('config')
124 _ip.magic('config')
125
125
126 stdout = captured.stdout
126 stdout = captured.stdout
127 config_classes = stdout.strip().split('\n')[1:]
127 config_classes = stdout.strip().split('\n')[1:]
128 assert config_classes == sorted(set(config_classes))
128 assert config_classes == sorted(set(config_classes))
129
129
130 def test_config_print_class():
130 def test_config_print_class():
131 """ test that config with a classname prints the class's options. """
131 """ test that config with a classname prints the class's options. """
132 with capture_output() as captured:
132 with capture_output() as captured:
133 _ip.magic('config TerminalInteractiveShell')
133 _ip.magic('config TerminalInteractiveShell')
134
134
135 stdout = captured.stdout
135 stdout = captured.stdout
136 assert re.match(
136 assert re.match(
137 "TerminalInteractiveShell.* options", stdout.splitlines()[0]
137 "TerminalInteractiveShell.* options", stdout.splitlines()[0]
138 ), f"{stdout}\n\n1st line of stdout not like 'TerminalInteractiveShell.* options'"
138 ), f"{stdout}\n\n1st line of stdout not like 'TerminalInteractiveShell.* options'"
139
139
140
140
141 def test_rehashx():
141 def test_rehashx():
142 # clear up everything
142 # clear up everything
143 _ip.alias_manager.clear_aliases()
143 _ip.alias_manager.clear_aliases()
144 del _ip.db['syscmdlist']
144 del _ip.db['syscmdlist']
145
145
146 _ip.magic('rehashx')
146 _ip.magic('rehashx')
147 # Practically ALL ipython development systems will have more than 10 aliases
147 # Practically ALL ipython development systems will have more than 10 aliases
148
148
149 assert len(_ip.alias_manager.aliases) > 10
149 assert len(_ip.alias_manager.aliases) > 10
150 for name, cmd in _ip.alias_manager.aliases:
150 for name, cmd in _ip.alias_manager.aliases:
151 # we must strip dots from alias names
151 # we must strip dots from alias names
152 assert "." not in name
152 assert "." not in name
153
153
154 # rehashx must fill up syscmdlist
154 # rehashx must fill up syscmdlist
155 scoms = _ip.db['syscmdlist']
155 scoms = _ip.db['syscmdlist']
156 assert len(scoms) > 10
156 assert len(scoms) > 10
157
157
158
158
159 def test_magic_parse_options():
159 def test_magic_parse_options():
160 """Test that we don't mangle paths when parsing magic options."""
160 """Test that we don't mangle paths when parsing magic options."""
161 ip = get_ipython()
161 ip = get_ipython()
162 path = 'c:\\x'
162 path = 'c:\\x'
163 m = DummyMagics(ip)
163 m = DummyMagics(ip)
164 opts = m.parse_options('-f %s' % path,'f:')[0]
164 opts = m.parse_options('-f %s' % path,'f:')[0]
165 # argv splitting is os-dependent
165 # argv splitting is os-dependent
166 if os.name == 'posix':
166 if os.name == 'posix':
167 expected = 'c:x'
167 expected = 'c:x'
168 else:
168 else:
169 expected = path
169 expected = path
170 assert opts["f"] == expected
170 assert opts["f"] == expected
171
171
172
172
173 def test_magic_parse_long_options():
173 def test_magic_parse_long_options():
174 """Magic.parse_options can handle --foo=bar long options"""
174 """Magic.parse_options can handle --foo=bar long options"""
175 ip = get_ipython()
175 ip = get_ipython()
176 m = DummyMagics(ip)
176 m = DummyMagics(ip)
177 opts, _ = m.parse_options("--foo --bar=bubble", "a", "foo", "bar=")
177 opts, _ = m.parse_options("--foo --bar=bubble", "a", "foo", "bar=")
178 assert "foo" in opts
178 assert "foo" in opts
179 assert "bar" in opts
179 assert "bar" in opts
180 assert opts["bar"] == "bubble"
180 assert opts["bar"] == "bubble"
181
181
182
182
183 def doctest_hist_f():
183 def doctest_hist_f():
184 """Test %hist -f with temporary filename.
184 """Test %hist -f with temporary filename.
185
185
186 In [9]: import tempfile
186 In [9]: import tempfile
187
187
188 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
188 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
189
189
190 In [11]: %hist -nl -f $tfile 3
190 In [11]: %hist -nl -f $tfile 3
191
191
192 In [13]: import os; os.unlink(tfile)
192 In [13]: import os; os.unlink(tfile)
193 """
193 """
194
194
195
195
196 def doctest_hist_op():
196 def doctest_hist_op():
197 """Test %hist -op
197 """Test %hist -op
198
198
199 In [1]: class b(float):
199 In [1]: class b(float):
200 ...: pass
200 ...: pass
201 ...:
201 ...:
202
202
203 In [2]: class s(object):
203 In [2]: class s(object):
204 ...: def __str__(self):
204 ...: def __str__(self):
205 ...: return 's'
205 ...: return 's'
206 ...:
206 ...:
207
207
208 In [3]:
208 In [3]:
209
209
210 In [4]: class r(b):
210 In [4]: class r(b):
211 ...: def __repr__(self):
211 ...: def __repr__(self):
212 ...: return 'r'
212 ...: return 'r'
213 ...:
213 ...:
214
214
215 In [5]: class sr(s,r): pass
215 In [5]: class sr(s,r): pass
216 ...:
216 ...:
217
217
218 In [6]:
218 In [6]:
219
219
220 In [7]: bb=b()
220 In [7]: bb=b()
221
221
222 In [8]: ss=s()
222 In [8]: ss=s()
223
223
224 In [9]: rr=r()
224 In [9]: rr=r()
225
225
226 In [10]: ssrr=sr()
226 In [10]: ssrr=sr()
227
227
228 In [11]: 4.5
228 In [11]: 4.5
229 Out[11]: 4.5
229 Out[11]: 4.5
230
230
231 In [12]: str(ss)
231 In [12]: str(ss)
232 Out[12]: 's'
232 Out[12]: 's'
233
233
234 In [13]:
234 In [13]:
235
235
236 In [14]: %hist -op
236 In [14]: %hist -op
237 >>> class b:
237 >>> class b:
238 ... pass
238 ... pass
239 ...
239 ...
240 >>> class s(b):
240 >>> class s(b):
241 ... def __str__(self):
241 ... def __str__(self):
242 ... return 's'
242 ... return 's'
243 ...
243 ...
244 >>>
244 >>>
245 >>> class r(b):
245 >>> class r(b):
246 ... def __repr__(self):
246 ... def __repr__(self):
247 ... return 'r'
247 ... return 'r'
248 ...
248 ...
249 >>> class sr(s,r): pass
249 >>> class sr(s,r): pass
250 >>>
250 >>>
251 >>> bb=b()
251 >>> bb=b()
252 >>> ss=s()
252 >>> ss=s()
253 >>> rr=r()
253 >>> rr=r()
254 >>> ssrr=sr()
254 >>> ssrr=sr()
255 >>> 4.5
255 >>> 4.5
256 4.5
256 4.5
257 >>> str(ss)
257 >>> str(ss)
258 's'
258 's'
259 >>>
259 >>>
260 """
260 """
261
261
262 def test_hist_pof():
262 def test_hist_pof():
263 ip = get_ipython()
263 ip = get_ipython()
264 ip.run_cell("1+2", store_history=True)
264 ip.run_cell("1+2", store_history=True)
265 #raise Exception(ip.history_manager.session_number)
265 #raise Exception(ip.history_manager.session_number)
266 #raise Exception(list(ip.history_manager._get_range_session()))
266 #raise Exception(list(ip.history_manager._get_range_session()))
267 with TemporaryDirectory() as td:
267 with TemporaryDirectory() as td:
268 tf = os.path.join(td, 'hist.py')
268 tf = os.path.join(td, 'hist.py')
269 ip.run_line_magic('history', '-pof %s' % tf)
269 ip.run_line_magic('history', '-pof %s' % tf)
270 assert os.path.isfile(tf)
270 assert os.path.isfile(tf)
271
271
272
272
273 def test_macro():
273 def test_macro():
274 ip = get_ipython()
274 ip = get_ipython()
275 ip.history_manager.reset() # Clear any existing history.
275 ip.history_manager.reset() # Clear any existing history.
276 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
276 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
277 for i, cmd in enumerate(cmds, start=1):
277 for i, cmd in enumerate(cmds, start=1):
278 ip.history_manager.store_inputs(i, cmd)
278 ip.history_manager.store_inputs(i, cmd)
279 ip.magic("macro test 1-3")
279 ip.magic("macro test 1-3")
280 assert ip.user_ns["test"].value == "\n".join(cmds) + "\n"
280 assert ip.user_ns["test"].value == "\n".join(cmds) + "\n"
281
281
282 # List macros
282 # List macros
283 assert "test" in ip.magic("macro")
283 assert "test" in ip.magic("macro")
284
284
285
285
286 def test_macro_run():
286 def test_macro_run():
287 """Test that we can run a multi-line macro successfully."""
287 """Test that we can run a multi-line macro successfully."""
288 ip = get_ipython()
288 ip = get_ipython()
289 ip.history_manager.reset()
289 ip.history_manager.reset()
290 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
290 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
291 for cmd in cmds:
291 for cmd in cmds:
292 ip.run_cell(cmd, store_history=True)
292 ip.run_cell(cmd, store_history=True)
293 assert ip.user_ns["test"].value == "a+=1\nprint(a)\n"
293 assert ip.user_ns["test"].value == "a+=1\nprint(a)\n"
294 with tt.AssertPrints("12"):
294 with tt.AssertPrints("12"):
295 ip.run_cell("test")
295 ip.run_cell("test")
296 with tt.AssertPrints("13"):
296 with tt.AssertPrints("13"):
297 ip.run_cell("test")
297 ip.run_cell("test")
298
298
299
299
300 def test_magic_magic():
300 def test_magic_magic():
301 """Test %magic"""
301 """Test %magic"""
302 ip = get_ipython()
302 ip = get_ipython()
303 with capture_output() as captured:
303 with capture_output() as captured:
304 ip.magic("magic")
304 ip.magic("magic")
305
305
306 stdout = captured.stdout
306 stdout = captured.stdout
307 assert "%magic" in stdout
307 assert "%magic" in stdout
308 assert "IPython" in stdout
308 assert "IPython" in stdout
309 assert "Available" in stdout
309 assert "Available" in stdout
310
310
311
311
312 @dec.skipif_not_numpy
312 @dec.skipif_not_numpy
313 def test_numpy_reset_array_undec():
313 def test_numpy_reset_array_undec():
314 "Test '%reset array' functionality"
314 "Test '%reset array' functionality"
315 _ip.ex("import numpy as np")
315 _ip.ex("import numpy as np")
316 _ip.ex("a = np.empty(2)")
316 _ip.ex("a = np.empty(2)")
317 assert "a" in _ip.user_ns
317 assert "a" in _ip.user_ns
318 _ip.magic("reset -f array")
318 _ip.magic("reset -f array")
319 assert "a" not in _ip.user_ns
319 assert "a" not in _ip.user_ns
320
320
321
321
322 def test_reset_out():
322 def test_reset_out():
323 "Test '%reset out' magic"
323 "Test '%reset out' magic"
324 _ip.run_cell("parrot = 'dead'", store_history=True)
324 _ip.run_cell("parrot = 'dead'", store_history=True)
325 # test '%reset -f out', make an Out prompt
325 # test '%reset -f out', make an Out prompt
326 _ip.run_cell("parrot", store_history=True)
326 _ip.run_cell("parrot", store_history=True)
327 assert "dead" in [_ip.user_ns[x] for x in ("_", "__", "___")]
327 assert "dead" in [_ip.user_ns[x] for x in ("_", "__", "___")]
328 _ip.magic("reset -f out")
328 _ip.magic("reset -f out")
329 assert "dead" not in [_ip.user_ns[x] for x in ("_", "__", "___")]
329 assert "dead" not in [_ip.user_ns[x] for x in ("_", "__", "___")]
330 assert len(_ip.user_ns["Out"]) == 0
330 assert len(_ip.user_ns["Out"]) == 0
331
331
332
332
333 def test_reset_in():
333 def test_reset_in():
334 "Test '%reset in' magic"
334 "Test '%reset in' magic"
335 # test '%reset -f in'
335 # test '%reset -f in'
336 _ip.run_cell("parrot", store_history=True)
336 _ip.run_cell("parrot", store_history=True)
337 assert "parrot" in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
337 assert "parrot" in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
338 _ip.magic("%reset -f in")
338 _ip.magic("%reset -f in")
339 assert "parrot" not in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
339 assert "parrot" not in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
340 assert len(set(_ip.user_ns["In"])) == 1
340 assert len(set(_ip.user_ns["In"])) == 1
341
341
342
342
343 def test_reset_dhist():
343 def test_reset_dhist():
344 "Test '%reset dhist' magic"
344 "Test '%reset dhist' magic"
345 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
345 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
346 _ip.magic("cd " + os.path.dirname(pytest.__file__))
346 _ip.magic("cd " + os.path.dirname(pytest.__file__))
347 _ip.magic("cd -")
347 _ip.magic("cd -")
348 assert len(_ip.user_ns["_dh"]) > 0
348 assert len(_ip.user_ns["_dh"]) > 0
349 _ip.magic("reset -f dhist")
349 _ip.magic("reset -f dhist")
350 assert len(_ip.user_ns["_dh"]) == 0
350 assert len(_ip.user_ns["_dh"]) == 0
351 _ip.run_cell("_dh = [d for d in tmp]") # restore
351 _ip.run_cell("_dh = [d for d in tmp]") # restore
352
352
353
353
354 def test_reset_in_length():
354 def test_reset_in_length():
355 "Test that '%reset in' preserves In[] length"
355 "Test that '%reset in' preserves In[] length"
356 _ip.run_cell("print 'foo'")
356 _ip.run_cell("print 'foo'")
357 _ip.run_cell("reset -f in")
357 _ip.run_cell("reset -f in")
358 assert len(_ip.user_ns["In"]) == _ip.displayhook.prompt_count + 1
358 assert len(_ip.user_ns["In"]) == _ip.displayhook.prompt_count + 1
359
359
360
360
361 class TestResetErrors(TestCase):
361 class TestResetErrors(TestCase):
362
362
363 def test_reset_redefine(self):
363 def test_reset_redefine(self):
364
364
365 @magics_class
365 @magics_class
366 class KernelMagics(Magics):
366 class KernelMagics(Magics):
367 @line_magic
367 @line_magic
368 def less(self, shell): pass
368 def less(self, shell): pass
369
369
370 _ip.register_magics(KernelMagics)
370 _ip.register_magics(KernelMagics)
371
371
372 with self.assertLogs() as cm:
372 with self.assertLogs() as cm:
373 # hack, we want to just capture logs, but assertLogs fails if not
373 # hack, we want to just capture logs, but assertLogs fails if not
374 # logs get produce.
374 # logs get produce.
375 # so log one things we ignore.
375 # so log one things we ignore.
376 import logging as log_mod
376 import logging as log_mod
377 log = log_mod.getLogger()
377 log = log_mod.getLogger()
378 log.info('Nothing')
378 log.info('Nothing')
379 # end hack.
379 # end hack.
380 _ip.run_cell("reset -f")
380 _ip.run_cell("reset -f")
381
381
382 assert len(cm.output) == 1
382 assert len(cm.output) == 1
383 for out in cm.output:
383 for out in cm.output:
384 assert "Invalid alias" not in out
384 assert "Invalid alias" not in out
385
385
386 def test_tb_syntaxerror():
386 def test_tb_syntaxerror():
387 """test %tb after a SyntaxError"""
387 """test %tb after a SyntaxError"""
388 ip = get_ipython()
388 ip = get_ipython()
389 ip.run_cell("for")
389 ip.run_cell("for")
390
390
391 # trap and validate stdout
391 # trap and validate stdout
392 save_stdout = sys.stdout
392 save_stdout = sys.stdout
393 try:
393 try:
394 sys.stdout = StringIO()
394 sys.stdout = StringIO()
395 ip.run_cell("%tb")
395 ip.run_cell("%tb")
396 out = sys.stdout.getvalue()
396 out = sys.stdout.getvalue()
397 finally:
397 finally:
398 sys.stdout = save_stdout
398 sys.stdout = save_stdout
399 # trim output, and only check the last line
399 # trim output, and only check the last line
400 last_line = out.rstrip().splitlines()[-1].strip()
400 last_line = out.rstrip().splitlines()[-1].strip()
401 assert last_line == "SyntaxError: invalid syntax"
401 assert last_line == "SyntaxError: invalid syntax"
402
402
403
403
404 def test_time():
404 def test_time():
405 ip = get_ipython()
405 ip = get_ipython()
406
406
407 with tt.AssertPrints("Wall time: "):
407 with tt.AssertPrints("Wall time: "):
408 ip.run_cell("%time None")
408 ip.run_cell("%time None")
409
409
410 ip.run_cell("def f(kmjy):\n"
410 ip.run_cell("def f(kmjy):\n"
411 " %time print (2*kmjy)")
411 " %time print (2*kmjy)")
412
412
413 with tt.AssertPrints("Wall time: "):
413 with tt.AssertPrints("Wall time: "):
414 with tt.AssertPrints("hihi", suppress=False):
414 with tt.AssertPrints("hihi", suppress=False):
415 ip.run_cell("f('hi')")
415 ip.run_cell("f('hi')")
416
416
417 def test_time_last_not_expression():
417 def test_time_last_not_expression():
418 ip.run_cell("%%time\n"
418 ip.run_cell("%%time\n"
419 "var_1 = 1\n"
419 "var_1 = 1\n"
420 "var_2 = 2\n")
420 "var_2 = 2\n")
421 assert ip.user_ns['var_1'] == 1
421 assert ip.user_ns['var_1'] == 1
422 del ip.user_ns['var_1']
422 del ip.user_ns['var_1']
423 assert ip.user_ns['var_2'] == 2
423 assert ip.user_ns['var_2'] == 2
424 del ip.user_ns['var_2']
424 del ip.user_ns['var_2']
425
425
426
426
427 @dec.skip_win32
427 @dec.skip_win32
428 def test_time2():
428 def test_time2():
429 ip = get_ipython()
429 ip = get_ipython()
430
430
431 with tt.AssertPrints("CPU times: user "):
431 with tt.AssertPrints("CPU times: user "):
432 ip.run_cell("%time None")
432 ip.run_cell("%time None")
433
433
434 def test_time3():
434 def test_time3():
435 """Erroneous magic function calls, issue gh-3334"""
435 """Erroneous magic function calls, issue gh-3334"""
436 ip = get_ipython()
436 ip = get_ipython()
437 ip.user_ns.pop('run', None)
437 ip.user_ns.pop('run', None)
438
438
439 with tt.AssertNotPrints("not found", channel='stderr'):
439 with tt.AssertNotPrints("not found", channel='stderr'):
440 ip.run_cell("%%time\n"
440 ip.run_cell("%%time\n"
441 "run = 0\n"
441 "run = 0\n"
442 "run += 1")
442 "run += 1")
443
443
444 def test_multiline_time():
444 def test_multiline_time():
445 """Make sure last statement from time return a value."""
445 """Make sure last statement from time return a value."""
446 ip = get_ipython()
446 ip = get_ipython()
447 ip.user_ns.pop('run', None)
447 ip.user_ns.pop('run', None)
448
448
449 ip.run_cell(dedent("""\
449 ip.run_cell(dedent("""\
450 %%time
450 %%time
451 a = "ho"
451 a = "ho"
452 b = "hey"
452 b = "hey"
453 a+b
453 a+b
454 """
454 """
455 )
455 )
456 )
456 )
457 assert ip.user_ns_hidden["_"] == "hohey"
457 assert ip.user_ns_hidden["_"] == "hohey"
458
458
459
459
460 def test_time_local_ns():
460 def test_time_local_ns():
461 """
461 """
462 Test that local_ns is actually global_ns when running a cell magic
462 Test that local_ns is actually global_ns when running a cell magic
463 """
463 """
464 ip = get_ipython()
464 ip = get_ipython()
465 ip.run_cell("%%time\n" "myvar = 1")
465 ip.run_cell("%%time\n" "myvar = 1")
466 assert ip.user_ns["myvar"] == 1
466 assert ip.user_ns["myvar"] == 1
467 del ip.user_ns["myvar"]
467 del ip.user_ns["myvar"]
468
468
469
469
470 def test_doctest_mode():
470 def test_doctest_mode():
471 "Toggle doctest_mode twice, it should be a no-op and run without error"
471 "Toggle doctest_mode twice, it should be a no-op and run without error"
472 _ip.magic('doctest_mode')
472 _ip.magic('doctest_mode')
473 _ip.magic('doctest_mode')
473 _ip.magic('doctest_mode')
474
474
475
475
476 def test_parse_options():
476 def test_parse_options():
477 """Tests for basic options parsing in magics."""
477 """Tests for basic options parsing in magics."""
478 # These are only the most minimal of tests, more should be added later. At
478 # These are only the most minimal of tests, more should be added later. At
479 # the very least we check that basic text/unicode calls work OK.
479 # the very least we check that basic text/unicode calls work OK.
480 m = DummyMagics(_ip)
480 m = DummyMagics(_ip)
481 assert m.parse_options("foo", "")[1] == "foo"
481 assert m.parse_options("foo", "")[1] == "foo"
482 assert m.parse_options("foo", "")[1] == "foo"
482 assert m.parse_options("foo", "")[1] == "foo"
483
483
484
484
485 def test_parse_options_preserve_non_option_string():
485 def test_parse_options_preserve_non_option_string():
486 """Test to assert preservation of non-option part of magic-block, while parsing magic options."""
486 """Test to assert preservation of non-option part of magic-block, while parsing magic options."""
487 m = DummyMagics(_ip)
487 m = DummyMagics(_ip)
488 opts, stmt = m.parse_options(
488 opts, stmt = m.parse_options(
489 " -n1 -r 13 _ = 314 + foo", "n:r:", preserve_non_opts=True
489 " -n1 -r 13 _ = 314 + foo", "n:r:", preserve_non_opts=True
490 )
490 )
491 assert opts == {"n": "1", "r": "13"}
491 assert opts == {"n": "1", "r": "13"}
492 assert stmt == "_ = 314 + foo"
492 assert stmt == "_ = 314 + foo"
493
493
494
494
495 def test_run_magic_preserve_code_block():
495 def test_run_magic_preserve_code_block():
496 """Test to assert preservation of non-option part of magic-block, while running magic."""
496 """Test to assert preservation of non-option part of magic-block, while running magic."""
497 _ip.user_ns["spaces"] = []
497 _ip.user_ns["spaces"] = []
498 _ip.magic("timeit -n1 -r1 spaces.append([s.count(' ') for s in ['document']])")
498 _ip.magic("timeit -n1 -r1 spaces.append([s.count(' ') for s in ['document']])")
499 assert _ip.user_ns["spaces"] == [[0]]
499 assert _ip.user_ns["spaces"] == [[0]]
500
500
501
501
502 def test_dirops():
502 def test_dirops():
503 """Test various directory handling operations."""
503 """Test various directory handling operations."""
504 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
504 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
505 curpath = os.getcwd
505 curpath = os.getcwd
506 startdir = os.getcwd()
506 startdir = os.getcwd()
507 ipdir = os.path.realpath(_ip.ipython_dir)
507 ipdir = os.path.realpath(_ip.ipython_dir)
508 try:
508 try:
509 _ip.magic('cd "%s"' % ipdir)
509 _ip.magic('cd "%s"' % ipdir)
510 assert curpath() == ipdir
510 assert curpath() == ipdir
511 _ip.magic('cd -')
511 _ip.magic('cd -')
512 assert curpath() == startdir
512 assert curpath() == startdir
513 _ip.magic('pushd "%s"' % ipdir)
513 _ip.magic('pushd "%s"' % ipdir)
514 assert curpath() == ipdir
514 assert curpath() == ipdir
515 _ip.magic('popd')
515 _ip.magic('popd')
516 assert curpath() == startdir
516 assert curpath() == startdir
517 finally:
517 finally:
518 os.chdir(startdir)
518 os.chdir(startdir)
519
519
520
520
521 def test_cd_force_quiet():
521 def test_cd_force_quiet():
522 """Test OSMagics.cd_force_quiet option"""
522 """Test OSMagics.cd_force_quiet option"""
523 _ip.config.OSMagics.cd_force_quiet = True
523 _ip.config.OSMagics.cd_force_quiet = True
524 osmagics = osm.OSMagics(shell=_ip)
524 osmagics = osm.OSMagics(shell=_ip)
525
525
526 startdir = os.getcwd()
526 startdir = os.getcwd()
527 ipdir = os.path.realpath(_ip.ipython_dir)
527 ipdir = os.path.realpath(_ip.ipython_dir)
528
528
529 try:
529 try:
530 with tt.AssertNotPrints(ipdir):
530 with tt.AssertNotPrints(ipdir):
531 osmagics.cd('"%s"' % ipdir)
531 osmagics.cd('"%s"' % ipdir)
532 with tt.AssertNotPrints(startdir):
532 with tt.AssertNotPrints(startdir):
533 osmagics.cd('-')
533 osmagics.cd('-')
534 finally:
534 finally:
535 os.chdir(startdir)
535 os.chdir(startdir)
536
536
537
537
538 def test_xmode():
538 def test_xmode():
539 # Calling xmode three times should be a no-op
539 # Calling xmode three times should be a no-op
540 xmode = _ip.InteractiveTB.mode
540 xmode = _ip.InteractiveTB.mode
541 for i in range(4):
541 for i in range(4):
542 _ip.magic("xmode")
542 _ip.magic("xmode")
543 assert _ip.InteractiveTB.mode == xmode
543 assert _ip.InteractiveTB.mode == xmode
544
544
545 def test_reset_hard():
545 def test_reset_hard():
546 monitor = []
546 monitor = []
547 class A(object):
547 class A(object):
548 def __del__(self):
548 def __del__(self):
549 monitor.append(1)
549 monitor.append(1)
550 def __repr__(self):
550 def __repr__(self):
551 return "<A instance>"
551 return "<A instance>"
552
552
553 _ip.user_ns["a"] = A()
553 _ip.user_ns["a"] = A()
554 _ip.run_cell("a")
554 _ip.run_cell("a")
555
555
556 assert monitor == []
556 assert monitor == []
557 _ip.magic("reset -f")
557 _ip.magic("reset -f")
558 assert monitor == [1]
558 assert monitor == [1]
559
559
560 class TestXdel(tt.TempFileMixin):
560 class TestXdel(tt.TempFileMixin):
561 def test_xdel(self):
561 def test_xdel(self):
562 """Test that references from %run are cleared by xdel."""
562 """Test that references from %run are cleared by xdel."""
563 src = ("class A(object):\n"
563 src = ("class A(object):\n"
564 " monitor = []\n"
564 " monitor = []\n"
565 " def __del__(self):\n"
565 " def __del__(self):\n"
566 " self.monitor.append(1)\n"
566 " self.monitor.append(1)\n"
567 "a = A()\n")
567 "a = A()\n")
568 self.mktmp(src)
568 self.mktmp(src)
569 # %run creates some hidden references...
569 # %run creates some hidden references...
570 _ip.magic("run %s" % self.fname)
570 _ip.magic("run %s" % self.fname)
571 # ... as does the displayhook.
571 # ... as does the displayhook.
572 _ip.run_cell("a")
572 _ip.run_cell("a")
573
573
574 monitor = _ip.user_ns["A"].monitor
574 monitor = _ip.user_ns["A"].monitor
575 assert monitor == []
575 assert monitor == []
576
576
577 _ip.magic("xdel a")
577 _ip.magic("xdel a")
578
578
579 # Check that a's __del__ method has been called.
579 # Check that a's __del__ method has been called.
580 gc.collect(0)
580 gc.collect(0)
581 assert monitor == [1]
581 assert monitor == [1]
582
582
583 def doctest_who():
583 def doctest_who():
584 """doctest for %who
584 """doctest for %who
585
585
586 In [1]: %reset -sf
586 In [1]: %reset -sf
587
587
588 In [2]: alpha = 123
588 In [2]: alpha = 123
589
589
590 In [3]: beta = 'beta'
590 In [3]: beta = 'beta'
591
591
592 In [4]: %who int
592 In [4]: %who int
593 alpha
593 alpha
594
594
595 In [5]: %who str
595 In [5]: %who str
596 beta
596 beta
597
597
598 In [6]: %whos
598 In [6]: %whos
599 Variable Type Data/Info
599 Variable Type Data/Info
600 ----------------------------
600 ----------------------------
601 alpha int 123
601 alpha int 123
602 beta str beta
602 beta str beta
603
603
604 In [7]: %who_ls
604 In [7]: %who_ls
605 Out[7]: ['alpha', 'beta']
605 Out[7]: ['alpha', 'beta']
606 """
606 """
607
607
608 def test_whos():
608 def test_whos():
609 """Check that whos is protected against objects where repr() fails."""
609 """Check that whos is protected against objects where repr() fails."""
610 class A(object):
610 class A(object):
611 def __repr__(self):
611 def __repr__(self):
612 raise Exception()
612 raise Exception()
613 _ip.user_ns['a'] = A()
613 _ip.user_ns['a'] = A()
614 _ip.magic("whos")
614 _ip.magic("whos")
615
615
616 def doctest_precision():
616 def doctest_precision():
617 """doctest for %precision
617 """doctest for %precision
618
618
619 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
619 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
620
620
621 In [2]: %precision 5
621 In [2]: %precision 5
622 Out[2]: '%.5f'
622 Out[2]: '%.5f'
623
623
624 In [3]: f.float_format
624 In [3]: f.float_format
625 Out[3]: '%.5f'
625 Out[3]: '%.5f'
626
626
627 In [4]: %precision %e
627 In [4]: %precision %e
628 Out[4]: '%e'
628 Out[4]: '%e'
629
629
630 In [5]: f(3.1415927)
630 In [5]: f(3.1415927)
631 Out[5]: '3.141593e+00'
631 Out[5]: '3.141593e+00'
632 """
632 """
633
633
634 def test_debug_magic():
634 def test_debug_magic():
635 """Test debugging a small code with %debug
635 """Test debugging a small code with %debug
636
636
637 In [1]: with PdbTestInput(['c']):
637 In [1]: with PdbTestInput(['c']):
638 ...: %debug print("a b") #doctest: +ELLIPSIS
638 ...: %debug print("a b") #doctest: +ELLIPSIS
639 ...:
639 ...:
640 ...
640 ...
641 ipdb> c
641 ipdb> c
642 a b
642 a b
643 In [2]:
643 In [2]:
644 """
644 """
645
645
646 def test_psearch():
646 def test_psearch():
647 with tt.AssertPrints("dict.fromkeys"):
647 with tt.AssertPrints("dict.fromkeys"):
648 _ip.run_cell("dict.fr*?")
648 _ip.run_cell("dict.fr*?")
649 with tt.AssertPrints("π.is_integer"):
649 with tt.AssertPrints("π.is_integer"):
650 _ip.run_cell("π = 3.14;\nπ.is_integ*?")
650 _ip.run_cell("π = 3.14;\nπ.is_integ*?")
651
651
652 def test_timeit_shlex():
652 def test_timeit_shlex():
653 """test shlex issues with timeit (#1109)"""
653 """test shlex issues with timeit (#1109)"""
654 _ip.ex("def f(*a,**kw): pass")
654 _ip.ex("def f(*a,**kw): pass")
655 _ip.magic('timeit -n1 "this is a bug".count(" ")')
655 _ip.magic('timeit -n1 "this is a bug".count(" ")')
656 _ip.magic('timeit -r1 -n1 f(" ", 1)')
656 _ip.magic('timeit -r1 -n1 f(" ", 1)')
657 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
657 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
658 _ip.magic('timeit -r1 -n1 ("a " + "b")')
658 _ip.magic('timeit -r1 -n1 ("a " + "b")')
659 _ip.magic('timeit -r1 -n1 f("a " + "b")')
659 _ip.magic('timeit -r1 -n1 f("a " + "b")')
660 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
660 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
661
661
662
662
663 def test_timeit_special_syntax():
663 def test_timeit_special_syntax():
664 "Test %%timeit with IPython special syntax"
664 "Test %%timeit with IPython special syntax"
665 @register_line_magic
665 @register_line_magic
666 def lmagic(line):
666 def lmagic(line):
667 ip = get_ipython()
667 ip = get_ipython()
668 ip.user_ns['lmagic_out'] = line
668 ip.user_ns['lmagic_out'] = line
669
669
670 # line mode test
670 # line mode test
671 _ip.run_line_magic("timeit", "-n1 -r1 %lmagic my line")
671 _ip.run_line_magic("timeit", "-n1 -r1 %lmagic my line")
672 assert _ip.user_ns["lmagic_out"] == "my line"
672 assert _ip.user_ns["lmagic_out"] == "my line"
673 # cell mode test
673 # cell mode test
674 _ip.run_cell_magic("timeit", "-n1 -r1", "%lmagic my line2")
674 _ip.run_cell_magic("timeit", "-n1 -r1", "%lmagic my line2")
675 assert _ip.user_ns["lmagic_out"] == "my line2"
675 assert _ip.user_ns["lmagic_out"] == "my line2"
676
676
677
677
678 def test_timeit_return():
678 def test_timeit_return():
679 """
679 """
680 test whether timeit -o return object
680 test whether timeit -o return object
681 """
681 """
682
682
683 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
683 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
684 assert(res is not None)
684 assert(res is not None)
685
685
686 def test_timeit_quiet():
686 def test_timeit_quiet():
687 """
687 """
688 test quiet option of timeit magic
688 test quiet option of timeit magic
689 """
689 """
690 with tt.AssertNotPrints("loops"):
690 with tt.AssertNotPrints("loops"):
691 _ip.run_cell("%timeit -n1 -r1 -q 1")
691 _ip.run_cell("%timeit -n1 -r1 -q 1")
692
692
693 def test_timeit_return_quiet():
693 def test_timeit_return_quiet():
694 with tt.AssertNotPrints("loops"):
694 with tt.AssertNotPrints("loops"):
695 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
695 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
696 assert (res is not None)
696 assert (res is not None)
697
697
698 def test_timeit_invalid_return():
698 def test_timeit_invalid_return():
699 with pytest.raises(SyntaxError):
699 with pytest.raises(SyntaxError):
700 _ip.run_line_magic('timeit', 'return')
700 _ip.run_line_magic('timeit', 'return')
701
701
702 @dec.skipif(execution.profile is None)
702 @dec.skipif(execution.profile is None)
703 def test_prun_special_syntax():
703 def test_prun_special_syntax():
704 "Test %%prun with IPython special syntax"
704 "Test %%prun with IPython special syntax"
705 @register_line_magic
705 @register_line_magic
706 def lmagic(line):
706 def lmagic(line):
707 ip = get_ipython()
707 ip = get_ipython()
708 ip.user_ns['lmagic_out'] = line
708 ip.user_ns['lmagic_out'] = line
709
709
710 # line mode test
710 # line mode test
711 _ip.run_line_magic("prun", "-q %lmagic my line")
711 _ip.run_line_magic("prun", "-q %lmagic my line")
712 assert _ip.user_ns["lmagic_out"] == "my line"
712 assert _ip.user_ns["lmagic_out"] == "my line"
713 # cell mode test
713 # cell mode test
714 _ip.run_cell_magic("prun", "-q", "%lmagic my line2")
714 _ip.run_cell_magic("prun", "-q", "%lmagic my line2")
715 assert _ip.user_ns["lmagic_out"] == "my line2"
715 assert _ip.user_ns["lmagic_out"] == "my line2"
716
716
717
717
718 @dec.skipif(execution.profile is None)
718 @dec.skipif(execution.profile is None)
719 def test_prun_quotes():
719 def test_prun_quotes():
720 "Test that prun does not clobber string escapes (GH #1302)"
720 "Test that prun does not clobber string escapes (GH #1302)"
721 _ip.magic(r"prun -q x = '\t'")
721 _ip.magic(r"prun -q x = '\t'")
722 assert _ip.user_ns["x"] == "\t"
722 assert _ip.user_ns["x"] == "\t"
723
723
724
724
725 def test_extension():
725 def test_extension():
726 # Debugging information for failures of this test
726 # Debugging information for failures of this test
727 print('sys.path:')
727 print('sys.path:')
728 for p in sys.path:
728 for p in sys.path:
729 print(' ', p)
729 print(' ', p)
730 print('CWD', os.getcwd())
730 print('CWD', os.getcwd())
731
731
732 pytest.raises(ImportError, _ip.magic, "load_ext daft_extension")
732 pytest.raises(ImportError, _ip.magic, "load_ext daft_extension")
733 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
733 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
734 sys.path.insert(0, daft_path)
734 sys.path.insert(0, daft_path)
735 try:
735 try:
736 _ip.user_ns.pop('arq', None)
736 _ip.user_ns.pop('arq', None)
737 invalidate_caches() # Clear import caches
737 invalidate_caches() # Clear import caches
738 _ip.magic("load_ext daft_extension")
738 _ip.magic("load_ext daft_extension")
739 assert _ip.user_ns["arq"] == 185
739 assert _ip.user_ns["arq"] == 185
740 _ip.magic("unload_ext daft_extension")
740 _ip.magic("unload_ext daft_extension")
741 assert 'arq' not in _ip.user_ns
741 assert 'arq' not in _ip.user_ns
742 finally:
742 finally:
743 sys.path.remove(daft_path)
743 sys.path.remove(daft_path)
744
744
745
745
746 def test_notebook_export_json():
746 def test_notebook_export_json():
747 pytest.importorskip("nbformat")
747 pytest.importorskip("nbformat")
748 _ip = get_ipython()
748 _ip = get_ipython()
749 _ip.history_manager.reset() # Clear any existing history.
749 _ip.history_manager.reset() # Clear any existing history.
750 cmds = ["a=1", "def b():\n return a**2", "print('noël, été', b())"]
750 cmds = ["a=1", "def b():\n return a**2", "print('noël, été', b())"]
751 for i, cmd in enumerate(cmds, start=1):
751 for i, cmd in enumerate(cmds, start=1):
752 _ip.history_manager.store_inputs(i, cmd)
752 _ip.history_manager.store_inputs(i, cmd)
753 with TemporaryDirectory() as td:
753 with TemporaryDirectory() as td:
754 outfile = os.path.join(td, "nb.ipynb")
754 outfile = os.path.join(td, "nb.ipynb")
755 _ip.magic("notebook %s" % outfile)
755 _ip.magic("notebook %s" % outfile)
756
756
757
757
758 class TestEnv(TestCase):
758 class TestEnv(TestCase):
759
759
760 def test_env(self):
760 def test_env(self):
761 env = _ip.magic("env")
761 env = _ip.magic("env")
762 self.assertTrue(isinstance(env, dict))
762 self.assertTrue(isinstance(env, dict))
763
763
764 def test_env_secret(self):
764 def test_env_secret(self):
765 env = _ip.magic("env")
765 env = _ip.magic("env")
766 hidden = "<hidden>"
766 hidden = "<hidden>"
767 with mock.patch.dict(
767 with mock.patch.dict(
768 os.environ,
768 os.environ,
769 {
769 {
770 "API_KEY": "abc123",
770 "API_KEY": "abc123",
771 "SECRET_THING": "ssshhh",
771 "SECRET_THING": "ssshhh",
772 "JUPYTER_TOKEN": "",
772 "JUPYTER_TOKEN": "",
773 "VAR": "abc"
773 "VAR": "abc"
774 }
774 }
775 ):
775 ):
776 env = _ip.magic("env")
776 env = _ip.magic("env")
777 assert env["API_KEY"] == hidden
777 assert env["API_KEY"] == hidden
778 assert env["SECRET_THING"] == hidden
778 assert env["SECRET_THING"] == hidden
779 assert env["JUPYTER_TOKEN"] == hidden
779 assert env["JUPYTER_TOKEN"] == hidden
780 assert env["VAR"] == "abc"
780 assert env["VAR"] == "abc"
781
781
782 def test_env_get_set_simple(self):
782 def test_env_get_set_simple(self):
783 env = _ip.magic("env var val1")
783 env = _ip.magic("env var val1")
784 self.assertEqual(env, None)
784 self.assertEqual(env, None)
785 self.assertEqual(os.environ['var'], 'val1')
785 self.assertEqual(os.environ['var'], 'val1')
786 self.assertEqual(_ip.magic("env var"), 'val1')
786 self.assertEqual(_ip.magic("env var"), 'val1')
787 env = _ip.magic("env var=val2")
787 env = _ip.magic("env var=val2")
788 self.assertEqual(env, None)
788 self.assertEqual(env, None)
789 self.assertEqual(os.environ['var'], 'val2')
789 self.assertEqual(os.environ['var'], 'val2')
790
790
791 def test_env_get_set_complex(self):
791 def test_env_get_set_complex(self):
792 env = _ip.magic("env var 'val1 '' 'val2")
792 env = _ip.magic("env var 'val1 '' 'val2")
793 self.assertEqual(env, None)
793 self.assertEqual(env, None)
794 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
794 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
795 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
795 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
796 env = _ip.magic('env var=val2 val3="val4')
796 env = _ip.magic('env var=val2 val3="val4')
797 self.assertEqual(env, None)
797 self.assertEqual(env, None)
798 self.assertEqual(os.environ['var'], 'val2 val3="val4')
798 self.assertEqual(os.environ['var'], 'val2 val3="val4')
799
799
800 def test_env_set_bad_input(self):
800 def test_env_set_bad_input(self):
801 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
801 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
802
802
803 def test_env_set_whitespace(self):
803 def test_env_set_whitespace(self):
804 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
804 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
805
805
806
806
807 class CellMagicTestCase(TestCase):
807 class CellMagicTestCase(TestCase):
808
808
809 def check_ident(self, magic):
809 def check_ident(self, magic):
810 # Manually called, we get the result
810 # Manually called, we get the result
811 out = _ip.run_cell_magic(magic, "a", "b")
811 out = _ip.run_cell_magic(magic, "a", "b")
812 assert out == ("a", "b")
812 assert out == ("a", "b")
813 # Via run_cell, it goes into the user's namespace via displayhook
813 # Via run_cell, it goes into the user's namespace via displayhook
814 _ip.run_cell("%%" + magic + " c\nd\n")
814 _ip.run_cell("%%" + magic + " c\nd\n")
815 assert _ip.user_ns["_"] == ("c", "d\n")
815 assert _ip.user_ns["_"] == ("c", "d\n")
816
816
817 def test_cell_magic_func_deco(self):
817 def test_cell_magic_func_deco(self):
818 "Cell magic using simple decorator"
818 "Cell magic using simple decorator"
819 @register_cell_magic
819 @register_cell_magic
820 def cellm(line, cell):
820 def cellm(line, cell):
821 return line, cell
821 return line, cell
822
822
823 self.check_ident('cellm')
823 self.check_ident('cellm')
824
824
825 def test_cell_magic_reg(self):
825 def test_cell_magic_reg(self):
826 "Cell magic manually registered"
826 "Cell magic manually registered"
827 def cellm(line, cell):
827 def cellm(line, cell):
828 return line, cell
828 return line, cell
829
829
830 _ip.register_magic_function(cellm, 'cell', 'cellm2')
830 _ip.register_magic_function(cellm, 'cell', 'cellm2')
831 self.check_ident('cellm2')
831 self.check_ident('cellm2')
832
832
833 def test_cell_magic_class(self):
833 def test_cell_magic_class(self):
834 "Cell magics declared via a class"
834 "Cell magics declared via a class"
835 @magics_class
835 @magics_class
836 class MyMagics(Magics):
836 class MyMagics(Magics):
837
837
838 @cell_magic
838 @cell_magic
839 def cellm3(self, line, cell):
839 def cellm3(self, line, cell):
840 return line, cell
840 return line, cell
841
841
842 _ip.register_magics(MyMagics)
842 _ip.register_magics(MyMagics)
843 self.check_ident('cellm3')
843 self.check_ident('cellm3')
844
844
845 def test_cell_magic_class2(self):
845 def test_cell_magic_class2(self):
846 "Cell magics declared via a class, #2"
846 "Cell magics declared via a class, #2"
847 @magics_class
847 @magics_class
848 class MyMagics2(Magics):
848 class MyMagics2(Magics):
849
849
850 @cell_magic('cellm4')
850 @cell_magic('cellm4')
851 def cellm33(self, line, cell):
851 def cellm33(self, line, cell):
852 return line, cell
852 return line, cell
853
853
854 _ip.register_magics(MyMagics2)
854 _ip.register_magics(MyMagics2)
855 self.check_ident('cellm4')
855 self.check_ident('cellm4')
856 # Check that nothing is registered as 'cellm33'
856 # Check that nothing is registered as 'cellm33'
857 c33 = _ip.find_cell_magic('cellm33')
857 c33 = _ip.find_cell_magic('cellm33')
858 assert c33 == None
858 assert c33 == None
859
859
860 def test_file():
860 def test_file():
861 """Basic %%writefile"""
861 """Basic %%writefile"""
862 ip = get_ipython()
862 ip = get_ipython()
863 with TemporaryDirectory() as td:
863 with TemporaryDirectory() as td:
864 fname = os.path.join(td, 'file1')
864 fname = os.path.join(td, "file1")
865 ip.run_cell_magic("writefile", fname, u'\n'.join([
865 ip.run_cell_magic(
866 'line1',
866 "writefile",
867 'line2',
867 fname,
868 ]))
868 "\n".join(
869 s = Path(fname).read_text(encoding='utf-8')
869 [
870 "line1",
871 "line2",
872 ]
873 ),
874 )
875 s = Path(fname).read_text(encoding="utf-8")
870 assert "line1\n" in s
876 assert "line1\n" in s
871 assert "line2" in s
877 assert "line2" in s
872
878
873
879
874 @dec.skip_win32
880 @dec.skip_win32
875 def test_file_single_quote():
881 def test_file_single_quote():
876 """Basic %%writefile with embedded single quotes"""
882 """Basic %%writefile with embedded single quotes"""
877 ip = get_ipython()
883 ip = get_ipython()
878 with TemporaryDirectory() as td:
884 with TemporaryDirectory() as td:
879 fname = os.path.join(td, '\'file1\'')
885 fname = os.path.join(td, "'file1'")
880 ip.run_cell_magic("writefile", fname, u'\n'.join([
886 ip.run_cell_magic(
881 'line1',
887 "writefile",
882 'line2',
888 fname,
883 ]))
889 "\n".join(
884 s = Path(fname).read_text(encoding='utf-8')
890 [
891 "line1",
892 "line2",
893 ]
894 ),
895 )
896 s = Path(fname).read_text(encoding="utf-8")
885 assert "line1\n" in s
897 assert "line1\n" in s
886 assert "line2" in s
898 assert "line2" in s
887
899
888
900
889 @dec.skip_win32
901 @dec.skip_win32
890 def test_file_double_quote():
902 def test_file_double_quote():
891 """Basic %%writefile with embedded double quotes"""
903 """Basic %%writefile with embedded double quotes"""
892 ip = get_ipython()
904 ip = get_ipython()
893 with TemporaryDirectory() as td:
905 with TemporaryDirectory() as td:
894 fname = os.path.join(td, '"file1"')
906 fname = os.path.join(td, '"file1"')
895 ip.run_cell_magic("writefile", fname, u'\n'.join([
907 ip.run_cell_magic(
896 'line1',
908 "writefile",
897 'line2',
909 fname,
898 ]))
910 "\n".join(
899 s = Path(fname).read_text(encoding='utf-8')
911 [
912 "line1",
913 "line2",
914 ]
915 ),
916 )
917 s = Path(fname).read_text(encoding="utf-8")
900 assert "line1\n" in s
918 assert "line1\n" in s
901 assert "line2" in s
919 assert "line2" in s
902
920
903
921
904 def test_file_var_expand():
922 def test_file_var_expand():
905 """%%writefile $filename"""
923 """%%writefile $filename"""
906 ip = get_ipython()
924 ip = get_ipython()
907 with TemporaryDirectory() as td:
925 with TemporaryDirectory() as td:
908 fname = os.path.join(td, 'file1')
926 fname = os.path.join(td, "file1")
909 ip.user_ns['filename'] = fname
927 ip.user_ns["filename"] = fname
910 ip.run_cell_magic("writefile", '$filename', u'\n'.join([
928 ip.run_cell_magic(
911 'line1',
929 "writefile",
912 'line2',
930 "$filename",
913 ]))
931 "\n".join(
914 s = Path(fname).read_text(encoding='utf-8')
932 [
933 "line1",
934 "line2",
935 ]
936 ),
937 )
938 s = Path(fname).read_text(encoding="utf-8")
915 assert "line1\n" in s
939 assert "line1\n" in s
916 assert "line2" in s
940 assert "line2" in s
917
941
918
942
919 def test_file_unicode():
943 def test_file_unicode():
920 """%%writefile with unicode cell"""
944 """%%writefile with unicode cell"""
921 ip = get_ipython()
945 ip = get_ipython()
922 with TemporaryDirectory() as td:
946 with TemporaryDirectory() as td:
923 fname = os.path.join(td, 'file1')
947 fname = os.path.join(td, 'file1')
924 ip.run_cell_magic("writefile", fname, u'\n'.join([
948 ip.run_cell_magic("writefile", fname, u'\n'.join([
925 u'liné1',
949 u'liné1',
926 u'liné2',
950 u'liné2',
927 ]))
951 ]))
928 with io.open(fname, encoding='utf-8') as f:
952 with io.open(fname, encoding='utf-8') as f:
929 s = f.read()
953 s = f.read()
930 assert "liné1\n" in s
954 assert "liné1\n" in s
931 assert "liné2" in s
955 assert "liné2" in s
932
956
933
957
934 def test_file_amend():
958 def test_file_amend():
935 """%%writefile -a amends files"""
959 """%%writefile -a amends files"""
936 ip = get_ipython()
960 ip = get_ipython()
937 with TemporaryDirectory() as td:
961 with TemporaryDirectory() as td:
938 fname = os.path.join(td, 'file2')
962 fname = os.path.join(td, "file2")
939 ip.run_cell_magic("writefile", fname, u'\n'.join([
963 ip.run_cell_magic(
940 'line1',
964 "writefile",
941 'line2',
965 fname,
942 ]))
966 "\n".join(
943 ip.run_cell_magic("writefile", "-a %s" % fname, u'\n'.join([
967 [
944 'line3',
968 "line1",
945 'line4',
969 "line2",
946 ]))
970 ]
947 s = Path(fname).read_text(encoding='utf-8')
971 ),
972 )
973 ip.run_cell_magic(
974 "writefile",
975 "-a %s" % fname,
976 "\n".join(
977 [
978 "line3",
979 "line4",
980 ]
981 ),
982 )
983 s = Path(fname).read_text(encoding="utf-8")
948 assert "line1\n" in s
984 assert "line1\n" in s
949 assert "line3\n" in s
985 assert "line3\n" in s
950
986
951
987
952 def test_file_spaces():
988 def test_file_spaces():
953 """%%file with spaces in filename"""
989 """%%file with spaces in filename"""
954 ip = get_ipython()
990 ip = get_ipython()
955 with TemporaryWorkingDirectory() as td:
991 with TemporaryWorkingDirectory() as td:
956 fname = "file name"
992 fname = "file name"
957 ip.run_cell_magic("file", '"%s"'%fname, u'\n'.join([
993 ip.run_cell_magic(
958 'line1',
994 "file",
959 'line2',
995 '"%s"' % fname,
960 ]))
996 "\n".join(
961 s = Path(fname).read_text(encoding='utf-8')
997 [
998 "line1",
999 "line2",
1000 ]
1001 ),
1002 )
1003 s = Path(fname).read_text(encoding="utf-8")
962 assert "line1\n" in s
1004 assert "line1\n" in s
963 assert "line2" in s
1005 assert "line2" in s
964
1006
965
1007
966 def test_script_config():
1008 def test_script_config():
967 ip = get_ipython()
1009 ip = get_ipython()
968 ip.config.ScriptMagics.script_magics = ['whoda']
1010 ip.config.ScriptMagics.script_magics = ['whoda']
969 sm = script.ScriptMagics(shell=ip)
1011 sm = script.ScriptMagics(shell=ip)
970 assert "whoda" in sm.magics["cell"]
1012 assert "whoda" in sm.magics["cell"]
971
1013
972
1014
973 def test_script_out():
1015 def test_script_out():
974 ip = get_ipython()
1016 ip = get_ipython()
975 ip.run_cell_magic("script", f"--out output {sys.executable}", "print('hi')")
1017 ip.run_cell_magic("script", f"--out output {sys.executable}", "print('hi')")
976 assert ip.user_ns["output"].strip() == "hi"
1018 assert ip.user_ns["output"].strip() == "hi"
977
1019
978
1020
979 def test_script_err():
1021 def test_script_err():
980 ip = get_ipython()
1022 ip = get_ipython()
981 ip.run_cell_magic(
1023 ip.run_cell_magic(
982 "script",
1024 "script",
983 f"--err error {sys.executable}",
1025 f"--err error {sys.executable}",
984 "import sys; print('hello', file=sys.stderr)",
1026 "import sys; print('hello', file=sys.stderr)",
985 )
1027 )
986 assert ip.user_ns["error"].strip() == "hello"
1028 assert ip.user_ns["error"].strip() == "hello"
987
1029
988
1030
989 def test_script_out_err():
1031 def test_script_out_err():
990
1032
991 ip = get_ipython()
1033 ip = get_ipython()
992 ip.run_cell_magic(
1034 ip.run_cell_magic(
993 "script",
1035 "script",
994 f"--out output --err error {sys.executable}",
1036 f"--out output --err error {sys.executable}",
995 "\n".join(
1037 "\n".join(
996 [
1038 [
997 "import sys",
1039 "import sys",
998 "print('hi')",
1040 "print('hi')",
999 "print('hello', file=sys.stderr)",
1041 "print('hello', file=sys.stderr)",
1000 ]
1042 ]
1001 ),
1043 ),
1002 )
1044 )
1003 assert ip.user_ns["output"].strip() == "hi"
1045 assert ip.user_ns["output"].strip() == "hi"
1004 assert ip.user_ns["error"].strip() == "hello"
1046 assert ip.user_ns["error"].strip() == "hello"
1005
1047
1006
1048
1007 async def test_script_bg_out():
1049 async def test_script_bg_out():
1008 ip = get_ipython()
1050 ip = get_ipython()
1009 ip.run_cell_magic("script", f"--bg --out output {sys.executable}", "print('hi')")
1051 ip.run_cell_magic("script", f"--bg --out output {sys.executable}", "print('hi')")
1010 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1052 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1011 assert ip.user_ns["output"].at_eof()
1053 assert ip.user_ns["output"].at_eof()
1012
1054
1013
1055
1014 async def test_script_bg_err():
1056 async def test_script_bg_err():
1015 ip = get_ipython()
1057 ip = get_ipython()
1016 ip.run_cell_magic(
1058 ip.run_cell_magic(
1017 "script",
1059 "script",
1018 f"--bg --err error {sys.executable}",
1060 f"--bg --err error {sys.executable}",
1019 "import sys; print('hello', file=sys.stderr)",
1061 "import sys; print('hello', file=sys.stderr)",
1020 )
1062 )
1021 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1063 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1022 assert ip.user_ns["error"].at_eof()
1064 assert ip.user_ns["error"].at_eof()
1023
1065
1024
1066
1025 async def test_script_bg_out_err():
1067 async def test_script_bg_out_err():
1026 ip = get_ipython()
1068 ip = get_ipython()
1027 ip.run_cell_magic(
1069 ip.run_cell_magic(
1028 "script",
1070 "script",
1029 f"--bg --out output --err error {sys.executable}",
1071 f"--bg --out output --err error {sys.executable}",
1030 "\n".join(
1072 "\n".join(
1031 [
1073 [
1032 "import sys",
1074 "import sys",
1033 "print('hi')",
1075 "print('hi')",
1034 "print('hello', file=sys.stderr)",
1076 "print('hello', file=sys.stderr)",
1035 ]
1077 ]
1036 ),
1078 ),
1037 )
1079 )
1038 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1080 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1039 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1081 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1040 assert ip.user_ns["output"].at_eof()
1082 assert ip.user_ns["output"].at_eof()
1041 assert ip.user_ns["error"].at_eof()
1083 assert ip.user_ns["error"].at_eof()
1042
1084
1043
1085
1044 async def test_script_bg_proc():
1086 async def test_script_bg_proc():
1045 ip = get_ipython()
1087 ip = get_ipython()
1046 ip.run_cell_magic(
1088 ip.run_cell_magic(
1047 "script",
1089 "script",
1048 f"--bg --out output --proc p {sys.executable}",
1090 f"--bg --out output --proc p {sys.executable}",
1049 "\n".join(
1091 "\n".join(
1050 [
1092 [
1051 "import sys",
1093 "import sys",
1052 "print('hi')",
1094 "print('hi')",
1053 "print('hello', file=sys.stderr)",
1095 "print('hello', file=sys.stderr)",
1054 ]
1096 ]
1055 ),
1097 ),
1056 )
1098 )
1057 p = ip.user_ns["p"]
1099 p = ip.user_ns["p"]
1058 await p.wait()
1100 await p.wait()
1059 assert p.returncode == 0
1101 assert p.returncode == 0
1060 assert (await p.stdout.read()).strip() == b"hi"
1102 assert (await p.stdout.read()).strip() == b"hi"
1061 # not captured, so empty
1103 # not captured, so empty
1062 assert (await p.stderr.read()) == b""
1104 assert (await p.stderr.read()) == b""
1063 assert p.stdout.at_eof()
1105 assert p.stdout.at_eof()
1064 assert p.stderr.at_eof()
1106 assert p.stderr.at_eof()
1065
1107
1066
1108
1067 def test_script_defaults():
1109 def test_script_defaults():
1068 ip = get_ipython()
1110 ip = get_ipython()
1069 for cmd in ['sh', 'bash', 'perl', 'ruby']:
1111 for cmd in ['sh', 'bash', 'perl', 'ruby']:
1070 try:
1112 try:
1071 find_cmd(cmd)
1113 find_cmd(cmd)
1072 except Exception:
1114 except Exception:
1073 pass
1115 pass
1074 else:
1116 else:
1075 assert cmd in ip.magics_manager.magics["cell"]
1117 assert cmd in ip.magics_manager.magics["cell"]
1076
1118
1077
1119
1078 @magics_class
1120 @magics_class
1079 class FooFoo(Magics):
1121 class FooFoo(Magics):
1080 """class with both %foo and %%foo magics"""
1122 """class with both %foo and %%foo magics"""
1081 @line_magic('foo')
1123 @line_magic('foo')
1082 def line_foo(self, line):
1124 def line_foo(self, line):
1083 "I am line foo"
1125 "I am line foo"
1084 pass
1126 pass
1085
1127
1086 @cell_magic("foo")
1128 @cell_magic("foo")
1087 def cell_foo(self, line, cell):
1129 def cell_foo(self, line, cell):
1088 "I am cell foo, not line foo"
1130 "I am cell foo, not line foo"
1089 pass
1131 pass
1090
1132
1091 def test_line_cell_info():
1133 def test_line_cell_info():
1092 """%%foo and %foo magics are distinguishable to inspect"""
1134 """%%foo and %foo magics are distinguishable to inspect"""
1093 ip = get_ipython()
1135 ip = get_ipython()
1094 ip.magics_manager.register(FooFoo)
1136 ip.magics_manager.register(FooFoo)
1095 oinfo = ip.object_inspect("foo")
1137 oinfo = ip.object_inspect("foo")
1096 assert oinfo["found"] is True
1138 assert oinfo["found"] is True
1097 assert oinfo["ismagic"] is True
1139 assert oinfo["ismagic"] is True
1098
1140
1099 oinfo = ip.object_inspect("%%foo")
1141 oinfo = ip.object_inspect("%%foo")
1100 assert oinfo["found"] is True
1142 assert oinfo["found"] is True
1101 assert oinfo["ismagic"] is True
1143 assert oinfo["ismagic"] is True
1102 assert oinfo["docstring"] == FooFoo.cell_foo.__doc__
1144 assert oinfo["docstring"] == FooFoo.cell_foo.__doc__
1103
1145
1104 oinfo = ip.object_inspect("%foo")
1146 oinfo = ip.object_inspect("%foo")
1105 assert oinfo["found"] is True
1147 assert oinfo["found"] is True
1106 assert oinfo["ismagic"] is True
1148 assert oinfo["ismagic"] is True
1107 assert oinfo["docstring"] == FooFoo.line_foo.__doc__
1149 assert oinfo["docstring"] == FooFoo.line_foo.__doc__
1108
1150
1109
1151
1110 def test_multiple_magics():
1152 def test_multiple_magics():
1111 ip = get_ipython()
1153 ip = get_ipython()
1112 foo1 = FooFoo(ip)
1154 foo1 = FooFoo(ip)
1113 foo2 = FooFoo(ip)
1155 foo2 = FooFoo(ip)
1114 mm = ip.magics_manager
1156 mm = ip.magics_manager
1115 mm.register(foo1)
1157 mm.register(foo1)
1116 assert mm.magics["line"]["foo"].__self__ is foo1
1158 assert mm.magics["line"]["foo"].__self__ is foo1
1117 mm.register(foo2)
1159 mm.register(foo2)
1118 assert mm.magics["line"]["foo"].__self__ is foo2
1160 assert mm.magics["line"]["foo"].__self__ is foo2
1119
1161
1120
1162
1121 def test_alias_magic():
1163 def test_alias_magic():
1122 """Test %alias_magic."""
1164 """Test %alias_magic."""
1123 ip = get_ipython()
1165 ip = get_ipython()
1124 mm = ip.magics_manager
1166 mm = ip.magics_manager
1125
1167
1126 # Basic operation: both cell and line magics are created, if possible.
1168 # Basic operation: both cell and line magics are created, if possible.
1127 ip.run_line_magic("alias_magic", "timeit_alias timeit")
1169 ip.run_line_magic("alias_magic", "timeit_alias timeit")
1128 assert "timeit_alias" in mm.magics["line"]
1170 assert "timeit_alias" in mm.magics["line"]
1129 assert "timeit_alias" in mm.magics["cell"]
1171 assert "timeit_alias" in mm.magics["cell"]
1130
1172
1131 # --cell is specified, line magic not created.
1173 # --cell is specified, line magic not created.
1132 ip.run_line_magic("alias_magic", "--cell timeit_cell_alias timeit")
1174 ip.run_line_magic("alias_magic", "--cell timeit_cell_alias timeit")
1133 assert "timeit_cell_alias" not in mm.magics["line"]
1175 assert "timeit_cell_alias" not in mm.magics["line"]
1134 assert "timeit_cell_alias" in mm.magics["cell"]
1176 assert "timeit_cell_alias" in mm.magics["cell"]
1135
1177
1136 # Test that line alias is created successfully.
1178 # Test that line alias is created successfully.
1137 ip.run_line_magic("alias_magic", "--line env_alias env")
1179 ip.run_line_magic("alias_magic", "--line env_alias env")
1138 assert ip.run_line_magic("env", "") == ip.run_line_magic("env_alias", "")
1180 assert ip.run_line_magic("env", "") == ip.run_line_magic("env_alias", "")
1139
1181
1140 # Test that line alias with parameters passed in is created successfully.
1182 # Test that line alias with parameters passed in is created successfully.
1141 ip.run_line_magic(
1183 ip.run_line_magic(
1142 "alias_magic", "--line history_alias history --params " + shlex.quote("3")
1184 "alias_magic", "--line history_alias history --params " + shlex.quote("3")
1143 )
1185 )
1144 assert "history_alias" in mm.magics["line"]
1186 assert "history_alias" in mm.magics["line"]
1145
1187
1146
1188
1147 def test_save():
1189 def test_save():
1148 """Test %save."""
1190 """Test %save."""
1149 ip = get_ipython()
1191 ip = get_ipython()
1150 ip.history_manager.reset() # Clear any existing history.
1192 ip.history_manager.reset() # Clear any existing history.
1151 cmds = ["a=1", "def b():\n return a**2", "print(a, b())"]
1193 cmds = ["a=1", "def b():\n return a**2", "print(a, b())"]
1152 for i, cmd in enumerate(cmds, start=1):
1194 for i, cmd in enumerate(cmds, start=1):
1153 ip.history_manager.store_inputs(i, cmd)
1195 ip.history_manager.store_inputs(i, cmd)
1154 with TemporaryDirectory() as tmpdir:
1196 with TemporaryDirectory() as tmpdir:
1155 file = os.path.join(tmpdir, "testsave.py")
1197 file = os.path.join(tmpdir, "testsave.py")
1156 ip.run_line_magic("save", "%s 1-10" % file)
1198 ip.run_line_magic("save", "%s 1-10" % file)
1157 content = Path(file).read_text(encoding='utf-8')
1199 content = Path(file).read_text(encoding="utf-8")
1158 assert content.count(cmds[0]) == 1
1200 assert content.count(cmds[0]) == 1
1159 assert "coding: utf-8" in content
1201 assert "coding: utf-8" in content
1160 ip.run_line_magic("save", "-a %s 1-10" % file)
1202 ip.run_line_magic("save", "-a %s 1-10" % file)
1161 content = Path(file).read_text(encoding='utf-8')
1203 content = Path(file).read_text(encoding="utf-8")
1162 assert content.count(cmds[0]) == 2
1204 assert content.count(cmds[0]) == 2
1163 assert "coding: utf-8" in content
1205 assert "coding: utf-8" in content
1164
1206
1165
1207
1166 def test_save_with_no_args():
1208 def test_save_with_no_args():
1167 ip = get_ipython()
1209 ip = get_ipython()
1168 ip.history_manager.reset() # Clear any existing history.
1210 ip.history_manager.reset() # Clear any existing history.
1169 cmds = ["a=1", "def b():\n return a**2", "print(a, b())", "%save"]
1211 cmds = ["a=1", "def b():\n return a**2", "print(a, b())", "%save"]
1170 for i, cmd in enumerate(cmds, start=1):
1212 for i, cmd in enumerate(cmds, start=1):
1171 ip.history_manager.store_inputs(i, cmd)
1213 ip.history_manager.store_inputs(i, cmd)
1172
1214
1173 with TemporaryDirectory() as tmpdir:
1215 with TemporaryDirectory() as tmpdir:
1174 path = os.path.join(tmpdir, "testsave.py")
1216 path = os.path.join(tmpdir, "testsave.py")
1175 ip.run_line_magic("save", path)
1217 ip.run_line_magic("save", path)
1176 content = Path(path).read_text(encoding='utf-8')
1218 content = Path(path).read_text(encoding="utf-8")
1177 expected_content = dedent(
1219 expected_content = dedent(
1178 """\
1220 """\
1179 # coding: utf-8
1221 # coding: utf-8
1180 a=1
1222 a=1
1181 def b():
1223 def b():
1182 return a**2
1224 return a**2
1183 print(a, b())
1225 print(a, b())
1184 """
1226 """
1185 )
1227 )
1186 assert content == expected_content
1228 assert content == expected_content
1187
1229
1188
1230
1189 def test_store():
1231 def test_store():
1190 """Test %store."""
1232 """Test %store."""
1191 ip = get_ipython()
1233 ip = get_ipython()
1192 ip.run_line_magic('load_ext', 'storemagic')
1234 ip.run_line_magic('load_ext', 'storemagic')
1193
1235
1194 # make sure the storage is empty
1236 # make sure the storage is empty
1195 ip.run_line_magic("store", "-z")
1237 ip.run_line_magic("store", "-z")
1196 ip.user_ns["var"] = 42
1238 ip.user_ns["var"] = 42
1197 ip.run_line_magic("store", "var")
1239 ip.run_line_magic("store", "var")
1198 ip.user_ns["var"] = 39
1240 ip.user_ns["var"] = 39
1199 ip.run_line_magic("store", "-r")
1241 ip.run_line_magic("store", "-r")
1200 assert ip.user_ns["var"] == 42
1242 assert ip.user_ns["var"] == 42
1201
1243
1202 ip.run_line_magic("store", "-d var")
1244 ip.run_line_magic("store", "-d var")
1203 ip.user_ns["var"] = 39
1245 ip.user_ns["var"] = 39
1204 ip.run_line_magic("store", "-r")
1246 ip.run_line_magic("store", "-r")
1205 assert ip.user_ns["var"] == 39
1247 assert ip.user_ns["var"] == 39
1206
1248
1207
1249
1208 def _run_edit_test(arg_s, exp_filename=None,
1250 def _run_edit_test(arg_s, exp_filename=None,
1209 exp_lineno=-1,
1251 exp_lineno=-1,
1210 exp_contents=None,
1252 exp_contents=None,
1211 exp_is_temp=None):
1253 exp_is_temp=None):
1212 ip = get_ipython()
1254 ip = get_ipython()
1213 M = code.CodeMagics(ip)
1255 M = code.CodeMagics(ip)
1214 last_call = ['','']
1256 last_call = ['','']
1215 opts,args = M.parse_options(arg_s,'prxn:')
1257 opts,args = M.parse_options(arg_s,'prxn:')
1216 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1258 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1217
1259
1218 if exp_filename is not None:
1260 if exp_filename is not None:
1219 assert exp_filename == filename
1261 assert exp_filename == filename
1220 if exp_contents is not None:
1262 if exp_contents is not None:
1221 with io.open(filename, 'r', encoding='utf-8') as f:
1263 with io.open(filename, 'r', encoding='utf-8') as f:
1222 contents = f.read()
1264 contents = f.read()
1223 assert exp_contents == contents
1265 assert exp_contents == contents
1224 if exp_lineno != -1:
1266 if exp_lineno != -1:
1225 assert exp_lineno == lineno
1267 assert exp_lineno == lineno
1226 if exp_is_temp is not None:
1268 if exp_is_temp is not None:
1227 assert exp_is_temp == is_temp
1269 assert exp_is_temp == is_temp
1228
1270
1229
1271
1230 def test_edit_interactive():
1272 def test_edit_interactive():
1231 """%edit on interactively defined objects"""
1273 """%edit on interactively defined objects"""
1232 ip = get_ipython()
1274 ip = get_ipython()
1233 n = ip.execution_count
1275 n = ip.execution_count
1234 ip.run_cell("def foo(): return 1", store_history=True)
1276 ip.run_cell("def foo(): return 1", store_history=True)
1235
1277
1236 with pytest.raises(code.InteractivelyDefined) as e:
1278 with pytest.raises(code.InteractivelyDefined) as e:
1237 _run_edit_test("foo")
1279 _run_edit_test("foo")
1238 assert e.value.index == n
1280 assert e.value.index == n
1239
1281
1240
1282
1241 def test_edit_cell():
1283 def test_edit_cell():
1242 """%edit [cell id]"""
1284 """%edit [cell id]"""
1243 ip = get_ipython()
1285 ip = get_ipython()
1244
1286
1245 ip.run_cell("def foo(): return 1", store_history=True)
1287 ip.run_cell("def foo(): return 1", store_history=True)
1246
1288
1247 # test
1289 # test
1248 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1290 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1249
1291
1250 def test_edit_fname():
1292 def test_edit_fname():
1251 """%edit file"""
1293 """%edit file"""
1252 # test
1294 # test
1253 _run_edit_test("test file.py", exp_filename="test file.py")
1295 _run_edit_test("test file.py", exp_filename="test file.py")
1254
1296
1255 def test_bookmark():
1297 def test_bookmark():
1256 ip = get_ipython()
1298 ip = get_ipython()
1257 ip.run_line_magic('bookmark', 'bmname')
1299 ip.run_line_magic('bookmark', 'bmname')
1258 with tt.AssertPrints('bmname'):
1300 with tt.AssertPrints('bmname'):
1259 ip.run_line_magic('bookmark', '-l')
1301 ip.run_line_magic('bookmark', '-l')
1260 ip.run_line_magic('bookmark', '-d bmname')
1302 ip.run_line_magic('bookmark', '-d bmname')
1261
1303
1262 def test_ls_magic():
1304 def test_ls_magic():
1263 ip = get_ipython()
1305 ip = get_ipython()
1264 json_formatter = ip.display_formatter.formatters['application/json']
1306 json_formatter = ip.display_formatter.formatters['application/json']
1265 json_formatter.enabled = True
1307 json_formatter.enabled = True
1266 lsmagic = ip.magic('lsmagic')
1308 lsmagic = ip.magic('lsmagic')
1267 with warnings.catch_warnings(record=True) as w:
1309 with warnings.catch_warnings(record=True) as w:
1268 j = json_formatter(lsmagic)
1310 j = json_formatter(lsmagic)
1269 assert sorted(j) == ["cell", "line"]
1311 assert sorted(j) == ["cell", "line"]
1270 assert w == [] # no warnings
1312 assert w == [] # no warnings
1271
1313
1272
1314
1273 def test_strip_initial_indent():
1315 def test_strip_initial_indent():
1274 def sii(s):
1316 def sii(s):
1275 lines = s.splitlines()
1317 lines = s.splitlines()
1276 return '\n'.join(code.strip_initial_indent(lines))
1318 return '\n'.join(code.strip_initial_indent(lines))
1277
1319
1278 assert sii(" a = 1\nb = 2") == "a = 1\nb = 2"
1320 assert sii(" a = 1\nb = 2") == "a = 1\nb = 2"
1279 assert sii(" a\n b\nc") == "a\n b\nc"
1321 assert sii(" a\n b\nc") == "a\n b\nc"
1280 assert sii("a\n b") == "a\n b"
1322 assert sii("a\n b") == "a\n b"
1281
1323
1282 def test_logging_magic_quiet_from_arg():
1324 def test_logging_magic_quiet_from_arg():
1283 _ip.config.LoggingMagics.quiet = False
1325 _ip.config.LoggingMagics.quiet = False
1284 lm = logging.LoggingMagics(shell=_ip)
1326 lm = logging.LoggingMagics(shell=_ip)
1285 with TemporaryDirectory() as td:
1327 with TemporaryDirectory() as td:
1286 try:
1328 try:
1287 with tt.AssertNotPrints(re.compile("Activating.*")):
1329 with tt.AssertNotPrints(re.compile("Activating.*")):
1288 lm.logstart('-q {}'.format(
1330 lm.logstart('-q {}'.format(
1289 os.path.join(td, "quiet_from_arg.log")))
1331 os.path.join(td, "quiet_from_arg.log")))
1290 finally:
1332 finally:
1291 _ip.logger.logstop()
1333 _ip.logger.logstop()
1292
1334
1293 def test_logging_magic_quiet_from_config():
1335 def test_logging_magic_quiet_from_config():
1294 _ip.config.LoggingMagics.quiet = True
1336 _ip.config.LoggingMagics.quiet = True
1295 lm = logging.LoggingMagics(shell=_ip)
1337 lm = logging.LoggingMagics(shell=_ip)
1296 with TemporaryDirectory() as td:
1338 with TemporaryDirectory() as td:
1297 try:
1339 try:
1298 with tt.AssertNotPrints(re.compile("Activating.*")):
1340 with tt.AssertNotPrints(re.compile("Activating.*")):
1299 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1341 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1300 finally:
1342 finally:
1301 _ip.logger.logstop()
1343 _ip.logger.logstop()
1302
1344
1303
1345
1304 def test_logging_magic_not_quiet():
1346 def test_logging_magic_not_quiet():
1305 _ip.config.LoggingMagics.quiet = False
1347 _ip.config.LoggingMagics.quiet = False
1306 lm = logging.LoggingMagics(shell=_ip)
1348 lm = logging.LoggingMagics(shell=_ip)
1307 with TemporaryDirectory() as td:
1349 with TemporaryDirectory() as td:
1308 try:
1350 try:
1309 with tt.AssertPrints(re.compile("Activating.*")):
1351 with tt.AssertPrints(re.compile("Activating.*")):
1310 lm.logstart(os.path.join(td, "not_quiet.log"))
1352 lm.logstart(os.path.join(td, "not_quiet.log"))
1311 finally:
1353 finally:
1312 _ip.logger.logstop()
1354 _ip.logger.logstop()
1313
1355
1314
1356
1315 def test_time_no_var_expand():
1357 def test_time_no_var_expand():
1316 _ip.user_ns['a'] = 5
1358 _ip.user_ns['a'] = 5
1317 _ip.user_ns['b'] = []
1359 _ip.user_ns['b'] = []
1318 _ip.magic('time b.append("{a}")')
1360 _ip.magic('time b.append("{a}")')
1319 assert _ip.user_ns['b'] == ['{a}']
1361 assert _ip.user_ns['b'] == ['{a}']
1320
1362
1321
1363
1322 # this is slow, put at the end for local testing.
1364 # this is slow, put at the end for local testing.
1323 def test_timeit_arguments():
1365 def test_timeit_arguments():
1324 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1366 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1325 _ip.magic("timeit -n1 -r1 a=('#')")
1367 _ip.magic("timeit -n1 -r1 a=('#')")
1326
1368
1327
1369
1328 TEST_MODULE = """
1370 TEST_MODULE = """
1329 print('Loaded my_tmp')
1371 print('Loaded my_tmp')
1330 if __name__ == "__main__":
1372 if __name__ == "__main__":
1331 print('I just ran a script')
1373 print('I just ran a script')
1332 """
1374 """
1333
1375
1334
1376
1335 def test_run_module_from_import_hook():
1377 def test_run_module_from_import_hook():
1336 "Test that a module can be loaded via an import hook"
1378 "Test that a module can be loaded via an import hook"
1337 with TemporaryDirectory() as tmpdir:
1379 with TemporaryDirectory() as tmpdir:
1338 fullpath = os.path.join(tmpdir, 'my_tmp.py')
1380 fullpath = os.path.join(tmpdir, "my_tmp.py")
1339 Path(fullpath).write_text(TEST_MODULE, encoding='utf-8')
1381 Path(fullpath).write_text(TEST_MODULE, encoding="utf-8")
1340
1382
1341 import importlib.abc
1383 import importlib.abc
1342 import importlib.util
1384 import importlib.util
1343
1385
1344 class MyTempImporter(importlib.abc.MetaPathFinder, importlib.abc.SourceLoader):
1386 class MyTempImporter(importlib.abc.MetaPathFinder, importlib.abc.SourceLoader):
1345 def find_spec(self, fullname, path, target=None):
1387 def find_spec(self, fullname, path, target=None):
1346 if fullname == "my_tmp":
1388 if fullname == "my_tmp":
1347 return importlib.util.spec_from_loader(fullname, self)
1389 return importlib.util.spec_from_loader(fullname, self)
1348
1390
1349 def get_filename(self, fullname):
1391 def get_filename(self, fullname):
1350 assert fullname == "my_tmp"
1392 assert fullname == "my_tmp"
1351 return fullpath
1393 return fullpath
1352
1394
1353 def get_data(self, path):
1395 def get_data(self, path):
1354 assert Path(path).samefile(fullpath)
1396 assert Path(path).samefile(fullpath)
1355 return Path(fullpath).read_text(encoding='utf-8')
1397 return Path(fullpath).read_text(encoding="utf-8")
1356
1398
1357 sys.meta_path.insert(0, MyTempImporter())
1399 sys.meta_path.insert(0, MyTempImporter())
1358
1400
1359 with capture_output() as captured:
1401 with capture_output() as captured:
1360 _ip.magic("run -m my_tmp")
1402 _ip.magic("run -m my_tmp")
1361 _ip.run_cell("import my_tmp")
1403 _ip.run_cell("import my_tmp")
1362
1404
1363 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1405 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1364 assert output == captured.stdout
1406 assert output == captured.stdout
1365
1407
1366 sys.meta_path.pop(0)
1408 sys.meta_path.pop(0)
@@ -1,156 +1,156 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Tests for profile-related functions.
2 """Tests for profile-related functions.
3
3
4 Currently only the startup-dir functionality is tested, but more tests should
4 Currently only the startup-dir functionality is tested, but more tests should
5 be added for:
5 be added for:
6
6
7 * ipython profile create
7 * ipython profile create
8 * ipython profile list
8 * ipython profile list
9 * ipython profile create --parallel
9 * ipython profile create --parallel
10 * security dir permissions
10 * security dir permissions
11
11
12 Authors
12 Authors
13 -------
13 -------
14
14
15 * MinRK
15 * MinRK
16
16
17 """
17 """
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import shutil
23 import shutil
24 import sys
24 import sys
25 import tempfile
25 import tempfile
26
26
27 from pathlib import Path
27 from pathlib import Path
28 from unittest import TestCase
28 from unittest import TestCase
29
29
30 from IPython.core.profileapp import list_profiles_in, list_bundled_profiles
30 from IPython.core.profileapp import list_profiles_in, list_bundled_profiles
31 from IPython.core.profiledir import ProfileDir
31 from IPython.core.profiledir import ProfileDir
32
32
33 from IPython.testing import decorators as dec
33 from IPython.testing import decorators as dec
34 from IPython.testing import tools as tt
34 from IPython.testing import tools as tt
35 from IPython.utils.process import getoutput
35 from IPython.utils.process import getoutput
36 from IPython.utils.tempdir import TemporaryDirectory
36 from IPython.utils.tempdir import TemporaryDirectory
37
37
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39 # Globals
39 # Globals
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 TMP_TEST_DIR = Path(tempfile.mkdtemp())
41 TMP_TEST_DIR = Path(tempfile.mkdtemp())
42 HOME_TEST_DIR = TMP_TEST_DIR / "home_test_dir"
42 HOME_TEST_DIR = TMP_TEST_DIR / "home_test_dir"
43 IP_TEST_DIR = HOME_TEST_DIR / ".ipython"
43 IP_TEST_DIR = HOME_TEST_DIR / ".ipython"
44
44
45 #
45 #
46 # Setup/teardown functions/decorators
46 # Setup/teardown functions/decorators
47 #
47 #
48
48
49 def setup_module():
49 def setup_module():
50 """Setup test environment for the module:
50 """Setup test environment for the module:
51
51
52 - Adds dummy home dir tree
52 - Adds dummy home dir tree
53 """
53 """
54 # Do not mask exceptions here. In particular, catching WindowsError is a
54 # Do not mask exceptions here. In particular, catching WindowsError is a
55 # problem because that exception is only defined on Windows...
55 # problem because that exception is only defined on Windows...
56 (Path.cwd() / IP_TEST_DIR).mkdir(parents=True)
56 (Path.cwd() / IP_TEST_DIR).mkdir(parents=True)
57
57
58
58
59 def teardown_module():
59 def teardown_module():
60 """Teardown test environment for the module:
60 """Teardown test environment for the module:
61
61
62 - Remove dummy home dir tree
62 - Remove dummy home dir tree
63 """
63 """
64 # Note: we remove the parent test dir, which is the root of all test
64 # Note: we remove the parent test dir, which is the root of all test
65 # subdirs we may have created. Use shutil instead of os.removedirs, so
65 # subdirs we may have created. Use shutil instead of os.removedirs, so
66 # that non-empty directories are all recursively removed.
66 # that non-empty directories are all recursively removed.
67 shutil.rmtree(TMP_TEST_DIR)
67 shutil.rmtree(TMP_TEST_DIR)
68
68
69
69
70 #-----------------------------------------------------------------------------
70 #-----------------------------------------------------------------------------
71 # Test functions
71 # Test functions
72 #-----------------------------------------------------------------------------
72 #-----------------------------------------------------------------------------
73 class ProfileStartupTest(TestCase):
73 class ProfileStartupTest(TestCase):
74 def setUp(self):
74 def setUp(self):
75 # create profile dir
75 # create profile dir
76 self.pd = ProfileDir.create_profile_dir_by_name(IP_TEST_DIR, "test")
76 self.pd = ProfileDir.create_profile_dir_by_name(IP_TEST_DIR, "test")
77 self.options = ["--ipython-dir", IP_TEST_DIR, "--profile", "test"]
77 self.options = ["--ipython-dir", IP_TEST_DIR, "--profile", "test"]
78 self.fname = TMP_TEST_DIR / "test.py"
78 self.fname = TMP_TEST_DIR / "test.py"
79
79
80 def tearDown(self):
80 def tearDown(self):
81 # We must remove this profile right away so its presence doesn't
81 # We must remove this profile right away so its presence doesn't
82 # confuse other tests.
82 # confuse other tests.
83 shutil.rmtree(self.pd.location)
83 shutil.rmtree(self.pd.location)
84
84
85 def init(self, startup_file, startup, test):
85 def init(self, startup_file, startup, test):
86 # write startup python file
86 # write startup python file
87 with open(Path(self.pd.startup_dir) / startup_file, "w", encoding='utf-8') as f:
87 with open(Path(self.pd.startup_dir) / startup_file, "w", encoding="utf-8") as f:
88 f.write(startup)
88 f.write(startup)
89 # write simple test file, to check that the startup file was run
89 # write simple test file, to check that the startup file was run
90 with open(self.fname, 'w', encoding='utf-8') as f:
90 with open(self.fname, "w", encoding="utf-8") as f:
91 f.write(test)
91 f.write(test)
92
92
93 def validate(self, output):
93 def validate(self, output):
94 tt.ipexec_validate(self.fname, output, "", options=self.options)
94 tt.ipexec_validate(self.fname, output, "", options=self.options)
95
95
96 def test_startup_py(self):
96 def test_startup_py(self):
97 self.init('00-start.py', 'zzz=123\n', 'print(zzz)\n')
97 self.init('00-start.py', 'zzz=123\n', 'print(zzz)\n')
98 self.validate('123')
98 self.validate('123')
99
99
100 def test_startup_ipy(self):
100 def test_startup_ipy(self):
101 self.init('00-start.ipy', '%xmode plain\n', '')
101 self.init('00-start.ipy', '%xmode plain\n', '')
102 self.validate('Exception reporting mode: Plain')
102 self.validate('Exception reporting mode: Plain')
103
103
104
104
105 def test_list_profiles_in():
105 def test_list_profiles_in():
106 # No need to remove these directories and files, as they will get nuked in
106 # No need to remove these directories and files, as they will get nuked in
107 # the module-level teardown.
107 # the module-level teardown.
108 td = Path(tempfile.mkdtemp(dir=TMP_TEST_DIR))
108 td = Path(tempfile.mkdtemp(dir=TMP_TEST_DIR))
109 for name in ("profile_foo", "profile_hello", "not_a_profile"):
109 for name in ("profile_foo", "profile_hello", "not_a_profile"):
110 Path(td / name).mkdir(parents=True)
110 Path(td / name).mkdir(parents=True)
111 if dec.unicode_paths:
111 if dec.unicode_paths:
112 Path(td / u"profile_ünicode").mkdir(parents=True)
112 Path(td / u"profile_ünicode").mkdir(parents=True)
113
113
114 with open(td / "profile_file", "w", encoding='utf-8') as f:
114 with open(td / "profile_file", "w", encoding="utf-8") as f:
115 f.write("I am not a profile directory")
115 f.write("I am not a profile directory")
116 profiles = list_profiles_in(td)
116 profiles = list_profiles_in(td)
117
117
118 # unicode normalization can turn u'ünicode' into u'u\0308nicode',
118 # unicode normalization can turn u'ünicode' into u'u\0308nicode',
119 # so only check for *nicode, and that creating a ProfileDir from the
119 # so only check for *nicode, and that creating a ProfileDir from the
120 # name remains valid
120 # name remains valid
121 found_unicode = False
121 found_unicode = False
122 for p in list(profiles):
122 for p in list(profiles):
123 if p.endswith('nicode'):
123 if p.endswith('nicode'):
124 pd = ProfileDir.find_profile_dir_by_name(td, p)
124 pd = ProfileDir.find_profile_dir_by_name(td, p)
125 profiles.remove(p)
125 profiles.remove(p)
126 found_unicode = True
126 found_unicode = True
127 break
127 break
128 if dec.unicode_paths:
128 if dec.unicode_paths:
129 assert found_unicode is True
129 assert found_unicode is True
130 assert set(profiles) == {"foo", "hello"}
130 assert set(profiles) == {"foo", "hello"}
131
131
132
132
133 def test_list_bundled_profiles():
133 def test_list_bundled_profiles():
134 # This variable will need to be updated when a new profile gets bundled
134 # This variable will need to be updated when a new profile gets bundled
135 bundled = sorted(list_bundled_profiles())
135 bundled = sorted(list_bundled_profiles())
136 assert bundled == []
136 assert bundled == []
137
137
138
138
139 def test_profile_create_ipython_dir():
139 def test_profile_create_ipython_dir():
140 """ipython profile create respects --ipython-dir"""
140 """ipython profile create respects --ipython-dir"""
141 with TemporaryDirectory() as td:
141 with TemporaryDirectory() as td:
142 getoutput(
142 getoutput(
143 [
143 [
144 sys.executable,
144 sys.executable,
145 "-m",
145 "-m",
146 "IPython",
146 "IPython",
147 "profile",
147 "profile",
148 "create",
148 "create",
149 "foo",
149 "foo",
150 "--ipython-dir=%s" % td,
150 "--ipython-dir=%s" % td,
151 ]
151 ]
152 )
152 )
153 profile_dir = Path(td) / "profile_foo"
153 profile_dir = Path(td) / "profile_foo"
154 assert Path(profile_dir).exists()
154 assert Path(profile_dir).exists()
155 ipython_config = profile_dir / "ipython_config.py"
155 ipython_config = profile_dir / "ipython_config.py"
156 assert Path(ipython_config).exists()
156 assert Path(ipython_config).exists()
@@ -1,612 +1,620 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for code execution (%run and related), which is particularly tricky.
2 """Tests for code execution (%run and related), which is particularly tricky.
3
3
4 Because of how %run manages namespaces, and the fact that we are trying here to
4 Because of how %run manages namespaces, and the fact that we are trying here to
5 verify subtle object deletion and reference counting issues, the %run tests
5 verify subtle object deletion and reference counting issues, the %run tests
6 will be kept in this separate file. This makes it easier to aggregate in one
6 will be kept in this separate file. This makes it easier to aggregate in one
7 place the tricks needed to handle it; most other magics are much easier to test
7 place the tricks needed to handle it; most other magics are much easier to test
8 and we do so in a common test_magic file.
8 and we do so in a common test_magic file.
9
9
10 Note that any test using `run -i` should make sure to do a `reset` afterwards,
10 Note that any test using `run -i` should make sure to do a `reset` afterwards,
11 as otherwise it may influence later tests.
11 as otherwise it may influence later tests.
12 """
12 """
13
13
14 # Copyright (c) IPython Development Team.
14 # Copyright (c) IPython Development Team.
15 # Distributed under the terms of the Modified BSD License.
15 # Distributed under the terms of the Modified BSD License.
16
16
17
17
18
18
19 import functools
19 import functools
20 import os
20 import os
21 import platform
21 import platform
22 from os.path import join as pjoin
22 from os.path import join as pjoin
23 import random
23 import random
24 import string
24 import string
25 import sys
25 import sys
26 import textwrap
26 import textwrap
27 import unittest
27 import unittest
28 from unittest.mock import patch
28 from unittest.mock import patch
29
29
30 import pytest
30 import pytest
31
31
32 from IPython.testing import decorators as dec
32 from IPython.testing import decorators as dec
33 from IPython.testing import tools as tt
33 from IPython.testing import tools as tt
34 from IPython.utils.io import capture_output
34 from IPython.utils.io import capture_output
35 from IPython.utils.tempdir import TemporaryDirectory
35 from IPython.utils.tempdir import TemporaryDirectory
36 from IPython.core import debugger
36 from IPython.core import debugger
37
37
38 def doctest_refbug():
38 def doctest_refbug():
39 """Very nasty problem with references held by multiple runs of a script.
39 """Very nasty problem with references held by multiple runs of a script.
40 See: https://github.com/ipython/ipython/issues/141
40 See: https://github.com/ipython/ipython/issues/141
41
41
42 In [1]: _ip.clear_main_mod_cache()
42 In [1]: _ip.clear_main_mod_cache()
43 # random
43 # random
44
44
45 In [2]: %run refbug
45 In [2]: %run refbug
46
46
47 In [3]: call_f()
47 In [3]: call_f()
48 lowercased: hello
48 lowercased: hello
49
49
50 In [4]: %run refbug
50 In [4]: %run refbug
51
51
52 In [5]: call_f()
52 In [5]: call_f()
53 lowercased: hello
53 lowercased: hello
54 lowercased: hello
54 lowercased: hello
55 """
55 """
56
56
57
57
58 def doctest_run_builtins():
58 def doctest_run_builtins():
59 r"""Check that %run doesn't damage __builtins__.
59 r"""Check that %run doesn't damage __builtins__.
60
60
61 In [1]: import tempfile
61 In [1]: import tempfile
62
62
63 In [2]: bid1 = id(__builtins__)
63 In [2]: bid1 = id(__builtins__)
64
64
65 In [3]: fname = tempfile.mkstemp('.py')[1]
65 In [3]: fname = tempfile.mkstemp('.py')[1]
66
66
67 In [3]: f = open(fname, 'w', encoding='utf-8')
67 In [3]: f = open(fname, 'w', encoding='utf-8')
68
68
69 In [4]: dummy= f.write('pass\n')
69 In [4]: dummy= f.write('pass\n')
70
70
71 In [5]: f.flush()
71 In [5]: f.flush()
72
72
73 In [6]: t1 = type(__builtins__)
73 In [6]: t1 = type(__builtins__)
74
74
75 In [7]: %run $fname
75 In [7]: %run $fname
76
76
77 In [7]: f.close()
77 In [7]: f.close()
78
78
79 In [8]: bid2 = id(__builtins__)
79 In [8]: bid2 = id(__builtins__)
80
80
81 In [9]: t2 = type(__builtins__)
81 In [9]: t2 = type(__builtins__)
82
82
83 In [10]: t1 == t2
83 In [10]: t1 == t2
84 Out[10]: True
84 Out[10]: True
85
85
86 In [10]: bid1 == bid2
86 In [10]: bid1 == bid2
87 Out[10]: True
87 Out[10]: True
88
88
89 In [12]: try:
89 In [12]: try:
90 ....: os.unlink(fname)
90 ....: os.unlink(fname)
91 ....: except:
91 ....: except:
92 ....: pass
92 ....: pass
93 ....:
93 ....:
94 """
94 """
95
95
96
96
97 def doctest_run_option_parser():
97 def doctest_run_option_parser():
98 r"""Test option parser in %run.
98 r"""Test option parser in %run.
99
99
100 In [1]: %run print_argv.py
100 In [1]: %run print_argv.py
101 []
101 []
102
102
103 In [2]: %run print_argv.py print*.py
103 In [2]: %run print_argv.py print*.py
104 ['print_argv.py']
104 ['print_argv.py']
105
105
106 In [3]: %run -G print_argv.py print*.py
106 In [3]: %run -G print_argv.py print*.py
107 ['print*.py']
107 ['print*.py']
108
108
109 """
109 """
110
110
111
111
112 @dec.skip_win32
112 @dec.skip_win32
113 def doctest_run_option_parser_for_posix():
113 def doctest_run_option_parser_for_posix():
114 r"""Test option parser in %run (Linux/OSX specific).
114 r"""Test option parser in %run (Linux/OSX specific).
115
115
116 You need double quote to escape glob in POSIX systems:
116 You need double quote to escape glob in POSIX systems:
117
117
118 In [1]: %run print_argv.py print\\*.py
118 In [1]: %run print_argv.py print\\*.py
119 ['print*.py']
119 ['print*.py']
120
120
121 You can't use quote to escape glob in POSIX systems:
121 You can't use quote to escape glob in POSIX systems:
122
122
123 In [2]: %run print_argv.py 'print*.py'
123 In [2]: %run print_argv.py 'print*.py'
124 ['print_argv.py']
124 ['print_argv.py']
125
125
126 """
126 """
127
127
128
128
129 doctest_run_option_parser_for_posix.__skip_doctest__ = sys.platform == "win32"
129 doctest_run_option_parser_for_posix.__skip_doctest__ = sys.platform == "win32"
130
130
131
131
132 @dec.skip_if_not_win32
132 @dec.skip_if_not_win32
133 def doctest_run_option_parser_for_windows():
133 def doctest_run_option_parser_for_windows():
134 r"""Test option parser in %run (Windows specific).
134 r"""Test option parser in %run (Windows specific).
135
135
136 In Windows, you can't escape ``*` `by backslash:
136 In Windows, you can't escape ``*` `by backslash:
137
137
138 In [1]: %run print_argv.py print\\*.py
138 In [1]: %run print_argv.py print\\*.py
139 ['print\\\\*.py']
139 ['print\\\\*.py']
140
140
141 You can use quote to escape glob:
141 You can use quote to escape glob:
142
142
143 In [2]: %run print_argv.py 'print*.py'
143 In [2]: %run print_argv.py 'print*.py'
144 ["'print*.py'"]
144 ["'print*.py'"]
145
145
146 """
146 """
147
147
148
148
149 doctest_run_option_parser_for_windows.__skip_doctest__ = sys.platform != "win32"
149 doctest_run_option_parser_for_windows.__skip_doctest__ = sys.platform != "win32"
150
150
151
151
152 def doctest_reset_del():
152 def doctest_reset_del():
153 """Test that resetting doesn't cause errors in __del__ methods.
153 """Test that resetting doesn't cause errors in __del__ methods.
154
154
155 In [2]: class A(object):
155 In [2]: class A(object):
156 ...: def __del__(self):
156 ...: def __del__(self):
157 ...: print(str("Hi"))
157 ...: print(str("Hi"))
158 ...:
158 ...:
159
159
160 In [3]: a = A()
160 In [3]: a = A()
161
161
162 In [4]: get_ipython().reset(); import gc; x = gc.collect(0)
162 In [4]: get_ipython().reset(); import gc; x = gc.collect(0)
163 Hi
163 Hi
164
164
165 In [5]: 1+1
165 In [5]: 1+1
166 Out[5]: 2
166 Out[5]: 2
167 """
167 """
168
168
169 # For some tests, it will be handy to organize them in a class with a common
169 # For some tests, it will be handy to organize them in a class with a common
170 # setup that makes a temp file
170 # setup that makes a temp file
171
171
172 class TestMagicRunPass(tt.TempFileMixin):
172 class TestMagicRunPass(tt.TempFileMixin):
173
173
174 def setUp(self):
174 def setUp(self):
175 content = "a = [1,2,3]\nb = 1"
175 content = "a = [1,2,3]\nb = 1"
176 self.mktmp(content)
176 self.mktmp(content)
177
177
178 def run_tmpfile(self):
178 def run_tmpfile(self):
179 _ip = get_ipython()
179 _ip = get_ipython()
180 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
180 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
181 # See below and ticket https://bugs.launchpad.net/bugs/366353
181 # See below and ticket https://bugs.launchpad.net/bugs/366353
182 _ip.magic('run %s' % self.fname)
182 _ip.magic('run %s' % self.fname)
183
183
184 def run_tmpfile_p(self):
184 def run_tmpfile_p(self):
185 _ip = get_ipython()
185 _ip = get_ipython()
186 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
186 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
187 # See below and ticket https://bugs.launchpad.net/bugs/366353
187 # See below and ticket https://bugs.launchpad.net/bugs/366353
188 _ip.magic('run -p %s' % self.fname)
188 _ip.magic('run -p %s' % self.fname)
189
189
190 def test_builtins_id(self):
190 def test_builtins_id(self):
191 """Check that %run doesn't damage __builtins__ """
191 """Check that %run doesn't damage __builtins__ """
192 _ip = get_ipython()
192 _ip = get_ipython()
193 # Test that the id of __builtins__ is not modified by %run
193 # Test that the id of __builtins__ is not modified by %run
194 bid1 = id(_ip.user_ns['__builtins__'])
194 bid1 = id(_ip.user_ns['__builtins__'])
195 self.run_tmpfile()
195 self.run_tmpfile()
196 bid2 = id(_ip.user_ns['__builtins__'])
196 bid2 = id(_ip.user_ns['__builtins__'])
197 assert bid1 == bid2
197 assert bid1 == bid2
198
198
199 def test_builtins_type(self):
199 def test_builtins_type(self):
200 """Check that the type of __builtins__ doesn't change with %run.
200 """Check that the type of __builtins__ doesn't change with %run.
201
201
202 However, the above could pass if __builtins__ was already modified to
202 However, the above could pass if __builtins__ was already modified to
203 be a dict (it should be a module) by a previous use of %run. So we
203 be a dict (it should be a module) by a previous use of %run. So we
204 also check explicitly that it really is a module:
204 also check explicitly that it really is a module:
205 """
205 """
206 _ip = get_ipython()
206 _ip = get_ipython()
207 self.run_tmpfile()
207 self.run_tmpfile()
208 assert type(_ip.user_ns["__builtins__"]) == type(sys)
208 assert type(_ip.user_ns["__builtins__"]) == type(sys)
209
209
210 def test_run_profile(self):
210 def test_run_profile(self):
211 """Test that the option -p, which invokes the profiler, do not
211 """Test that the option -p, which invokes the profiler, do not
212 crash by invoking execfile"""
212 crash by invoking execfile"""
213 self.run_tmpfile_p()
213 self.run_tmpfile_p()
214
214
215 def test_run_debug_twice(self):
215 def test_run_debug_twice(self):
216 # https://github.com/ipython/ipython/issues/10028
216 # https://github.com/ipython/ipython/issues/10028
217 _ip = get_ipython()
217 _ip = get_ipython()
218 with tt.fake_input(['c']):
218 with tt.fake_input(['c']):
219 _ip.magic('run -d %s' % self.fname)
219 _ip.magic('run -d %s' % self.fname)
220 with tt.fake_input(['c']):
220 with tt.fake_input(['c']):
221 _ip.magic('run -d %s' % self.fname)
221 _ip.magic('run -d %s' % self.fname)
222
222
223 def test_run_debug_twice_with_breakpoint(self):
223 def test_run_debug_twice_with_breakpoint(self):
224 """Make a valid python temp file."""
224 """Make a valid python temp file."""
225 _ip = get_ipython()
225 _ip = get_ipython()
226 with tt.fake_input(['b 2', 'c', 'c']):
226 with tt.fake_input(['b 2', 'c', 'c']):
227 _ip.magic('run -d %s' % self.fname)
227 _ip.magic('run -d %s' % self.fname)
228
228
229 with tt.fake_input(['c']):
229 with tt.fake_input(['c']):
230 with tt.AssertNotPrints('KeyError'):
230 with tt.AssertNotPrints('KeyError'):
231 _ip.magic('run -d %s' % self.fname)
231 _ip.magic('run -d %s' % self.fname)
232
232
233
233
234 class TestMagicRunSimple(tt.TempFileMixin):
234 class TestMagicRunSimple(tt.TempFileMixin):
235
235
236 def test_simpledef(self):
236 def test_simpledef(self):
237 """Test that simple class definitions work."""
237 """Test that simple class definitions work."""
238 src = ("class foo: pass\n"
238 src = ("class foo: pass\n"
239 "def f(): return foo()")
239 "def f(): return foo()")
240 self.mktmp(src)
240 self.mktmp(src)
241 _ip.magic("run %s" % self.fname)
241 _ip.magic("run %s" % self.fname)
242 _ip.run_cell("t = isinstance(f(), foo)")
242 _ip.run_cell("t = isinstance(f(), foo)")
243 assert _ip.user_ns["t"] is True
243 assert _ip.user_ns["t"] is True
244
244
245 @pytest.mark.xfail(
245 @pytest.mark.xfail(
246 platform.python_implementation() == "PyPy",
246 platform.python_implementation() == "PyPy",
247 reason="expecting __del__ call on exit is unreliable and doesn't happen on PyPy",
247 reason="expecting __del__ call on exit is unreliable and doesn't happen on PyPy",
248 )
248 )
249 def test_obj_del(self):
249 def test_obj_del(self):
250 """Test that object's __del__ methods are called on exit."""
250 """Test that object's __del__ methods are called on exit."""
251 src = ("class A(object):\n"
251 src = ("class A(object):\n"
252 " def __del__(self):\n"
252 " def __del__(self):\n"
253 " print('object A deleted')\n"
253 " print('object A deleted')\n"
254 "a = A()\n")
254 "a = A()\n")
255 self.mktmp(src)
255 self.mktmp(src)
256 err = None
256 err = None
257 tt.ipexec_validate(self.fname, 'object A deleted', err)
257 tt.ipexec_validate(self.fname, 'object A deleted', err)
258
258
259 def test_aggressive_namespace_cleanup(self):
259 def test_aggressive_namespace_cleanup(self):
260 """Test that namespace cleanup is not too aggressive GH-238
260 """Test that namespace cleanup is not too aggressive GH-238
261
261
262 Returning from another run magic deletes the namespace"""
262 Returning from another run magic deletes the namespace"""
263 # see ticket https://github.com/ipython/ipython/issues/238
263 # see ticket https://github.com/ipython/ipython/issues/238
264
264
265 with tt.TempFileMixin() as empty:
265 with tt.TempFileMixin() as empty:
266 empty.mktmp("")
266 empty.mktmp("")
267 # On Windows, the filename will have \users in it, so we need to use the
267 # On Windows, the filename will have \users in it, so we need to use the
268 # repr so that the \u becomes \\u.
268 # repr so that the \u becomes \\u.
269 src = (
269 src = (
270 "ip = get_ipython()\n"
270 "ip = get_ipython()\n"
271 "for i in range(5):\n"
271 "for i in range(5):\n"
272 " try:\n"
272 " try:\n"
273 " ip.magic(%r)\n"
273 " ip.magic(%r)\n"
274 " except NameError as e:\n"
274 " except NameError as e:\n"
275 " print(i)\n"
275 " print(i)\n"
276 " break\n" % ("run " + empty.fname)
276 " break\n" % ("run " + empty.fname)
277 )
277 )
278 self.mktmp(src)
278 self.mktmp(src)
279 _ip.magic("run %s" % self.fname)
279 _ip.magic("run %s" % self.fname)
280 _ip.run_cell("ip == get_ipython()")
280 _ip.run_cell("ip == get_ipython()")
281 assert _ip.user_ns["i"] == 4
281 assert _ip.user_ns["i"] == 4
282
282
283 def test_run_second(self):
283 def test_run_second(self):
284 """Test that running a second file doesn't clobber the first, gh-3547"""
284 """Test that running a second file doesn't clobber the first, gh-3547"""
285 self.mktmp("avar = 1\n" "def afunc():\n" " return avar\n")
285 self.mktmp("avar = 1\n" "def afunc():\n" " return avar\n")
286
286
287 with tt.TempFileMixin() as empty:
287 with tt.TempFileMixin() as empty:
288 empty.mktmp("")
288 empty.mktmp("")
289
289
290 _ip.magic("run %s" % self.fname)
290 _ip.magic("run %s" % self.fname)
291 _ip.magic("run %s" % empty.fname)
291 _ip.magic("run %s" % empty.fname)
292 assert _ip.user_ns["afunc"]() == 1
292 assert _ip.user_ns["afunc"]() == 1
293
293
294 def test_tclass(self):
294 def test_tclass(self):
295 mydir = os.path.dirname(__file__)
295 mydir = os.path.dirname(__file__)
296 tc = os.path.join(mydir, "tclass")
296 tc = os.path.join(mydir, "tclass")
297 src = f"""\
297 src = f"""\
298 import gc
298 import gc
299 %run "{tc}" C-first
299 %run "{tc}" C-first
300 gc.collect(0)
300 gc.collect(0)
301 %run "{tc}" C-second
301 %run "{tc}" C-second
302 gc.collect(0)
302 gc.collect(0)
303 %run "{tc}" C-third
303 %run "{tc}" C-third
304 gc.collect(0)
304 gc.collect(0)
305 %reset -f
305 %reset -f
306 """
306 """
307 self.mktmp(src, ".ipy")
307 self.mktmp(src, ".ipy")
308 out = """\
308 out = """\
309 ARGV 1-: ['C-first']
309 ARGV 1-: ['C-first']
310 ARGV 1-: ['C-second']
310 ARGV 1-: ['C-second']
311 tclass.py: deleting object: C-first
311 tclass.py: deleting object: C-first
312 ARGV 1-: ['C-third']
312 ARGV 1-: ['C-third']
313 tclass.py: deleting object: C-second
313 tclass.py: deleting object: C-second
314 tclass.py: deleting object: C-third
314 tclass.py: deleting object: C-third
315 """
315 """
316 err = None
316 err = None
317 tt.ipexec_validate(self.fname, out, err)
317 tt.ipexec_validate(self.fname, out, err)
318
318
319 def test_run_i_after_reset(self):
319 def test_run_i_after_reset(self):
320 """Check that %run -i still works after %reset (gh-693)"""
320 """Check that %run -i still works after %reset (gh-693)"""
321 src = "yy = zz\n"
321 src = "yy = zz\n"
322 self.mktmp(src)
322 self.mktmp(src)
323 _ip.run_cell("zz = 23")
323 _ip.run_cell("zz = 23")
324 try:
324 try:
325 _ip.magic("run -i %s" % self.fname)
325 _ip.magic("run -i %s" % self.fname)
326 assert _ip.user_ns["yy"] == 23
326 assert _ip.user_ns["yy"] == 23
327 finally:
327 finally:
328 _ip.magic('reset -f')
328 _ip.magic('reset -f')
329
329
330 _ip.run_cell("zz = 23")
330 _ip.run_cell("zz = 23")
331 try:
331 try:
332 _ip.magic("run -i %s" % self.fname)
332 _ip.magic("run -i %s" % self.fname)
333 assert _ip.user_ns["yy"] == 23
333 assert _ip.user_ns["yy"] == 23
334 finally:
334 finally:
335 _ip.magic('reset -f')
335 _ip.magic('reset -f')
336
336
337 def test_unicode(self):
337 def test_unicode(self):
338 """Check that files in odd encodings are accepted."""
338 """Check that files in odd encodings are accepted."""
339 mydir = os.path.dirname(__file__)
339 mydir = os.path.dirname(__file__)
340 na = os.path.join(mydir, 'nonascii.py')
340 na = os.path.join(mydir, 'nonascii.py')
341 _ip.magic('run "%s"' % na)
341 _ip.magic('run "%s"' % na)
342 assert _ip.user_ns["u"] == "Ўт№Ф"
342 assert _ip.user_ns["u"] == "Ўт№Ф"
343
343
344 def test_run_py_file_attribute(self):
344 def test_run_py_file_attribute(self):
345 """Test handling of `__file__` attribute in `%run <file>.py`."""
345 """Test handling of `__file__` attribute in `%run <file>.py`."""
346 src = "t = __file__\n"
346 src = "t = __file__\n"
347 self.mktmp(src)
347 self.mktmp(src)
348 _missing = object()
348 _missing = object()
349 file1 = _ip.user_ns.get('__file__', _missing)
349 file1 = _ip.user_ns.get('__file__', _missing)
350 _ip.magic('run %s' % self.fname)
350 _ip.magic('run %s' % self.fname)
351 file2 = _ip.user_ns.get('__file__', _missing)
351 file2 = _ip.user_ns.get('__file__', _missing)
352
352
353 # Check that __file__ was equal to the filename in the script's
353 # Check that __file__ was equal to the filename in the script's
354 # namespace.
354 # namespace.
355 assert _ip.user_ns["t"] == self.fname
355 assert _ip.user_ns["t"] == self.fname
356
356
357 # Check that __file__ was not leaked back into user_ns.
357 # Check that __file__ was not leaked back into user_ns.
358 assert file1 == file2
358 assert file1 == file2
359
359
360 def test_run_ipy_file_attribute(self):
360 def test_run_ipy_file_attribute(self):
361 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
361 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
362 src = "t = __file__\n"
362 src = "t = __file__\n"
363 self.mktmp(src, ext='.ipy')
363 self.mktmp(src, ext='.ipy')
364 _missing = object()
364 _missing = object()
365 file1 = _ip.user_ns.get('__file__', _missing)
365 file1 = _ip.user_ns.get('__file__', _missing)
366 _ip.magic('run %s' % self.fname)
366 _ip.magic('run %s' % self.fname)
367 file2 = _ip.user_ns.get('__file__', _missing)
367 file2 = _ip.user_ns.get('__file__', _missing)
368
368
369 # Check that __file__ was equal to the filename in the script's
369 # Check that __file__ was equal to the filename in the script's
370 # namespace.
370 # namespace.
371 assert _ip.user_ns["t"] == self.fname
371 assert _ip.user_ns["t"] == self.fname
372
372
373 # Check that __file__ was not leaked back into user_ns.
373 # Check that __file__ was not leaked back into user_ns.
374 assert file1 == file2
374 assert file1 == file2
375
375
376 def test_run_formatting(self):
376 def test_run_formatting(self):
377 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
377 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
378 src = "pass"
378 src = "pass"
379 self.mktmp(src)
379 self.mktmp(src)
380 _ip.magic('run -t -N 1 %s' % self.fname)
380 _ip.magic('run -t -N 1 %s' % self.fname)
381 _ip.magic('run -t -N 10 %s' % self.fname)
381 _ip.magic('run -t -N 10 %s' % self.fname)
382
382
383 def test_ignore_sys_exit(self):
383 def test_ignore_sys_exit(self):
384 """Test the -e option to ignore sys.exit()"""
384 """Test the -e option to ignore sys.exit()"""
385 src = "import sys; sys.exit(1)"
385 src = "import sys; sys.exit(1)"
386 self.mktmp(src)
386 self.mktmp(src)
387 with tt.AssertPrints('SystemExit'):
387 with tt.AssertPrints('SystemExit'):
388 _ip.magic('run %s' % self.fname)
388 _ip.magic('run %s' % self.fname)
389
389
390 with tt.AssertNotPrints('SystemExit'):
390 with tt.AssertNotPrints('SystemExit'):
391 _ip.magic('run -e %s' % self.fname)
391 _ip.magic('run -e %s' % self.fname)
392
392
393 def test_run_nb(self):
393 def test_run_nb(self):
394 """Test %run notebook.ipynb"""
394 """Test %run notebook.ipynb"""
395 pytest.importorskip("nbformat")
395 pytest.importorskip("nbformat")
396 from nbformat import v4, writes
396 from nbformat import v4, writes
397 nb = v4.new_notebook(
397 nb = v4.new_notebook(
398 cells=[
398 cells=[
399 v4.new_markdown_cell("The Ultimate Question of Everything"),
399 v4.new_markdown_cell("The Ultimate Question of Everything"),
400 v4.new_code_cell("answer=42")
400 v4.new_code_cell("answer=42")
401 ]
401 ]
402 )
402 )
403 src = writes(nb, version=4)
403 src = writes(nb, version=4)
404 self.mktmp(src, ext='.ipynb')
404 self.mktmp(src, ext='.ipynb')
405
405
406 _ip.magic("run %s" % self.fname)
406 _ip.magic("run %s" % self.fname)
407
407
408 assert _ip.user_ns["answer"] == 42
408 assert _ip.user_ns["answer"] == 42
409
409
410 def test_run_nb_error(self):
410 def test_run_nb_error(self):
411 """Test %run notebook.ipynb error"""
411 """Test %run notebook.ipynb error"""
412 pytest.importorskip("nbformat")
412 pytest.importorskip("nbformat")
413 from nbformat import v4, writes
413 from nbformat import v4, writes
414 # %run when a file name isn't provided
414 # %run when a file name isn't provided
415 pytest.raises(Exception, _ip.magic, "run")
415 pytest.raises(Exception, _ip.magic, "run")
416
416
417 # %run when a file doesn't exist
417 # %run when a file doesn't exist
418 pytest.raises(Exception, _ip.magic, "run foobar.ipynb")
418 pytest.raises(Exception, _ip.magic, "run foobar.ipynb")
419
419
420 # %run on a notebook with an error
420 # %run on a notebook with an error
421 nb = v4.new_notebook(
421 nb = v4.new_notebook(
422 cells=[
422 cells=[
423 v4.new_code_cell("0/0")
423 v4.new_code_cell("0/0")
424 ]
424 ]
425 )
425 )
426 src = writes(nb, version=4)
426 src = writes(nb, version=4)
427 self.mktmp(src, ext='.ipynb')
427 self.mktmp(src, ext='.ipynb')
428 pytest.raises(Exception, _ip.magic, "run %s" % self.fname)
428 pytest.raises(Exception, _ip.magic, "run %s" % self.fname)
429
429
430 def test_file_options(self):
430 def test_file_options(self):
431 src = ('import sys\n'
431 src = ('import sys\n'
432 'a = " ".join(sys.argv[1:])\n')
432 'a = " ".join(sys.argv[1:])\n')
433 self.mktmp(src)
433 self.mktmp(src)
434 test_opts = "-x 3 --verbose"
434 test_opts = "-x 3 --verbose"
435 _ip.run_line_magic("run", "{0} {1}".format(self.fname, test_opts))
435 _ip.run_line_magic("run", "{0} {1}".format(self.fname, test_opts))
436 assert _ip.user_ns["a"] == test_opts
436 assert _ip.user_ns["a"] == test_opts
437
437
438
438
439 class TestMagicRunWithPackage(unittest.TestCase):
439 class TestMagicRunWithPackage(unittest.TestCase):
440
440
441 def writefile(self, name, content):
441 def writefile(self, name, content):
442 path = os.path.join(self.tempdir.name, name)
442 path = os.path.join(self.tempdir.name, name)
443 d = os.path.dirname(path)
443 d = os.path.dirname(path)
444 if not os.path.isdir(d):
444 if not os.path.isdir(d):
445 os.makedirs(d)
445 os.makedirs(d)
446 with open(path, 'w', encoding='utf-8') as f:
446 with open(path, "w", encoding="utf-8") as f:
447 f.write(textwrap.dedent(content))
447 f.write(textwrap.dedent(content))
448
448
449 def setUp(self):
449 def setUp(self):
450 self.package = package = 'tmp{0}'.format(''.join([random.choice(string.ascii_letters) for i in range(10)]))
450 self.package = package = 'tmp{0}'.format(''.join([random.choice(string.ascii_letters) for i in range(10)]))
451 """Temporary (probably) valid python package name."""
451 """Temporary (probably) valid python package name."""
452
452
453 self.value = int(random.random() * 10000)
453 self.value = int(random.random() * 10000)
454
454
455 self.tempdir = TemporaryDirectory()
455 self.tempdir = TemporaryDirectory()
456 self.__orig_cwd = os.getcwd()
456 self.__orig_cwd = os.getcwd()
457 sys.path.insert(0, self.tempdir.name)
457 sys.path.insert(0, self.tempdir.name)
458
458
459 self.writefile(os.path.join(package, '__init__.py'), '')
459 self.writefile(os.path.join(package, '__init__.py'), '')
460 self.writefile(os.path.join(package, 'sub.py'), """
460 self.writefile(os.path.join(package, 'sub.py'), """
461 x = {0!r}
461 x = {0!r}
462 """.format(self.value))
462 """.format(self.value))
463 self.writefile(os.path.join(package, 'relative.py'), """
463 self.writefile(os.path.join(package, 'relative.py'), """
464 from .sub import x
464 from .sub import x
465 """)
465 """)
466 self.writefile(os.path.join(package, 'absolute.py'), """
466 self.writefile(os.path.join(package, 'absolute.py'), """
467 from {0}.sub import x
467 from {0}.sub import x
468 """.format(package))
468 """.format(package))
469 self.writefile(os.path.join(package, 'args.py'), """
469 self.writefile(os.path.join(package, 'args.py'), """
470 import sys
470 import sys
471 a = " ".join(sys.argv[1:])
471 a = " ".join(sys.argv[1:])
472 """.format(package))
472 """.format(package))
473
473
474 def tearDown(self):
474 def tearDown(self):
475 os.chdir(self.__orig_cwd)
475 os.chdir(self.__orig_cwd)
476 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
476 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
477 self.tempdir.cleanup()
477 self.tempdir.cleanup()
478
478
479 def check_run_submodule(self, submodule, opts=''):
479 def check_run_submodule(self, submodule, opts=''):
480 _ip.user_ns.pop('x', None)
480 _ip.user_ns.pop('x', None)
481 _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
481 _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
482 self.assertEqual(_ip.user_ns['x'], self.value,
482 self.assertEqual(_ip.user_ns['x'], self.value,
483 'Variable `x` is not loaded from module `{0}`.'
483 'Variable `x` is not loaded from module `{0}`.'
484 .format(submodule))
484 .format(submodule))
485
485
486 def test_run_submodule_with_absolute_import(self):
486 def test_run_submodule_with_absolute_import(self):
487 self.check_run_submodule('absolute')
487 self.check_run_submodule('absolute')
488
488
489 def test_run_submodule_with_relative_import(self):
489 def test_run_submodule_with_relative_import(self):
490 """Run submodule that has a relative import statement (#2727)."""
490 """Run submodule that has a relative import statement (#2727)."""
491 self.check_run_submodule('relative')
491 self.check_run_submodule('relative')
492
492
493 def test_prun_submodule_with_absolute_import(self):
493 def test_prun_submodule_with_absolute_import(self):
494 self.check_run_submodule('absolute', '-p')
494 self.check_run_submodule('absolute', '-p')
495
495
496 def test_prun_submodule_with_relative_import(self):
496 def test_prun_submodule_with_relative_import(self):
497 self.check_run_submodule('relative', '-p')
497 self.check_run_submodule('relative', '-p')
498
498
499 def with_fake_debugger(func):
499 def with_fake_debugger(func):
500 @functools.wraps(func)
500 @functools.wraps(func)
501 def wrapper(*args, **kwds):
501 def wrapper(*args, **kwds):
502 with patch.object(debugger.Pdb, 'run', staticmethod(eval)):
502 with patch.object(debugger.Pdb, 'run', staticmethod(eval)):
503 return func(*args, **kwds)
503 return func(*args, **kwds)
504 return wrapper
504 return wrapper
505
505
506 @with_fake_debugger
506 @with_fake_debugger
507 def test_debug_run_submodule_with_absolute_import(self):
507 def test_debug_run_submodule_with_absolute_import(self):
508 self.check_run_submodule('absolute', '-d')
508 self.check_run_submodule('absolute', '-d')
509
509
510 @with_fake_debugger
510 @with_fake_debugger
511 def test_debug_run_submodule_with_relative_import(self):
511 def test_debug_run_submodule_with_relative_import(self):
512 self.check_run_submodule('relative', '-d')
512 self.check_run_submodule('relative', '-d')
513
513
514 def test_module_options(self):
514 def test_module_options(self):
515 _ip.user_ns.pop("a", None)
515 _ip.user_ns.pop("a", None)
516 test_opts = "-x abc -m test"
516 test_opts = "-x abc -m test"
517 _ip.run_line_magic("run", "-m {0}.args {1}".format(self.package, test_opts))
517 _ip.run_line_magic("run", "-m {0}.args {1}".format(self.package, test_opts))
518 assert _ip.user_ns["a"] == test_opts
518 assert _ip.user_ns["a"] == test_opts
519
519
520 def test_module_options_with_separator(self):
520 def test_module_options_with_separator(self):
521 _ip.user_ns.pop("a", None)
521 _ip.user_ns.pop("a", None)
522 test_opts = "-x abc -m test"
522 test_opts = "-x abc -m test"
523 _ip.run_line_magic("run", "-m {0}.args -- {1}".format(self.package, test_opts))
523 _ip.run_line_magic("run", "-m {0}.args -- {1}".format(self.package, test_opts))
524 assert _ip.user_ns["a"] == test_opts
524 assert _ip.user_ns["a"] == test_opts
525
525
526
526
527 def test_run__name__():
527 def test_run__name__():
528 with TemporaryDirectory() as td:
528 with TemporaryDirectory() as td:
529 path = pjoin(td, 'foo.py')
529 path = pjoin(td, "foo.py")
530 with open(path, 'w', encoding='utf-8') as f:
530 with open(path, "w", encoding="utf-8") as f:
531 f.write("q = __name__")
531 f.write("q = __name__")
532
532
533 _ip.user_ns.pop("q", None)
533 _ip.user_ns.pop("q", None)
534 _ip.magic("run {}".format(path))
534 _ip.magic("run {}".format(path))
535 assert _ip.user_ns.pop("q") == "__main__"
535 assert _ip.user_ns.pop("q") == "__main__"
536
536
537 _ip.magic("run -n {}".format(path))
537 _ip.magic("run -n {}".format(path))
538 assert _ip.user_ns.pop("q") == "foo"
538 assert _ip.user_ns.pop("q") == "foo"
539
539
540 try:
540 try:
541 _ip.magic("run -i -n {}".format(path))
541 _ip.magic("run -i -n {}".format(path))
542 assert _ip.user_ns.pop("q") == "foo"
542 assert _ip.user_ns.pop("q") == "foo"
543 finally:
543 finally:
544 _ip.magic('reset -f')
544 _ip.magic('reset -f')
545
545
546
546
547 def test_run_tb():
547 def test_run_tb():
548 """Test traceback offset in %run"""
548 """Test traceback offset in %run"""
549 with TemporaryDirectory() as td:
549 with TemporaryDirectory() as td:
550 path = pjoin(td, 'foo.py')
550 path = pjoin(td, "foo.py")
551 with open(path, 'w', encoding='utf-8') as f:
551 with open(path, "w", encoding="utf-8") as f:
552 f.write('\n'.join([
552 f.write(
553 "\n".join(
554 [
553 "def foo():",
555 "def foo():",
554 " return bar()",
556 " return bar()",
555 "def bar():",
557 "def bar():",
556 " raise RuntimeError('hello!')",
558 " raise RuntimeError('hello!')",
557 "foo()",
559 "foo()",
558 ]))
560 ]
561 )
562 )
559 with capture_output() as io:
563 with capture_output() as io:
560 _ip.magic('run {}'.format(path))
564 _ip.magic('run {}'.format(path))
561 out = io.stdout
565 out = io.stdout
562 assert "execfile" not in out
566 assert "execfile" not in out
563 assert "RuntimeError" in out
567 assert "RuntimeError" in out
564 assert out.count("---->") == 3
568 assert out.count("---->") == 3
565 del ip.user_ns['bar']
569 del ip.user_ns['bar']
566 del ip.user_ns['foo']
570 del ip.user_ns['foo']
567
571
568
572
569 def test_multiprocessing_run():
573 def test_multiprocessing_run():
570 """Set we can run mutiprocesgin without messing up up main namespace
574 """Set we can run mutiprocesgin without messing up up main namespace
571
575
572 Note that import `nose.tools as nt` mdify the value s
576 Note that import `nose.tools as nt` mdify the value s
573 sys.module['__mp_main__'] so we need to temporarily set it to None to test
577 sys.module['__mp_main__'] so we need to temporarily set it to None to test
574 the issue.
578 the issue.
575 """
579 """
576 with TemporaryDirectory() as td:
580 with TemporaryDirectory() as td:
577 mpm = sys.modules.get('__mp_main__')
581 mpm = sys.modules.get('__mp_main__')
578 sys.modules['__mp_main__'] = None
582 sys.modules['__mp_main__'] = None
579 try:
583 try:
580 path = pjoin(td, 'test.py')
584 path = pjoin(td, "test.py")
581 with open(path, 'w', encoding='utf-8') as f:
585 with open(path, "w", encoding="utf-8") as f:
582 f.write("import multiprocessing\nprint('hoy')")
586 f.write("import multiprocessing\nprint('hoy')")
583 with capture_output() as io:
587 with capture_output() as io:
584 _ip.run_line_magic('run', path)
588 _ip.run_line_magic('run', path)
585 _ip.run_cell("i_m_undefined")
589 _ip.run_cell("i_m_undefined")
586 out = io.stdout
590 out = io.stdout
587 assert "hoy" in out
591 assert "hoy" in out
588 assert "AttributeError" not in out
592 assert "AttributeError" not in out
589 assert "NameError" in out
593 assert "NameError" in out
590 assert out.count("---->") == 1
594 assert out.count("---->") == 1
591 except:
595 except:
592 raise
596 raise
593 finally:
597 finally:
594 sys.modules['__mp_main__'] = mpm
598 sys.modules['__mp_main__'] = mpm
595
599
596
600
597 def test_script_tb():
601 def test_script_tb():
598 """Test traceback offset in `ipython script.py`"""
602 """Test traceback offset in `ipython script.py`"""
599 with TemporaryDirectory() as td:
603 with TemporaryDirectory() as td:
600 path = pjoin(td, 'foo.py')
604 path = pjoin(td, "foo.py")
601 with open(path, 'w', encoding='utf-8') as f:
605 with open(path, "w", encoding="utf-8") as f:
602 f.write('\n'.join([
606 f.write(
607 "\n".join(
608 [
603 "def foo():",
609 "def foo():",
604 " return bar()",
610 " return bar()",
605 "def bar():",
611 "def bar():",
606 " raise RuntimeError('hello!')",
612 " raise RuntimeError('hello!')",
607 "foo()",
613 "foo()",
608 ]))
614 ]
615 )
616 )
609 out, err = tt.ipexec(path)
617 out, err = tt.ipexec(path)
610 assert "execfile" not in out
618 assert "execfile" not in out
611 assert "RuntimeError" in out
619 assert "RuntimeError" in out
612 assert out.count("---->") == 3
620 assert out.count("---->") == 3
@@ -1,410 +1,410 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for IPython.core.ultratb
2 """Tests for IPython.core.ultratb
3 """
3 """
4 import io
4 import io
5 import logging
5 import logging
6 import platform
6 import platform
7 import re
7 import re
8 import sys
8 import sys
9 import os.path
9 import os.path
10 from textwrap import dedent
10 from textwrap import dedent
11 import traceback
11 import traceback
12 import unittest
12 import unittest
13
13
14 from IPython.core.ultratb import ColorTB, VerboseTB
14 from IPython.core.ultratb import ColorTB, VerboseTB
15
15
16
16
17 from IPython.testing import tools as tt
17 from IPython.testing import tools as tt
18 from IPython.testing.decorators import onlyif_unicode_paths
18 from IPython.testing.decorators import onlyif_unicode_paths
19 from IPython.utils.syspathcontext import prepended_to_syspath
19 from IPython.utils.syspathcontext import prepended_to_syspath
20 from IPython.utils.tempdir import TemporaryDirectory
20 from IPython.utils.tempdir import TemporaryDirectory
21
21
22 file_1 = """1
22 file_1 = """1
23 2
23 2
24 3
24 3
25 def f():
25 def f():
26 1/0
26 1/0
27 """
27 """
28
28
29 file_2 = """def f():
29 file_2 = """def f():
30 1/0
30 1/0
31 """
31 """
32
32
33
33
34 def recursionlimit(frames):
34 def recursionlimit(frames):
35 """
35 """
36 decorator to set the recursion limit temporarily
36 decorator to set the recursion limit temporarily
37 """
37 """
38
38
39 def inner(test_function):
39 def inner(test_function):
40 def wrapper(*args, **kwargs):
40 def wrapper(*args, **kwargs):
41 rl = sys.getrecursionlimit()
41 rl = sys.getrecursionlimit()
42 sys.setrecursionlimit(frames)
42 sys.setrecursionlimit(frames)
43 try:
43 try:
44 return test_function(*args, **kwargs)
44 return test_function(*args, **kwargs)
45 finally:
45 finally:
46 sys.setrecursionlimit(rl)
46 sys.setrecursionlimit(rl)
47
47
48 return wrapper
48 return wrapper
49
49
50 return inner
50 return inner
51
51
52
52
53 class ChangedPyFileTest(unittest.TestCase):
53 class ChangedPyFileTest(unittest.TestCase):
54 def test_changing_py_file(self):
54 def test_changing_py_file(self):
55 """Traceback produced if the line where the error occurred is missing?
55 """Traceback produced if the line where the error occurred is missing?
56
56
57 https://github.com/ipython/ipython/issues/1456
57 https://github.com/ipython/ipython/issues/1456
58 """
58 """
59 with TemporaryDirectory() as td:
59 with TemporaryDirectory() as td:
60 fname = os.path.join(td, "foo.py")
60 fname = os.path.join(td, "foo.py")
61 with open(fname, "w", encoding='utf-8') as f:
61 with open(fname, "w", encoding="utf-8") as f:
62 f.write(file_1)
62 f.write(file_1)
63
63
64 with prepended_to_syspath(td):
64 with prepended_to_syspath(td):
65 ip.run_cell("import foo")
65 ip.run_cell("import foo")
66
66
67 with tt.AssertPrints("ZeroDivisionError"):
67 with tt.AssertPrints("ZeroDivisionError"):
68 ip.run_cell("foo.f()")
68 ip.run_cell("foo.f()")
69
69
70 # Make the file shorter, so the line of the error is missing.
70 # Make the file shorter, so the line of the error is missing.
71 with open(fname, "w", encoding='utf-8') as f:
71 with open(fname, "w", encoding="utf-8") as f:
72 f.write(file_2)
72 f.write(file_2)
73
73
74 # For some reason, this was failing on the *second* call after
74 # For some reason, this was failing on the *second* call after
75 # changing the file, so we call f() twice.
75 # changing the file, so we call f() twice.
76 with tt.AssertNotPrints("Internal Python error", channel='stderr'):
76 with tt.AssertNotPrints("Internal Python error", channel='stderr'):
77 with tt.AssertPrints("ZeroDivisionError"):
77 with tt.AssertPrints("ZeroDivisionError"):
78 ip.run_cell("foo.f()")
78 ip.run_cell("foo.f()")
79 with tt.AssertPrints("ZeroDivisionError"):
79 with tt.AssertPrints("ZeroDivisionError"):
80 ip.run_cell("foo.f()")
80 ip.run_cell("foo.f()")
81
81
82 iso_8859_5_file = u'''# coding: iso-8859-5
82 iso_8859_5_file = u'''# coding: iso-8859-5
83
83
84 def fail():
84 def fail():
85 """дбИЖ"""
85 """дбИЖ"""
86 1/0 # дбИЖ
86 1/0 # дбИЖ
87 '''
87 '''
88
88
89 class NonAsciiTest(unittest.TestCase):
89 class NonAsciiTest(unittest.TestCase):
90 @onlyif_unicode_paths
90 @onlyif_unicode_paths
91 def test_nonascii_path(self):
91 def test_nonascii_path(self):
92 # Non-ascii directory name as well.
92 # Non-ascii directory name as well.
93 with TemporaryDirectory(suffix=u'é') as td:
93 with TemporaryDirectory(suffix=u'é') as td:
94 fname = os.path.join(td, u"fooé.py")
94 fname = os.path.join(td, u"fooé.py")
95 with open(fname, "w", encoding='utf-8') as f:
95 with open(fname, "w", encoding="utf-8") as f:
96 f.write(file_1)
96 f.write(file_1)
97
97
98 with prepended_to_syspath(td):
98 with prepended_to_syspath(td):
99 ip.run_cell("import foo")
99 ip.run_cell("import foo")
100
100
101 with tt.AssertPrints("ZeroDivisionError"):
101 with tt.AssertPrints("ZeroDivisionError"):
102 ip.run_cell("foo.f()")
102 ip.run_cell("foo.f()")
103
103
104 def test_iso8859_5(self):
104 def test_iso8859_5(self):
105 with TemporaryDirectory() as td:
105 with TemporaryDirectory() as td:
106 fname = os.path.join(td, 'dfghjkl.py')
106 fname = os.path.join(td, 'dfghjkl.py')
107
107
108 with io.open(fname, 'w', encoding='iso-8859-5') as f:
108 with io.open(fname, 'w', encoding='iso-8859-5') as f:
109 f.write(iso_8859_5_file)
109 f.write(iso_8859_5_file)
110
110
111 with prepended_to_syspath(td):
111 with prepended_to_syspath(td):
112 ip.run_cell("from dfghjkl import fail")
112 ip.run_cell("from dfghjkl import fail")
113
113
114 with tt.AssertPrints("ZeroDivisionError"):
114 with tt.AssertPrints("ZeroDivisionError"):
115 with tt.AssertPrints(u'дбИЖ', suppress=False):
115 with tt.AssertPrints(u'дбИЖ', suppress=False):
116 ip.run_cell('fail()')
116 ip.run_cell('fail()')
117
117
118 def test_nonascii_msg(self):
118 def test_nonascii_msg(self):
119 cell = u"raise Exception('é')"
119 cell = u"raise Exception('é')"
120 expected = u"Exception('é')"
120 expected = u"Exception('é')"
121 ip.run_cell("%xmode plain")
121 ip.run_cell("%xmode plain")
122 with tt.AssertPrints(expected):
122 with tt.AssertPrints(expected):
123 ip.run_cell(cell)
123 ip.run_cell(cell)
124
124
125 ip.run_cell("%xmode verbose")
125 ip.run_cell("%xmode verbose")
126 with tt.AssertPrints(expected):
126 with tt.AssertPrints(expected):
127 ip.run_cell(cell)
127 ip.run_cell(cell)
128
128
129 ip.run_cell("%xmode context")
129 ip.run_cell("%xmode context")
130 with tt.AssertPrints(expected):
130 with tt.AssertPrints(expected):
131 ip.run_cell(cell)
131 ip.run_cell(cell)
132
132
133 ip.run_cell("%xmode minimal")
133 ip.run_cell("%xmode minimal")
134 with tt.AssertPrints(u"Exception: é"):
134 with tt.AssertPrints(u"Exception: é"):
135 ip.run_cell(cell)
135 ip.run_cell(cell)
136
136
137 # Put this back into Context mode for later tests.
137 # Put this back into Context mode for later tests.
138 ip.run_cell("%xmode context")
138 ip.run_cell("%xmode context")
139
139
140 class NestedGenExprTestCase(unittest.TestCase):
140 class NestedGenExprTestCase(unittest.TestCase):
141 """
141 """
142 Regression test for the following issues:
142 Regression test for the following issues:
143 https://github.com/ipython/ipython/issues/8293
143 https://github.com/ipython/ipython/issues/8293
144 https://github.com/ipython/ipython/issues/8205
144 https://github.com/ipython/ipython/issues/8205
145 """
145 """
146 def test_nested_genexpr(self):
146 def test_nested_genexpr(self):
147 code = dedent(
147 code = dedent(
148 """\
148 """\
149 class SpecificException(Exception):
149 class SpecificException(Exception):
150 pass
150 pass
151
151
152 def foo(x):
152 def foo(x):
153 raise SpecificException("Success!")
153 raise SpecificException("Success!")
154
154
155 sum(sum(foo(x) for _ in [0]) for x in [0])
155 sum(sum(foo(x) for _ in [0]) for x in [0])
156 """
156 """
157 )
157 )
158 with tt.AssertPrints('SpecificException: Success!', suppress=False):
158 with tt.AssertPrints('SpecificException: Success!', suppress=False):
159 ip.run_cell(code)
159 ip.run_cell(code)
160
160
161
161
162 indentationerror_file = """if True:
162 indentationerror_file = """if True:
163 zoon()
163 zoon()
164 """
164 """
165
165
166 class IndentationErrorTest(unittest.TestCase):
166 class IndentationErrorTest(unittest.TestCase):
167 def test_indentationerror_shows_line(self):
167 def test_indentationerror_shows_line(self):
168 # See issue gh-2398
168 # See issue gh-2398
169 with tt.AssertPrints("IndentationError"):
169 with tt.AssertPrints("IndentationError"):
170 with tt.AssertPrints("zoon()", suppress=False):
170 with tt.AssertPrints("zoon()", suppress=False):
171 ip.run_cell(indentationerror_file)
171 ip.run_cell(indentationerror_file)
172
172
173 with TemporaryDirectory() as td:
173 with TemporaryDirectory() as td:
174 fname = os.path.join(td, "foo.py")
174 fname = os.path.join(td, "foo.py")
175 with open(fname, "w", encoding='utf-8') as f:
175 with open(fname, "w", encoding="utf-8") as f:
176 f.write(indentationerror_file)
176 f.write(indentationerror_file)
177
177
178 with tt.AssertPrints("IndentationError"):
178 with tt.AssertPrints("IndentationError"):
179 with tt.AssertPrints("zoon()", suppress=False):
179 with tt.AssertPrints("zoon()", suppress=False):
180 ip.magic('run %s' % fname)
180 ip.magic('run %s' % fname)
181
181
182 se_file_1 = """1
182 se_file_1 = """1
183 2
183 2
184 7/
184 7/
185 """
185 """
186
186
187 se_file_2 = """7/
187 se_file_2 = """7/
188 """
188 """
189
189
190 class SyntaxErrorTest(unittest.TestCase):
190 class SyntaxErrorTest(unittest.TestCase):
191
191
192 def test_syntaxerror_no_stacktrace_at_compile_time(self):
192 def test_syntaxerror_no_stacktrace_at_compile_time(self):
193 syntax_error_at_compile_time = """
193 syntax_error_at_compile_time = """
194 def foo():
194 def foo():
195 ..
195 ..
196 """
196 """
197 with tt.AssertPrints("SyntaxError"):
197 with tt.AssertPrints("SyntaxError"):
198 ip.run_cell(syntax_error_at_compile_time)
198 ip.run_cell(syntax_error_at_compile_time)
199
199
200 with tt.AssertNotPrints("foo()"):
200 with tt.AssertNotPrints("foo()"):
201 ip.run_cell(syntax_error_at_compile_time)
201 ip.run_cell(syntax_error_at_compile_time)
202
202
203 def test_syntaxerror_stacktrace_when_running_compiled_code(self):
203 def test_syntaxerror_stacktrace_when_running_compiled_code(self):
204 syntax_error_at_runtime = """
204 syntax_error_at_runtime = """
205 def foo():
205 def foo():
206 eval("..")
206 eval("..")
207
207
208 def bar():
208 def bar():
209 foo()
209 foo()
210
210
211 bar()
211 bar()
212 """
212 """
213 with tt.AssertPrints("SyntaxError"):
213 with tt.AssertPrints("SyntaxError"):
214 ip.run_cell(syntax_error_at_runtime)
214 ip.run_cell(syntax_error_at_runtime)
215 # Assert syntax error during runtime generate stacktrace
215 # Assert syntax error during runtime generate stacktrace
216 with tt.AssertPrints(["foo()", "bar()"]):
216 with tt.AssertPrints(["foo()", "bar()"]):
217 ip.run_cell(syntax_error_at_runtime)
217 ip.run_cell(syntax_error_at_runtime)
218 del ip.user_ns['bar']
218 del ip.user_ns['bar']
219 del ip.user_ns['foo']
219 del ip.user_ns['foo']
220
220
221 def test_changing_py_file(self):
221 def test_changing_py_file(self):
222 with TemporaryDirectory() as td:
222 with TemporaryDirectory() as td:
223 fname = os.path.join(td, "foo.py")
223 fname = os.path.join(td, "foo.py")
224 with open(fname, 'w', encoding='utf-8') as f:
224 with open(fname, "w", encoding="utf-8") as f:
225 f.write(se_file_1)
225 f.write(se_file_1)
226
226
227 with tt.AssertPrints(["7/", "SyntaxError"]):
227 with tt.AssertPrints(["7/", "SyntaxError"]):
228 ip.magic("run " + fname)
228 ip.magic("run " + fname)
229
229
230 # Modify the file
230 # Modify the file
231 with open(fname, 'w', encoding='utf-8') as f:
231 with open(fname, "w", encoding="utf-8") as f:
232 f.write(se_file_2)
232 f.write(se_file_2)
233
233
234 # The SyntaxError should point to the correct line
234 # The SyntaxError should point to the correct line
235 with tt.AssertPrints(["7/", "SyntaxError"]):
235 with tt.AssertPrints(["7/", "SyntaxError"]):
236 ip.magic("run " + fname)
236 ip.magic("run " + fname)
237
237
238 def test_non_syntaxerror(self):
238 def test_non_syntaxerror(self):
239 # SyntaxTB may be called with an error other than a SyntaxError
239 # SyntaxTB may be called with an error other than a SyntaxError
240 # See e.g. gh-4361
240 # See e.g. gh-4361
241 try:
241 try:
242 raise ValueError('QWERTY')
242 raise ValueError('QWERTY')
243 except ValueError:
243 except ValueError:
244 with tt.AssertPrints('QWERTY'):
244 with tt.AssertPrints('QWERTY'):
245 ip.showsyntaxerror()
245 ip.showsyntaxerror()
246
246
247 import sys
247 import sys
248
248
249 if sys.version_info < (3, 9) and platform.python_implementation() != "PyPy":
249 if sys.version_info < (3, 9) and platform.python_implementation() != "PyPy":
250 """
250 """
251 New 3.9 Pgen Parser does not raise Memory error, except on failed malloc.
251 New 3.9 Pgen Parser does not raise Memory error, except on failed malloc.
252 """
252 """
253 class MemoryErrorTest(unittest.TestCase):
253 class MemoryErrorTest(unittest.TestCase):
254 def test_memoryerror(self):
254 def test_memoryerror(self):
255 memoryerror_code = "(" * 200 + ")" * 200
255 memoryerror_code = "(" * 200 + ")" * 200
256 with tt.AssertPrints("MemoryError"):
256 with tt.AssertPrints("MemoryError"):
257 ip.run_cell(memoryerror_code)
257 ip.run_cell(memoryerror_code)
258
258
259
259
260 class Python3ChainedExceptionsTest(unittest.TestCase):
260 class Python3ChainedExceptionsTest(unittest.TestCase):
261 DIRECT_CAUSE_ERROR_CODE = """
261 DIRECT_CAUSE_ERROR_CODE = """
262 try:
262 try:
263 x = 1 + 2
263 x = 1 + 2
264 print(not_defined_here)
264 print(not_defined_here)
265 except Exception as e:
265 except Exception as e:
266 x += 55
266 x += 55
267 x - 1
267 x - 1
268 y = {}
268 y = {}
269 raise KeyError('uh') from e
269 raise KeyError('uh') from e
270 """
270 """
271
271
272 EXCEPTION_DURING_HANDLING_CODE = """
272 EXCEPTION_DURING_HANDLING_CODE = """
273 try:
273 try:
274 x = 1 + 2
274 x = 1 + 2
275 print(not_defined_here)
275 print(not_defined_here)
276 except Exception as e:
276 except Exception as e:
277 x += 55
277 x += 55
278 x - 1
278 x - 1
279 y = {}
279 y = {}
280 raise KeyError('uh')
280 raise KeyError('uh')
281 """
281 """
282
282
283 SUPPRESS_CHAINING_CODE = """
283 SUPPRESS_CHAINING_CODE = """
284 try:
284 try:
285 1/0
285 1/0
286 except Exception:
286 except Exception:
287 raise ValueError("Yikes") from None
287 raise ValueError("Yikes") from None
288 """
288 """
289
289
290 def test_direct_cause_error(self):
290 def test_direct_cause_error(self):
291 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
291 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
292 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
292 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
293
293
294 def test_exception_during_handling_error(self):
294 def test_exception_during_handling_error(self):
295 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
295 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
296 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
296 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
297
297
298 def test_suppress_exception_chaining(self):
298 def test_suppress_exception_chaining(self):
299 with tt.AssertNotPrints("ZeroDivisionError"), \
299 with tt.AssertNotPrints("ZeroDivisionError"), \
300 tt.AssertPrints("ValueError", suppress=False):
300 tt.AssertPrints("ValueError", suppress=False):
301 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
301 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
302
302
303 def test_plain_direct_cause_error(self):
303 def test_plain_direct_cause_error(self):
304 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
304 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
305 ip.run_cell("%xmode Plain")
305 ip.run_cell("%xmode Plain")
306 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
306 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
307 ip.run_cell("%xmode Verbose")
307 ip.run_cell("%xmode Verbose")
308
308
309 def test_plain_exception_during_handling_error(self):
309 def test_plain_exception_during_handling_error(self):
310 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
310 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
311 ip.run_cell("%xmode Plain")
311 ip.run_cell("%xmode Plain")
312 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
312 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
313 ip.run_cell("%xmode Verbose")
313 ip.run_cell("%xmode Verbose")
314
314
315 def test_plain_suppress_exception_chaining(self):
315 def test_plain_suppress_exception_chaining(self):
316 with tt.AssertNotPrints("ZeroDivisionError"), \
316 with tt.AssertNotPrints("ZeroDivisionError"), \
317 tt.AssertPrints("ValueError", suppress=False):
317 tt.AssertPrints("ValueError", suppress=False):
318 ip.run_cell("%xmode Plain")
318 ip.run_cell("%xmode Plain")
319 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
319 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
320 ip.run_cell("%xmode Verbose")
320 ip.run_cell("%xmode Verbose")
321
321
322
322
323 class RecursionTest(unittest.TestCase):
323 class RecursionTest(unittest.TestCase):
324 DEFINITIONS = """
324 DEFINITIONS = """
325 def non_recurs():
325 def non_recurs():
326 1/0
326 1/0
327
327
328 def r1():
328 def r1():
329 r1()
329 r1()
330
330
331 def r3a():
331 def r3a():
332 r3b()
332 r3b()
333
333
334 def r3b():
334 def r3b():
335 r3c()
335 r3c()
336
336
337 def r3c():
337 def r3c():
338 r3a()
338 r3a()
339
339
340 def r3o1():
340 def r3o1():
341 r3a()
341 r3a()
342
342
343 def r3o2():
343 def r3o2():
344 r3o1()
344 r3o1()
345 """
345 """
346 def setUp(self):
346 def setUp(self):
347 ip.run_cell(self.DEFINITIONS)
347 ip.run_cell(self.DEFINITIONS)
348
348
349 def test_no_recursion(self):
349 def test_no_recursion(self):
350 with tt.AssertNotPrints("skipping similar frames"):
350 with tt.AssertNotPrints("skipping similar frames"):
351 ip.run_cell("non_recurs()")
351 ip.run_cell("non_recurs()")
352
352
353 @recursionlimit(200)
353 @recursionlimit(200)
354 def test_recursion_one_frame(self):
354 def test_recursion_one_frame(self):
355 with tt.AssertPrints(re.compile(
355 with tt.AssertPrints(re.compile(
356 r"\[\.\.\. skipping similar frames: r1 at line 5 \(\d{2,3} times\)\]")
356 r"\[\.\.\. skipping similar frames: r1 at line 5 \(\d{2,3} times\)\]")
357 ):
357 ):
358 ip.run_cell("r1()")
358 ip.run_cell("r1()")
359
359
360 @recursionlimit(160)
360 @recursionlimit(160)
361 def test_recursion_three_frames(self):
361 def test_recursion_three_frames(self):
362 with tt.AssertPrints("[... skipping similar frames: "), \
362 with tt.AssertPrints("[... skipping similar frames: "), \
363 tt.AssertPrints(re.compile(r"r3a at line 8 \(\d{2} times\)"), suppress=False), \
363 tt.AssertPrints(re.compile(r"r3a at line 8 \(\d{2} times\)"), suppress=False), \
364 tt.AssertPrints(re.compile(r"r3b at line 11 \(\d{2} times\)"), suppress=False), \
364 tt.AssertPrints(re.compile(r"r3b at line 11 \(\d{2} times\)"), suppress=False), \
365 tt.AssertPrints(re.compile(r"r3c at line 14 \(\d{2} times\)"), suppress=False):
365 tt.AssertPrints(re.compile(r"r3c at line 14 \(\d{2} times\)"), suppress=False):
366 ip.run_cell("r3o2()")
366 ip.run_cell("r3o2()")
367
367
368
368
369 #----------------------------------------------------------------------------
369 #----------------------------------------------------------------------------
370
370
371 # module testing (minimal)
371 # module testing (minimal)
372 def test_handlers():
372 def test_handlers():
373 def spam(c, d_e):
373 def spam(c, d_e):
374 (d, e) = d_e
374 (d, e) = d_e
375 x = c + d
375 x = c + d
376 y = c * d
376 y = c * d
377 foo(x, y)
377 foo(x, y)
378
378
379 def foo(a, b, bar=1):
379 def foo(a, b, bar=1):
380 eggs(a, b + bar)
380 eggs(a, b + bar)
381
381
382 def eggs(f, g, z=globals()):
382 def eggs(f, g, z=globals()):
383 h = f + g
383 h = f + g
384 i = f - g
384 i = f - g
385 return h / i
385 return h / i
386
386
387 buff = io.StringIO()
387 buff = io.StringIO()
388
388
389 buff.write('')
389 buff.write('')
390 buff.write('*** Before ***')
390 buff.write('*** Before ***')
391 try:
391 try:
392 buff.write(spam(1, (2, 3)))
392 buff.write(spam(1, (2, 3)))
393 except:
393 except:
394 traceback.print_exc(file=buff)
394 traceback.print_exc(file=buff)
395
395
396 handler = ColorTB(ostream=buff)
396 handler = ColorTB(ostream=buff)
397 buff.write('*** ColorTB ***')
397 buff.write('*** ColorTB ***')
398 try:
398 try:
399 buff.write(spam(1, (2, 3)))
399 buff.write(spam(1, (2, 3)))
400 except:
400 except:
401 handler(*sys.exc_info())
401 handler(*sys.exc_info())
402 buff.write('')
402 buff.write('')
403
403
404 handler = VerboseTB(ostream=buff)
404 handler = VerboseTB(ostream=buff)
405 buff.write('*** VerboseTB ***')
405 buff.write('*** VerboseTB ***')
406 try:
406 try:
407 buff.write(spam(1, (2, 3)))
407 buff.write(spam(1, (2, 3)))
408 except:
408 except:
409 handler(*sys.exc_info())
409 handler(*sys.exc_info())
410 buff.write('')
410 buff.write('')
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now