##// END OF EJS Templates
Links cleanup, in particular peps have moved
Matthias Bussonnier -
Show More
@@ -1,854 +1,854 b''
1 """Implementation of magic functions for interaction with the OS.
1 """Implementation of magic functions for interaction with the OS.
2
2
3 Note: this module is named 'osm' instead of 'os' to avoid a collision with the
3 Note: this module is named 'osm' instead of 'os' to avoid a collision with the
4 builtin.
4 builtin.
5 """
5 """
6 # Copyright (c) IPython Development Team.
6 # Copyright (c) IPython Development Team.
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8
8
9 import io
9 import io
10 import os
10 import os
11 import re
11 import re
12 import sys
12 import sys
13 from pprint import pformat
13 from pprint import pformat
14
14
15 from IPython.core import magic_arguments
15 from IPython.core import magic_arguments
16 from IPython.core import oinspect
16 from IPython.core import oinspect
17 from IPython.core import page
17 from IPython.core import page
18 from IPython.core.alias import AliasError, Alias
18 from IPython.core.alias import AliasError, Alias
19 from IPython.core.error import UsageError
19 from IPython.core.error import UsageError
20 from IPython.core.magic import (
20 from IPython.core.magic import (
21 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
21 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
22 )
22 )
23 from IPython.testing.skipdoctest import skip_doctest
23 from IPython.testing.skipdoctest import skip_doctest
24 from IPython.utils.openpy import source_to_unicode
24 from IPython.utils.openpy import source_to_unicode
25 from IPython.utils.process import abbrev_cwd
25 from IPython.utils.process import abbrev_cwd
26 from IPython.utils.terminal import set_term_title
26 from IPython.utils.terminal import set_term_title
27 from traitlets import Bool
27 from traitlets import Bool
28 from warnings import warn
28 from warnings import warn
29
29
30
30
31 @magics_class
31 @magics_class
32 class OSMagics(Magics):
32 class OSMagics(Magics):
33 """Magics to interact with the underlying OS (shell-type functionality).
33 """Magics to interact with the underlying OS (shell-type functionality).
34 """
34 """
35
35
36 cd_force_quiet = Bool(False,
36 cd_force_quiet = Bool(False,
37 help="Force %cd magic to be quiet even if -q is not passed."
37 help="Force %cd magic to be quiet even if -q is not passed."
38 ).tag(config=True)
38 ).tag(config=True)
39
39
40 def __init__(self, shell=None, **kwargs):
40 def __init__(self, shell=None, **kwargs):
41
41
42 # Now define isexec in a cross platform manner.
42 # Now define isexec in a cross platform manner.
43 self.is_posix = False
43 self.is_posix = False
44 self.execre = None
44 self.execre = None
45 if os.name == 'posix':
45 if os.name == 'posix':
46 self.is_posix = True
46 self.is_posix = True
47 else:
47 else:
48 try:
48 try:
49 winext = os.environ['pathext'].replace(';','|').replace('.','')
49 winext = os.environ['pathext'].replace(';','|').replace('.','')
50 except KeyError:
50 except KeyError:
51 winext = 'exe|com|bat|py'
51 winext = 'exe|com|bat|py'
52 try:
52 try:
53 self.execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
53 self.execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
54 except re.error:
54 except re.error:
55 warn("Seems like your pathext environmental "
55 warn("Seems like your pathext environmental "
56 "variable is malformed. Please check it to "
56 "variable is malformed. Please check it to "
57 "enable a proper handle of file extensions "
57 "enable a proper handle of file extensions "
58 "managed for your system")
58 "managed for your system")
59 winext = 'exe|com|bat|py'
59 winext = 'exe|com|bat|py'
60 self.execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
60 self.execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
61
61
62 # call up the chain
62 # call up the chain
63 super().__init__(shell=shell, **kwargs)
63 super().__init__(shell=shell, **kwargs)
64
64
65
65
66 def _isexec_POSIX(self, file):
66 def _isexec_POSIX(self, file):
67 """
67 """
68 Test for executable on a POSIX system
68 Test for executable on a POSIX system
69 """
69 """
70 if os.access(file.path, os.X_OK):
70 if os.access(file.path, os.X_OK):
71 # will fail on maxOS if access is not X_OK
71 # will fail on maxOS if access is not X_OK
72 return file.is_file()
72 return file.is_file()
73 return False
73 return False
74
74
75
75
76
76
77 def _isexec_WIN(self, file):
77 def _isexec_WIN(self, file):
78 """
78 """
79 Test for executable file on non POSIX system
79 Test for executable file on non POSIX system
80 """
80 """
81 return file.is_file() and self.execre.match(file.name) is not None
81 return file.is_file() and self.execre.match(file.name) is not None
82
82
83 def isexec(self, file):
83 def isexec(self, file):
84 """
84 """
85 Test for executable file on non POSIX system
85 Test for executable file on non POSIX system
86 """
86 """
87 if self.is_posix:
87 if self.is_posix:
88 return self._isexec_POSIX(file)
88 return self._isexec_POSIX(file)
89 else:
89 else:
90 return self._isexec_WIN(file)
90 return self._isexec_WIN(file)
91
91
92
92
93 @skip_doctest
93 @skip_doctest
94 @line_magic
94 @line_magic
95 def alias(self, parameter_s=''):
95 def alias(self, parameter_s=''):
96 """Define an alias for a system command.
96 """Define an alias for a system command.
97
97
98 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
98 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
99
99
100 Then, typing 'alias_name params' will execute the system command 'cmd
100 Then, typing 'alias_name params' will execute the system command 'cmd
101 params' (from your underlying operating system).
101 params' (from your underlying operating system).
102
102
103 Aliases have lower precedence than magic functions and Python normal
103 Aliases have lower precedence than magic functions and Python normal
104 variables, so if 'foo' is both a Python variable and an alias, the
104 variables, so if 'foo' is both a Python variable and an alias, the
105 alias can not be executed until 'del foo' removes the Python variable.
105 alias can not be executed until 'del foo' removes the Python variable.
106
106
107 You can use the %l specifier in an alias definition to represent the
107 You can use the %l specifier in an alias definition to represent the
108 whole line when the alias is called. For example::
108 whole line when the alias is called. For example::
109
109
110 In [2]: alias bracket echo "Input in brackets: <%l>"
110 In [2]: alias bracket echo "Input in brackets: <%l>"
111 In [3]: bracket hello world
111 In [3]: bracket hello world
112 Input in brackets: <hello world>
112 Input in brackets: <hello world>
113
113
114 You can also define aliases with parameters using %s specifiers (one
114 You can also define aliases with parameters using %s specifiers (one
115 per parameter)::
115 per parameter)::
116
116
117 In [1]: alias parts echo first %s second %s
117 In [1]: alias parts echo first %s second %s
118 In [2]: %parts A B
118 In [2]: %parts A B
119 first A second B
119 first A second B
120 In [3]: %parts A
120 In [3]: %parts A
121 Incorrect number of arguments: 2 expected.
121 Incorrect number of arguments: 2 expected.
122 parts is an alias to: 'echo first %s second %s'
122 parts is an alias to: 'echo first %s second %s'
123
123
124 Note that %l and %s are mutually exclusive. You can only use one or
124 Note that %l and %s are mutually exclusive. You can only use one or
125 the other in your aliases.
125 the other in your aliases.
126
126
127 Aliases expand Python variables just like system calls using ! or !!
127 Aliases expand Python variables just like system calls using ! or !!
128 do: all expressions prefixed with '$' get expanded. For details of
128 do: all expressions prefixed with '$' get expanded. For details of
129 the semantic rules, see PEP-215:
129 the semantic rules, see PEP-215:
130 https://www.python.org/dev/peps/pep-0215/. This is the library used by
130 https://peps.python.org/pep-0215/. This is the library used by
131 IPython for variable expansion. If you want to access a true shell
131 IPython for variable expansion. If you want to access a true shell
132 variable, an extra $ is necessary to prevent its expansion by
132 variable, an extra $ is necessary to prevent its expansion by
133 IPython::
133 IPython::
134
134
135 In [6]: alias show echo
135 In [6]: alias show echo
136 In [7]: PATH='A Python string'
136 In [7]: PATH='A Python string'
137 In [8]: show $PATH
137 In [8]: show $PATH
138 A Python string
138 A Python string
139 In [9]: show $$PATH
139 In [9]: show $$PATH
140 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
140 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
141
141
142 You can use the alias facility to access all of $PATH. See the %rehashx
142 You can use the alias facility to access all of $PATH. See the %rehashx
143 function, which automatically creates aliases for the contents of your
143 function, which automatically creates aliases for the contents of your
144 $PATH.
144 $PATH.
145
145
146 If called with no parameters, %alias prints the current alias table
146 If called with no parameters, %alias prints the current alias table
147 for your system. For posix systems, the default aliases are 'cat',
147 for your system. For posix systems, the default aliases are 'cat',
148 'cp', 'mv', 'rm', 'rmdir', and 'mkdir', and other platform-specific
148 'cp', 'mv', 'rm', 'rmdir', and 'mkdir', and other platform-specific
149 aliases are added. For windows-based systems, the default aliases are
149 aliases are added. For windows-based systems, the default aliases are
150 'copy', 'ddir', 'echo', 'ls', 'ldir', 'mkdir', 'ren', and 'rmdir'.
150 'copy', 'ddir', 'echo', 'ls', 'ldir', 'mkdir', 'ren', and 'rmdir'.
151
151
152 You can see the definition of alias by adding a question mark in the
152 You can see the definition of alias by adding a question mark in the
153 end::
153 end::
154
154
155 In [1]: cat?
155 In [1]: cat?
156 Repr: <alias cat for 'cat'>"""
156 Repr: <alias cat for 'cat'>"""
157
157
158 par = parameter_s.strip()
158 par = parameter_s.strip()
159 if not par:
159 if not par:
160 aliases = sorted(self.shell.alias_manager.aliases)
160 aliases = sorted(self.shell.alias_manager.aliases)
161 # stored = self.shell.db.get('stored_aliases', {} )
161 # stored = self.shell.db.get('stored_aliases', {} )
162 # for k, v in stored:
162 # for k, v in stored:
163 # atab.append(k, v[0])
163 # atab.append(k, v[0])
164
164
165 print("Total number of aliases:", len(aliases))
165 print("Total number of aliases:", len(aliases))
166 sys.stdout.flush()
166 sys.stdout.flush()
167 return aliases
167 return aliases
168
168
169 # Now try to define a new one
169 # Now try to define a new one
170 try:
170 try:
171 alias,cmd = par.split(None, 1)
171 alias,cmd = par.split(None, 1)
172 except TypeError:
172 except TypeError:
173 print(oinspect.getdoc(self.alias))
173 print(oinspect.getdoc(self.alias))
174 return
174 return
175
175
176 try:
176 try:
177 self.shell.alias_manager.define_alias(alias, cmd)
177 self.shell.alias_manager.define_alias(alias, cmd)
178 except AliasError as e:
178 except AliasError as e:
179 print(e)
179 print(e)
180 # end magic_alias
180 # end magic_alias
181
181
182 @line_magic
182 @line_magic
183 def unalias(self, parameter_s=''):
183 def unalias(self, parameter_s=''):
184 """Remove an alias"""
184 """Remove an alias"""
185
185
186 aname = parameter_s.strip()
186 aname = parameter_s.strip()
187 try:
187 try:
188 self.shell.alias_manager.undefine_alias(aname)
188 self.shell.alias_manager.undefine_alias(aname)
189 except ValueError as e:
189 except ValueError as e:
190 print(e)
190 print(e)
191 return
191 return
192
192
193 stored = self.shell.db.get('stored_aliases', {} )
193 stored = self.shell.db.get('stored_aliases', {} )
194 if aname in stored:
194 if aname in stored:
195 print("Removing %stored alias",aname)
195 print("Removing %stored alias",aname)
196 del stored[aname]
196 del stored[aname]
197 self.shell.db['stored_aliases'] = stored
197 self.shell.db['stored_aliases'] = stored
198
198
199 @line_magic
199 @line_magic
200 def rehashx(self, parameter_s=''):
200 def rehashx(self, parameter_s=''):
201 """Update the alias table with all executable files in $PATH.
201 """Update the alias table with all executable files in $PATH.
202
202
203 rehashx explicitly checks that every entry in $PATH is a file
203 rehashx explicitly checks that every entry in $PATH is a file
204 with execute access (os.X_OK).
204 with execute access (os.X_OK).
205
205
206 Under Windows, it checks executability as a match against a
206 Under Windows, it checks executability as a match against a
207 '|'-separated string of extensions, stored in the IPython config
207 '|'-separated string of extensions, stored in the IPython config
208 variable win_exec_ext. This defaults to 'exe|com|bat'.
208 variable win_exec_ext. This defaults to 'exe|com|bat'.
209
209
210 This function also resets the root module cache of module completer,
210 This function also resets the root module cache of module completer,
211 used on slow filesystems.
211 used on slow filesystems.
212 """
212 """
213 from IPython.core.alias import InvalidAliasError
213 from IPython.core.alias import InvalidAliasError
214
214
215 # for the benefit of module completer in ipy_completers.py
215 # for the benefit of module completer in ipy_completers.py
216 del self.shell.db['rootmodules_cache']
216 del self.shell.db['rootmodules_cache']
217
217
218 path = [os.path.abspath(os.path.expanduser(p)) for p in
218 path = [os.path.abspath(os.path.expanduser(p)) for p in
219 os.environ.get('PATH','').split(os.pathsep)]
219 os.environ.get('PATH','').split(os.pathsep)]
220
220
221 syscmdlist = []
221 syscmdlist = []
222 savedir = os.getcwd()
222 savedir = os.getcwd()
223
223
224 # Now walk the paths looking for executables to alias.
224 # Now walk the paths looking for executables to alias.
225 try:
225 try:
226 # write the whole loop for posix/Windows so we don't have an if in
226 # write the whole loop for posix/Windows so we don't have an if in
227 # the innermost part
227 # the innermost part
228 if self.is_posix:
228 if self.is_posix:
229 for pdir in path:
229 for pdir in path:
230 try:
230 try:
231 os.chdir(pdir)
231 os.chdir(pdir)
232 except OSError:
232 except OSError:
233 continue
233 continue
234
234
235 # for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist:
235 # for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist:
236 dirlist = os.scandir(path=pdir)
236 dirlist = os.scandir(path=pdir)
237 for ff in dirlist:
237 for ff in dirlist:
238 if self.isexec(ff):
238 if self.isexec(ff):
239 fname = ff.name
239 fname = ff.name
240 try:
240 try:
241 # Removes dots from the name since ipython
241 # Removes dots from the name since ipython
242 # will assume names with dots to be python.
242 # will assume names with dots to be python.
243 if not self.shell.alias_manager.is_alias(fname):
243 if not self.shell.alias_manager.is_alias(fname):
244 self.shell.alias_manager.define_alias(
244 self.shell.alias_manager.define_alias(
245 fname.replace('.',''), fname)
245 fname.replace('.',''), fname)
246 except InvalidAliasError:
246 except InvalidAliasError:
247 pass
247 pass
248 else:
248 else:
249 syscmdlist.append(fname)
249 syscmdlist.append(fname)
250 else:
250 else:
251 no_alias = Alias.blacklist
251 no_alias = Alias.blacklist
252 for pdir in path:
252 for pdir in path:
253 try:
253 try:
254 os.chdir(pdir)
254 os.chdir(pdir)
255 except OSError:
255 except OSError:
256 continue
256 continue
257
257
258 # for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist:
258 # for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist:
259 dirlist = os.scandir(pdir)
259 dirlist = os.scandir(pdir)
260 for ff in dirlist:
260 for ff in dirlist:
261 fname = ff.name
261 fname = ff.name
262 base, ext = os.path.splitext(fname)
262 base, ext = os.path.splitext(fname)
263 if self.isexec(ff) and base.lower() not in no_alias:
263 if self.isexec(ff) and base.lower() not in no_alias:
264 if ext.lower() == '.exe':
264 if ext.lower() == '.exe':
265 fname = base
265 fname = base
266 try:
266 try:
267 # Removes dots from the name since ipython
267 # Removes dots from the name since ipython
268 # will assume names with dots to be python.
268 # will assume names with dots to be python.
269 self.shell.alias_manager.define_alias(
269 self.shell.alias_manager.define_alias(
270 base.lower().replace('.',''), fname)
270 base.lower().replace('.',''), fname)
271 except InvalidAliasError:
271 except InvalidAliasError:
272 pass
272 pass
273 syscmdlist.append(fname)
273 syscmdlist.append(fname)
274
274
275 self.shell.db['syscmdlist'] = syscmdlist
275 self.shell.db['syscmdlist'] = syscmdlist
276 finally:
276 finally:
277 os.chdir(savedir)
277 os.chdir(savedir)
278
278
279 @skip_doctest
279 @skip_doctest
280 @line_magic
280 @line_magic
281 def pwd(self, parameter_s=''):
281 def pwd(self, parameter_s=''):
282 """Return the current working directory path.
282 """Return the current working directory path.
283
283
284 Examples
284 Examples
285 --------
285 --------
286 ::
286 ::
287
287
288 In [9]: pwd
288 In [9]: pwd
289 Out[9]: '/home/tsuser/sprint/ipython'
289 Out[9]: '/home/tsuser/sprint/ipython'
290 """
290 """
291 try:
291 try:
292 return os.getcwd()
292 return os.getcwd()
293 except FileNotFoundError as e:
293 except FileNotFoundError as e:
294 raise UsageError("CWD no longer exists - please use %cd to change directory.") from e
294 raise UsageError("CWD no longer exists - please use %cd to change directory.") from e
295
295
296 @skip_doctest
296 @skip_doctest
297 @line_magic
297 @line_magic
298 def cd(self, parameter_s=''):
298 def cd(self, parameter_s=''):
299 """Change the current working directory.
299 """Change the current working directory.
300
300
301 This command automatically maintains an internal list of directories
301 This command automatically maintains an internal list of directories
302 you visit during your IPython session, in the variable ``_dh``. The
302 you visit during your IPython session, in the variable ``_dh``. The
303 command :magic:`%dhist` shows this history nicely formatted. You can
303 command :magic:`%dhist` shows this history nicely formatted. You can
304 also do ``cd -<tab>`` to see directory history conveniently.
304 also do ``cd -<tab>`` to see directory history conveniently.
305 Usage:
305 Usage:
306
306
307 - ``cd 'dir'``: changes to directory 'dir'.
307 - ``cd 'dir'``: changes to directory 'dir'.
308 - ``cd -``: changes to the last visited directory.
308 - ``cd -``: changes to the last visited directory.
309 - ``cd -<n>``: changes to the n-th directory in the directory history.
309 - ``cd -<n>``: changes to the n-th directory in the directory history.
310 - ``cd --foo``: change to directory that matches 'foo' in history
310 - ``cd --foo``: change to directory that matches 'foo' in history
311 - ``cd -b <bookmark_name>``: jump to a bookmark set by %bookmark
311 - ``cd -b <bookmark_name>``: jump to a bookmark set by %bookmark
312 - Hitting a tab key after ``cd -b`` allows you to tab-complete
312 - Hitting a tab key after ``cd -b`` allows you to tab-complete
313 bookmark names.
313 bookmark names.
314
314
315 .. note::
315 .. note::
316 ``cd <bookmark_name>`` is enough if there is no directory
316 ``cd <bookmark_name>`` is enough if there is no directory
317 ``<bookmark_name>``, but a bookmark with the name exists.
317 ``<bookmark_name>``, but a bookmark with the name exists.
318
318
319 Options:
319 Options:
320
320
321 -q Be quiet. Do not print the working directory after the
321 -q Be quiet. Do not print the working directory after the
322 cd command is executed. By default IPython's cd
322 cd command is executed. By default IPython's cd
323 command does print this directory, since the default
323 command does print this directory, since the default
324 prompts do not display path information.
324 prompts do not display path information.
325
325
326 .. note::
326 .. note::
327 Note that ``!cd`` doesn't work for this purpose because the shell
327 Note that ``!cd`` doesn't work for this purpose because the shell
328 where ``!command`` runs is immediately discarded after executing
328 where ``!command`` runs is immediately discarded after executing
329 'command'.
329 'command'.
330
330
331 Examples
331 Examples
332 --------
332 --------
333 ::
333 ::
334
334
335 In [10]: cd parent/child
335 In [10]: cd parent/child
336 /home/tsuser/parent/child
336 /home/tsuser/parent/child
337 """
337 """
338
338
339 try:
339 try:
340 oldcwd = os.getcwd()
340 oldcwd = os.getcwd()
341 except FileNotFoundError:
341 except FileNotFoundError:
342 # Happens if the CWD has been deleted.
342 # Happens if the CWD has been deleted.
343 oldcwd = None
343 oldcwd = None
344
344
345 numcd = re.match(r'(-)(\d+)$',parameter_s)
345 numcd = re.match(r'(-)(\d+)$',parameter_s)
346 # jump in directory history by number
346 # jump in directory history by number
347 if numcd:
347 if numcd:
348 nn = int(numcd.group(2))
348 nn = int(numcd.group(2))
349 try:
349 try:
350 ps = self.shell.user_ns['_dh'][nn]
350 ps = self.shell.user_ns['_dh'][nn]
351 except IndexError:
351 except IndexError:
352 print('The requested directory does not exist in history.')
352 print('The requested directory does not exist in history.')
353 return
353 return
354 else:
354 else:
355 opts = {}
355 opts = {}
356 elif parameter_s.startswith('--'):
356 elif parameter_s.startswith('--'):
357 ps = None
357 ps = None
358 fallback = None
358 fallback = None
359 pat = parameter_s[2:]
359 pat = parameter_s[2:]
360 dh = self.shell.user_ns['_dh']
360 dh = self.shell.user_ns['_dh']
361 # first search only by basename (last component)
361 # first search only by basename (last component)
362 for ent in reversed(dh):
362 for ent in reversed(dh):
363 if pat in os.path.basename(ent) and os.path.isdir(ent):
363 if pat in os.path.basename(ent) and os.path.isdir(ent):
364 ps = ent
364 ps = ent
365 break
365 break
366
366
367 if fallback is None and pat in ent and os.path.isdir(ent):
367 if fallback is None and pat in ent and os.path.isdir(ent):
368 fallback = ent
368 fallback = ent
369
369
370 # if we have no last part match, pick the first full path match
370 # if we have no last part match, pick the first full path match
371 if ps is None:
371 if ps is None:
372 ps = fallback
372 ps = fallback
373
373
374 if ps is None:
374 if ps is None:
375 print("No matching entry in directory history")
375 print("No matching entry in directory history")
376 return
376 return
377 else:
377 else:
378 opts = {}
378 opts = {}
379
379
380
380
381 else:
381 else:
382 opts, ps = self.parse_options(parameter_s, 'qb', mode='string')
382 opts, ps = self.parse_options(parameter_s, 'qb', mode='string')
383 # jump to previous
383 # jump to previous
384 if ps == '-':
384 if ps == '-':
385 try:
385 try:
386 ps = self.shell.user_ns['_dh'][-2]
386 ps = self.shell.user_ns['_dh'][-2]
387 except IndexError as e:
387 except IndexError as e:
388 raise UsageError('%cd -: No previous directory to change to.') from e
388 raise UsageError('%cd -: No previous directory to change to.') from e
389 # jump to bookmark if needed
389 # jump to bookmark if needed
390 else:
390 else:
391 if not os.path.isdir(ps) or 'b' in opts:
391 if not os.path.isdir(ps) or 'b' in opts:
392 bkms = self.shell.db.get('bookmarks', {})
392 bkms = self.shell.db.get('bookmarks', {})
393
393
394 if ps in bkms:
394 if ps in bkms:
395 target = bkms[ps]
395 target = bkms[ps]
396 print('(bookmark:%s) -> %s' % (ps, target))
396 print('(bookmark:%s) -> %s' % (ps, target))
397 ps = target
397 ps = target
398 else:
398 else:
399 if 'b' in opts:
399 if 'b' in opts:
400 raise UsageError("Bookmark '%s' not found. "
400 raise UsageError("Bookmark '%s' not found. "
401 "Use '%%bookmark -l' to see your bookmarks." % ps)
401 "Use '%%bookmark -l' to see your bookmarks." % ps)
402
402
403 # at this point ps should point to the target dir
403 # at this point ps should point to the target dir
404 if ps:
404 if ps:
405 try:
405 try:
406 os.chdir(os.path.expanduser(ps))
406 os.chdir(os.path.expanduser(ps))
407 if hasattr(self.shell, 'term_title') and self.shell.term_title:
407 if hasattr(self.shell, 'term_title') and self.shell.term_title:
408 set_term_title(self.shell.term_title_format.format(cwd=abbrev_cwd()))
408 set_term_title(self.shell.term_title_format.format(cwd=abbrev_cwd()))
409 except OSError:
409 except OSError:
410 print(sys.exc_info()[1])
410 print(sys.exc_info()[1])
411 else:
411 else:
412 cwd = os.getcwd()
412 cwd = os.getcwd()
413 dhist = self.shell.user_ns['_dh']
413 dhist = self.shell.user_ns['_dh']
414 if oldcwd != cwd:
414 if oldcwd != cwd:
415 dhist.append(cwd)
415 dhist.append(cwd)
416 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
416 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
417
417
418 else:
418 else:
419 os.chdir(self.shell.home_dir)
419 os.chdir(self.shell.home_dir)
420 if hasattr(self.shell, 'term_title') and self.shell.term_title:
420 if hasattr(self.shell, 'term_title') and self.shell.term_title:
421 set_term_title(self.shell.term_title_format.format(cwd="~"))
421 set_term_title(self.shell.term_title_format.format(cwd="~"))
422 cwd = os.getcwd()
422 cwd = os.getcwd()
423 dhist = self.shell.user_ns['_dh']
423 dhist = self.shell.user_ns['_dh']
424
424
425 if oldcwd != cwd:
425 if oldcwd != cwd:
426 dhist.append(cwd)
426 dhist.append(cwd)
427 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
427 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
428 if not 'q' in opts and not self.cd_force_quiet and self.shell.user_ns['_dh']:
428 if not 'q' in opts and not self.cd_force_quiet and self.shell.user_ns['_dh']:
429 print(self.shell.user_ns['_dh'][-1])
429 print(self.shell.user_ns['_dh'][-1])
430
430
431 @line_magic
431 @line_magic
432 def env(self, parameter_s=''):
432 def env(self, parameter_s=''):
433 """Get, set, or list environment variables.
433 """Get, set, or list environment variables.
434
434
435 Usage:\\
435 Usage:\\
436
436
437 :``%env``: lists all environment variables/values
437 :``%env``: lists all environment variables/values
438 :``%env var``: get value for var
438 :``%env var``: get value for var
439 :``%env var val``: set value for var
439 :``%env var val``: set value for var
440 :``%env var=val``: set value for var
440 :``%env var=val``: set value for var
441 :``%env var=$val``: set value for var, using python expansion if possible
441 :``%env var=$val``: set value for var, using python expansion if possible
442 """
442 """
443 if parameter_s.strip():
443 if parameter_s.strip():
444 split = '=' if '=' in parameter_s else ' '
444 split = '=' if '=' in parameter_s else ' '
445 bits = parameter_s.split(split)
445 bits = parameter_s.split(split)
446 if len(bits) == 1:
446 if len(bits) == 1:
447 key = parameter_s.strip()
447 key = parameter_s.strip()
448 if key in os.environ:
448 if key in os.environ:
449 return os.environ[key]
449 return os.environ[key]
450 else:
450 else:
451 err = "Environment does not have key: {0}".format(key)
451 err = "Environment does not have key: {0}".format(key)
452 raise UsageError(err)
452 raise UsageError(err)
453 if len(bits) > 1:
453 if len(bits) > 1:
454 return self.set_env(parameter_s)
454 return self.set_env(parameter_s)
455 env = dict(os.environ)
455 env = dict(os.environ)
456 # hide likely secrets when printing the whole environment
456 # hide likely secrets when printing the whole environment
457 for key in list(env):
457 for key in list(env):
458 if any(s in key.lower() for s in ('key', 'token', 'secret')):
458 if any(s in key.lower() for s in ('key', 'token', 'secret')):
459 env[key] = '<hidden>'
459 env[key] = '<hidden>'
460
460
461 return env
461 return env
462
462
463 @line_magic
463 @line_magic
464 def set_env(self, parameter_s):
464 def set_env(self, parameter_s):
465 """Set environment variables. Assumptions are that either "val" is a
465 """Set environment variables. Assumptions are that either "val" is a
466 name in the user namespace, or val is something that evaluates to a
466 name in the user namespace, or val is something that evaluates to a
467 string.
467 string.
468
468
469 Usage:\\
469 Usage:\\
470 %set_env var val: set value for var
470 %set_env var val: set value for var
471 %set_env var=val: set value for var
471 %set_env var=val: set value for var
472 %set_env var=$val: set value for var, using python expansion if possible
472 %set_env var=$val: set value for var, using python expansion if possible
473 """
473 """
474 split = '=' if '=' in parameter_s else ' '
474 split = '=' if '=' in parameter_s else ' '
475 bits = parameter_s.split(split, 1)
475 bits = parameter_s.split(split, 1)
476 if not parameter_s.strip() or len(bits)<2:
476 if not parameter_s.strip() or len(bits)<2:
477 raise UsageError("usage is 'set_env var=val'")
477 raise UsageError("usage is 'set_env var=val'")
478 var = bits[0].strip()
478 var = bits[0].strip()
479 val = bits[1].strip()
479 val = bits[1].strip()
480 if re.match(r'.*\s.*', var):
480 if re.match(r'.*\s.*', var):
481 # an environment variable with whitespace is almost certainly
481 # an environment variable with whitespace is almost certainly
482 # not what the user intended. what's more likely is the wrong
482 # not what the user intended. what's more likely is the wrong
483 # split was chosen, ie for "set_env cmd_args A=B", we chose
483 # split was chosen, ie for "set_env cmd_args A=B", we chose
484 # '=' for the split and should have chosen ' '. to get around
484 # '=' for the split and should have chosen ' '. to get around
485 # this, users should just assign directly to os.environ or use
485 # this, users should just assign directly to os.environ or use
486 # standard magic {var} expansion.
486 # standard magic {var} expansion.
487 err = "refusing to set env var with whitespace: '{0}'"
487 err = "refusing to set env var with whitespace: '{0}'"
488 err = err.format(val)
488 err = err.format(val)
489 raise UsageError(err)
489 raise UsageError(err)
490 os.environ[var] = val
490 os.environ[var] = val
491 print('env: {0}={1}'.format(var,val))
491 print('env: {0}={1}'.format(var,val))
492
492
493 @line_magic
493 @line_magic
494 def pushd(self, parameter_s=''):
494 def pushd(self, parameter_s=''):
495 """Place the current dir on stack and change directory.
495 """Place the current dir on stack and change directory.
496
496
497 Usage:\\
497 Usage:\\
498 %pushd ['dirname']
498 %pushd ['dirname']
499 """
499 """
500
500
501 dir_s = self.shell.dir_stack
501 dir_s = self.shell.dir_stack
502 tgt = os.path.expanduser(parameter_s)
502 tgt = os.path.expanduser(parameter_s)
503 cwd = os.getcwd().replace(self.shell.home_dir,'~')
503 cwd = os.getcwd().replace(self.shell.home_dir,'~')
504 if tgt:
504 if tgt:
505 self.cd(parameter_s)
505 self.cd(parameter_s)
506 dir_s.insert(0,cwd)
506 dir_s.insert(0,cwd)
507 return self.shell.run_line_magic('dirs', '')
507 return self.shell.run_line_magic('dirs', '')
508
508
509 @line_magic
509 @line_magic
510 def popd(self, parameter_s=''):
510 def popd(self, parameter_s=''):
511 """Change to directory popped off the top of the stack.
511 """Change to directory popped off the top of the stack.
512 """
512 """
513 if not self.shell.dir_stack:
513 if not self.shell.dir_stack:
514 raise UsageError("%popd on empty stack")
514 raise UsageError("%popd on empty stack")
515 top = self.shell.dir_stack.pop(0)
515 top = self.shell.dir_stack.pop(0)
516 self.cd(top)
516 self.cd(top)
517 print("popd ->",top)
517 print("popd ->",top)
518
518
519 @line_magic
519 @line_magic
520 def dirs(self, parameter_s=''):
520 def dirs(self, parameter_s=''):
521 """Return the current directory stack."""
521 """Return the current directory stack."""
522
522
523 return self.shell.dir_stack
523 return self.shell.dir_stack
524
524
525 @line_magic
525 @line_magic
526 def dhist(self, parameter_s=''):
526 def dhist(self, parameter_s=''):
527 """Print your history of visited directories.
527 """Print your history of visited directories.
528
528
529 %dhist -> print full history\\
529 %dhist -> print full history\\
530 %dhist n -> print last n entries only\\
530 %dhist n -> print last n entries only\\
531 %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
531 %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
532
532
533 This history is automatically maintained by the %cd command, and
533 This history is automatically maintained by the %cd command, and
534 always available as the global list variable _dh. You can use %cd -<n>
534 always available as the global list variable _dh. You can use %cd -<n>
535 to go to directory number <n>.
535 to go to directory number <n>.
536
536
537 Note that most of time, you should view directory history by entering
537 Note that most of time, you should view directory history by entering
538 cd -<TAB>.
538 cd -<TAB>.
539
539
540 """
540 """
541
541
542 dh = self.shell.user_ns['_dh']
542 dh = self.shell.user_ns['_dh']
543 if parameter_s:
543 if parameter_s:
544 try:
544 try:
545 args = map(int,parameter_s.split())
545 args = map(int,parameter_s.split())
546 except:
546 except:
547 self.arg_err(self.dhist)
547 self.arg_err(self.dhist)
548 return
548 return
549 if len(args) == 1:
549 if len(args) == 1:
550 ini,fin = max(len(dh)-(args[0]),0),len(dh)
550 ini,fin = max(len(dh)-(args[0]),0),len(dh)
551 elif len(args) == 2:
551 elif len(args) == 2:
552 ini,fin = args
552 ini,fin = args
553 fin = min(fin, len(dh))
553 fin = min(fin, len(dh))
554 else:
554 else:
555 self.arg_err(self.dhist)
555 self.arg_err(self.dhist)
556 return
556 return
557 else:
557 else:
558 ini,fin = 0,len(dh)
558 ini,fin = 0,len(dh)
559 print('Directory history (kept in _dh)')
559 print('Directory history (kept in _dh)')
560 for i in range(ini, fin):
560 for i in range(ini, fin):
561 print("%d: %s" % (i, dh[i]))
561 print("%d: %s" % (i, dh[i]))
562
562
563 @skip_doctest
563 @skip_doctest
564 @line_magic
564 @line_magic
565 def sc(self, parameter_s=''):
565 def sc(self, parameter_s=''):
566 """Shell capture - run shell command and capture output (DEPRECATED use !).
566 """Shell capture - run shell command and capture output (DEPRECATED use !).
567
567
568 DEPRECATED. Suboptimal, retained for backwards compatibility.
568 DEPRECATED. Suboptimal, retained for backwards compatibility.
569
569
570 You should use the form 'var = !command' instead. Example:
570 You should use the form 'var = !command' instead. Example:
571
571
572 "%sc -l myfiles = ls ~" should now be written as
572 "%sc -l myfiles = ls ~" should now be written as
573
573
574 "myfiles = !ls ~"
574 "myfiles = !ls ~"
575
575
576 myfiles.s, myfiles.l and myfiles.n still apply as documented
576 myfiles.s, myfiles.l and myfiles.n still apply as documented
577 below.
577 below.
578
578
579 --
579 --
580 %sc [options] varname=command
580 %sc [options] varname=command
581
581
582 IPython will run the given command using commands.getoutput(), and
582 IPython will run the given command using commands.getoutput(), and
583 will then update the user's interactive namespace with a variable
583 will then update the user's interactive namespace with a variable
584 called varname, containing the value of the call. Your command can
584 called varname, containing the value of the call. Your command can
585 contain shell wildcards, pipes, etc.
585 contain shell wildcards, pipes, etc.
586
586
587 The '=' sign in the syntax is mandatory, and the variable name you
587 The '=' sign in the syntax is mandatory, and the variable name you
588 supply must follow Python's standard conventions for valid names.
588 supply must follow Python's standard conventions for valid names.
589
589
590 (A special format without variable name exists for internal use)
590 (A special format without variable name exists for internal use)
591
591
592 Options:
592 Options:
593
593
594 -l: list output. Split the output on newlines into a list before
594 -l: list output. Split the output on newlines into a list before
595 assigning it to the given variable. By default the output is stored
595 assigning it to the given variable. By default the output is stored
596 as a single string.
596 as a single string.
597
597
598 -v: verbose. Print the contents of the variable.
598 -v: verbose. Print the contents of the variable.
599
599
600 In most cases you should not need to split as a list, because the
600 In most cases you should not need to split as a list, because the
601 returned value is a special type of string which can automatically
601 returned value is a special type of string which can automatically
602 provide its contents either as a list (split on newlines) or as a
602 provide its contents either as a list (split on newlines) or as a
603 space-separated string. These are convenient, respectively, either
603 space-separated string. These are convenient, respectively, either
604 for sequential processing or to be passed to a shell command.
604 for sequential processing or to be passed to a shell command.
605
605
606 For example::
606 For example::
607
607
608 # Capture into variable a
608 # Capture into variable a
609 In [1]: sc a=ls *py
609 In [1]: sc a=ls *py
610
610
611 # a is a string with embedded newlines
611 # a is a string with embedded newlines
612 In [2]: a
612 In [2]: a
613 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
613 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
614
614
615 # which can be seen as a list:
615 # which can be seen as a list:
616 In [3]: a.l
616 In [3]: a.l
617 Out[3]: ['setup.py', 'win32_manual_post_install.py']
617 Out[3]: ['setup.py', 'win32_manual_post_install.py']
618
618
619 # or as a whitespace-separated string:
619 # or as a whitespace-separated string:
620 In [4]: a.s
620 In [4]: a.s
621 Out[4]: 'setup.py win32_manual_post_install.py'
621 Out[4]: 'setup.py win32_manual_post_install.py'
622
622
623 # a.s is useful to pass as a single command line:
623 # a.s is useful to pass as a single command line:
624 In [5]: !wc -l $a.s
624 In [5]: !wc -l $a.s
625 146 setup.py
625 146 setup.py
626 130 win32_manual_post_install.py
626 130 win32_manual_post_install.py
627 276 total
627 276 total
628
628
629 # while the list form is useful to loop over:
629 # while the list form is useful to loop over:
630 In [6]: for f in a.l:
630 In [6]: for f in a.l:
631 ...: !wc -l $f
631 ...: !wc -l $f
632 ...:
632 ...:
633 146 setup.py
633 146 setup.py
634 130 win32_manual_post_install.py
634 130 win32_manual_post_install.py
635
635
636 Similarly, the lists returned by the -l option are also special, in
636 Similarly, the lists returned by the -l option are also special, in
637 the sense that you can equally invoke the .s attribute on them to
637 the sense that you can equally invoke the .s attribute on them to
638 automatically get a whitespace-separated string from their contents::
638 automatically get a whitespace-separated string from their contents::
639
639
640 In [7]: sc -l b=ls *py
640 In [7]: sc -l b=ls *py
641
641
642 In [8]: b
642 In [8]: b
643 Out[8]: ['setup.py', 'win32_manual_post_install.py']
643 Out[8]: ['setup.py', 'win32_manual_post_install.py']
644
644
645 In [9]: b.s
645 In [9]: b.s
646 Out[9]: 'setup.py win32_manual_post_install.py'
646 Out[9]: 'setup.py win32_manual_post_install.py'
647
647
648 In summary, both the lists and strings used for output capture have
648 In summary, both the lists and strings used for output capture have
649 the following special attributes::
649 the following special attributes::
650
650
651 .l (or .list) : value as list.
651 .l (or .list) : value as list.
652 .n (or .nlstr): value as newline-separated string.
652 .n (or .nlstr): value as newline-separated string.
653 .s (or .spstr): value as space-separated string.
653 .s (or .spstr): value as space-separated string.
654 """
654 """
655
655
656 opts,args = self.parse_options(parameter_s, 'lv')
656 opts,args = self.parse_options(parameter_s, 'lv')
657 # Try to get a variable name and command to run
657 # Try to get a variable name and command to run
658 try:
658 try:
659 # the variable name must be obtained from the parse_options
659 # the variable name must be obtained from the parse_options
660 # output, which uses shlex.split to strip options out.
660 # output, which uses shlex.split to strip options out.
661 var,_ = args.split('=', 1)
661 var,_ = args.split('=', 1)
662 var = var.strip()
662 var = var.strip()
663 # But the command has to be extracted from the original input
663 # But the command has to be extracted from the original input
664 # parameter_s, not on what parse_options returns, to avoid the
664 # parameter_s, not on what parse_options returns, to avoid the
665 # quote stripping which shlex.split performs on it.
665 # quote stripping which shlex.split performs on it.
666 _,cmd = parameter_s.split('=', 1)
666 _,cmd = parameter_s.split('=', 1)
667 except ValueError:
667 except ValueError:
668 var,cmd = '',''
668 var,cmd = '',''
669 # If all looks ok, proceed
669 # If all looks ok, proceed
670 split = 'l' in opts
670 split = 'l' in opts
671 out = self.shell.getoutput(cmd, split=split)
671 out = self.shell.getoutput(cmd, split=split)
672 if 'v' in opts:
672 if 'v' in opts:
673 print('%s ==\n%s' % (var, pformat(out)))
673 print('%s ==\n%s' % (var, pformat(out)))
674 if var:
674 if var:
675 self.shell.user_ns.update({var:out})
675 self.shell.user_ns.update({var:out})
676 else:
676 else:
677 return out
677 return out
678
678
679 @line_cell_magic
679 @line_cell_magic
680 def sx(self, line='', cell=None):
680 def sx(self, line='', cell=None):
681 """Shell execute - run shell command and capture output (!! is short-hand).
681 """Shell execute - run shell command and capture output (!! is short-hand).
682
682
683 %sx command
683 %sx command
684
684
685 IPython will run the given command using commands.getoutput(), and
685 IPython will run the given command using commands.getoutput(), and
686 return the result formatted as a list (split on '\\n'). Since the
686 return the result formatted as a list (split on '\\n'). Since the
687 output is _returned_, it will be stored in ipython's regular output
687 output is _returned_, it will be stored in ipython's regular output
688 cache Out[N] and in the '_N' automatic variables.
688 cache Out[N] and in the '_N' automatic variables.
689
689
690 Notes:
690 Notes:
691
691
692 1) If an input line begins with '!!', then %sx is automatically
692 1) If an input line begins with '!!', then %sx is automatically
693 invoked. That is, while::
693 invoked. That is, while::
694
694
695 !ls
695 !ls
696
696
697 causes ipython to simply issue system('ls'), typing::
697 causes ipython to simply issue system('ls'), typing::
698
698
699 !!ls
699 !!ls
700
700
701 is a shorthand equivalent to::
701 is a shorthand equivalent to::
702
702
703 %sx ls
703 %sx ls
704
704
705 2) %sx differs from %sc in that %sx automatically splits into a list,
705 2) %sx differs from %sc in that %sx automatically splits into a list,
706 like '%sc -l'. The reason for this is to make it as easy as possible
706 like '%sc -l'. The reason for this is to make it as easy as possible
707 to process line-oriented shell output via further python commands.
707 to process line-oriented shell output via further python commands.
708 %sc is meant to provide much finer control, but requires more
708 %sc is meant to provide much finer control, but requires more
709 typing.
709 typing.
710
710
711 3) Just like %sc -l, this is a list with special attributes:
711 3) Just like %sc -l, this is a list with special attributes:
712 ::
712 ::
713
713
714 .l (or .list) : value as list.
714 .l (or .list) : value as list.
715 .n (or .nlstr): value as newline-separated string.
715 .n (or .nlstr): value as newline-separated string.
716 .s (or .spstr): value as whitespace-separated string.
716 .s (or .spstr): value as whitespace-separated string.
717
717
718 This is very useful when trying to use such lists as arguments to
718 This is very useful when trying to use such lists as arguments to
719 system commands."""
719 system commands."""
720
720
721 if cell is None:
721 if cell is None:
722 # line magic
722 # line magic
723 return self.shell.getoutput(line)
723 return self.shell.getoutput(line)
724 else:
724 else:
725 opts,args = self.parse_options(line, '', 'out=')
725 opts,args = self.parse_options(line, '', 'out=')
726 output = self.shell.getoutput(cell)
726 output = self.shell.getoutput(cell)
727 out_name = opts.get('out', opts.get('o'))
727 out_name = opts.get('out', opts.get('o'))
728 if out_name:
728 if out_name:
729 self.shell.user_ns[out_name] = output
729 self.shell.user_ns[out_name] = output
730 else:
730 else:
731 return output
731 return output
732
732
733 system = line_cell_magic('system')(sx)
733 system = line_cell_magic('system')(sx)
734 bang = cell_magic('!')(sx)
734 bang = cell_magic('!')(sx)
735
735
736 @line_magic
736 @line_magic
737 def bookmark(self, parameter_s=''):
737 def bookmark(self, parameter_s=''):
738 """Manage IPython's bookmark system.
738 """Manage IPython's bookmark system.
739
739
740 %bookmark <name> - set bookmark to current dir
740 %bookmark <name> - set bookmark to current dir
741 %bookmark <name> <dir> - set bookmark to <dir>
741 %bookmark <name> <dir> - set bookmark to <dir>
742 %bookmark -l - list all bookmarks
742 %bookmark -l - list all bookmarks
743 %bookmark -d <name> - remove bookmark
743 %bookmark -d <name> - remove bookmark
744 %bookmark -r - remove all bookmarks
744 %bookmark -r - remove all bookmarks
745
745
746 You can later on access a bookmarked folder with::
746 You can later on access a bookmarked folder with::
747
747
748 %cd -b <name>
748 %cd -b <name>
749
749
750 or simply '%cd <name>' if there is no directory called <name> AND
750 or simply '%cd <name>' if there is no directory called <name> AND
751 there is such a bookmark defined.
751 there is such a bookmark defined.
752
752
753 Your bookmarks persist through IPython sessions, but they are
753 Your bookmarks persist through IPython sessions, but they are
754 associated with each profile."""
754 associated with each profile."""
755
755
756 opts,args = self.parse_options(parameter_s,'drl',mode='list')
756 opts,args = self.parse_options(parameter_s,'drl',mode='list')
757 if len(args) > 2:
757 if len(args) > 2:
758 raise UsageError("%bookmark: too many arguments")
758 raise UsageError("%bookmark: too many arguments")
759
759
760 bkms = self.shell.db.get('bookmarks',{})
760 bkms = self.shell.db.get('bookmarks',{})
761
761
762 if 'd' in opts:
762 if 'd' in opts:
763 try:
763 try:
764 todel = args[0]
764 todel = args[0]
765 except IndexError as e:
765 except IndexError as e:
766 raise UsageError(
766 raise UsageError(
767 "%bookmark -d: must provide a bookmark to delete") from e
767 "%bookmark -d: must provide a bookmark to delete") from e
768 else:
768 else:
769 try:
769 try:
770 del bkms[todel]
770 del bkms[todel]
771 except KeyError as e:
771 except KeyError as e:
772 raise UsageError(
772 raise UsageError(
773 "%%bookmark -d: Can't delete bookmark '%s'" % todel) from e
773 "%%bookmark -d: Can't delete bookmark '%s'" % todel) from e
774
774
775 elif 'r' in opts:
775 elif 'r' in opts:
776 bkms = {}
776 bkms = {}
777 elif 'l' in opts:
777 elif 'l' in opts:
778 bks = sorted(bkms)
778 bks = sorted(bkms)
779 if bks:
779 if bks:
780 size = max(map(len, bks))
780 size = max(map(len, bks))
781 else:
781 else:
782 size = 0
782 size = 0
783 fmt = '%-'+str(size)+'s -> %s'
783 fmt = '%-'+str(size)+'s -> %s'
784 print('Current bookmarks:')
784 print('Current bookmarks:')
785 for bk in bks:
785 for bk in bks:
786 print(fmt % (bk, bkms[bk]))
786 print(fmt % (bk, bkms[bk]))
787 else:
787 else:
788 if not args:
788 if not args:
789 raise UsageError("%bookmark: You must specify the bookmark name")
789 raise UsageError("%bookmark: You must specify the bookmark name")
790 elif len(args)==1:
790 elif len(args)==1:
791 bkms[args[0]] = os.getcwd()
791 bkms[args[0]] = os.getcwd()
792 elif len(args)==2:
792 elif len(args)==2:
793 bkms[args[0]] = args[1]
793 bkms[args[0]] = args[1]
794 self.shell.db['bookmarks'] = bkms
794 self.shell.db['bookmarks'] = bkms
795
795
796 @line_magic
796 @line_magic
797 def pycat(self, parameter_s=''):
797 def pycat(self, parameter_s=''):
798 """Show a syntax-highlighted file through a pager.
798 """Show a syntax-highlighted file through a pager.
799
799
800 This magic is similar to the cat utility, but it will assume the file
800 This magic is similar to the cat utility, but it will assume the file
801 to be Python source and will show it with syntax highlighting.
801 to be Python source and will show it with syntax highlighting.
802
802
803 This magic command can either take a local filename, an url,
803 This magic command can either take a local filename, an url,
804 an history range (see %history) or a macro as argument.
804 an history range (see %history) or a macro as argument.
805
805
806 If no parameter is given, prints out history of current session up to
806 If no parameter is given, prints out history of current session up to
807 this point. ::
807 this point. ::
808
808
809 %pycat myscript.py
809 %pycat myscript.py
810 %pycat 7-27
810 %pycat 7-27
811 %pycat myMacro
811 %pycat myMacro
812 %pycat http://www.example.com/myscript.py
812 %pycat http://www.example.com/myscript.py
813 """
813 """
814 try:
814 try:
815 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
815 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
816 except (ValueError, IOError):
816 except (ValueError, IOError):
817 print("Error: no such file, variable, URL, history range or macro")
817 print("Error: no such file, variable, URL, history range or macro")
818 return
818 return
819
819
820 page.page(self.shell.pycolorize(source_to_unicode(cont)))
820 page.page(self.shell.pycolorize(source_to_unicode(cont)))
821
821
822 @magic_arguments.magic_arguments()
822 @magic_arguments.magic_arguments()
823 @magic_arguments.argument(
823 @magic_arguments.argument(
824 '-a', '--append', action='store_true', default=False,
824 '-a', '--append', action='store_true', default=False,
825 help='Append contents of the cell to an existing file. '
825 help='Append contents of the cell to an existing file. '
826 'The file will be created if it does not exist.'
826 'The file will be created if it does not exist.'
827 )
827 )
828 @magic_arguments.argument(
828 @magic_arguments.argument(
829 'filename', type=str,
829 'filename', type=str,
830 help='file to write'
830 help='file to write'
831 )
831 )
832 @cell_magic
832 @cell_magic
833 def writefile(self, line, cell):
833 def writefile(self, line, cell):
834 """Write the contents of the cell to a file.
834 """Write the contents of the cell to a file.
835
835
836 The file will be overwritten unless the -a (--append) flag is specified.
836 The file will be overwritten unless the -a (--append) flag is specified.
837 """
837 """
838 args = magic_arguments.parse_argstring(self.writefile, line)
838 args = magic_arguments.parse_argstring(self.writefile, line)
839 if re.match(r'^(\'.*\')|(".*")$', args.filename):
839 if re.match(r'^(\'.*\')|(".*")$', args.filename):
840 filename = os.path.expanduser(args.filename[1:-1])
840 filename = os.path.expanduser(args.filename[1:-1])
841 else:
841 else:
842 filename = os.path.expanduser(args.filename)
842 filename = os.path.expanduser(args.filename)
843
843
844 if os.path.exists(filename):
844 if os.path.exists(filename):
845 if args.append:
845 if args.append:
846 print("Appending to %s" % filename)
846 print("Appending to %s" % filename)
847 else:
847 else:
848 print("Overwriting %s" % filename)
848 print("Overwriting %s" % filename)
849 else:
849 else:
850 print("Writing %s" % filename)
850 print("Writing %s" % filename)
851
851
852 mode = 'a' if args.append else 'w'
852 mode = 'a' if args.append else 'w'
853 with io.open(filename, mode, encoding='utf-8') as f:
853 with io.open(filename, mode, encoding='utf-8') as f:
854 f.write(cell)
854 f.write(cell)
@@ -1,101 +1,97 b''
1 .. This (-*- rst -*-) format file contains commonly used link targets
1 .. This (-*- rst -*-) format file contains commonly used link targets
2 and name substitutions. It may be included in many files,
2 and name substitutions. It may be included in many files,
3 therefore it should only contain link targets and name
3 therefore it should only contain link targets and name
4 substitutions. Try grepping for "^\.\. _" to find plausible
4 substitutions. Try grepping for "^\.\. _" to find plausible
5 candidates for this list.
5 candidates for this list.
6
6
7 NOTE: this file must have an extension *opposite* to that of the main reST
7 NOTE: this file must have an extension *opposite* to that of the main reST
8 files in the manuals, so that we can include it with ".. include::"
8 files in the manuals, so that we can include it with ".. include::"
9 directives, but without triggering warnings from Sphinx for not being listed
9 directives, but without triggering warnings from Sphinx for not being listed
10 in any toctree. Since IPython uses .txt for the main files, this one will
10 in any toctree. Since IPython uses .txt for the main files, this one will
11 use .rst.
11 use .rst.
12
12
13 NOTE: reST targets are
13 NOTE: reST targets are
14 __not_case_sensitive__, so only one target definition is needed for
14 __not_case_sensitive__, so only one target definition is needed for
15 ipython, IPython, etc.
15 ipython, IPython, etc.
16
16
17 NOTE: Some of these were taken from the nipy links compendium.
17 NOTE: Some of these were taken from the nipy links compendium.
18
18
19 .. Main IPython links
19 .. Main IPython links
20 .. _ipython: https://ipython.org
20 .. _ipython: https://ipython.org
21 .. _`ipython manual`: https://ipython.org/documentation.html
21 .. _`ipython manual`: https://ipython.org/documentation.html
22 .. _ipython_github: http://github.com/ipython/ipython/
22 .. _ipython_github: http://github.com/ipython/ipython/
23 .. _ipython_github_repo: http://github.com/ipython/ipython/
24 .. _ipython_downloads: https://ipython.org/download.html
25 .. _ipython_pypi: http://pypi.python.org/pypi/ipython
26 .. _nbviewer: http://nbviewer.ipython.org
23 .. _nbviewer: http://nbviewer.ipython.org
27
24
28 .. _ZeroMQ: http://zeromq.org
25 .. _ZeroMQ: http://zeromq.org
29
26
30 .. Documentation tools and related links
27 .. Documentation tools and related links
31 .. _graphviz: http://www.graphviz.org
28 .. _graphviz: http://www.graphviz.org
32 .. _Sphinx: http://sphinx.pocoo.org
29 .. _Sphinx: http://sphinx.pocoo.org
33 .. _`Sphinx reST`: http://sphinx.pocoo.org/rest.html
30 .. _`Sphinx reST`: http://sphinx.pocoo.org/rest.html
34 .. _sampledoc: http://matplotlib.org/sampledoc
31 .. _sampledoc: http://matplotlib.org/sampledoc
35 .. _reST: http://docutils.sourceforge.net/rst.html
32 .. _reST: http://docutils.sourceforge.net/rst.html
36 .. _docutils: http://docutils.sourceforge.net
33 .. _docutils: http://docutils.sourceforge.net
37 .. _lyx: http://www.lyx.org
34 .. _lyx: http://www.lyx.org
38 .. _pep8: http://www.python.org/dev/peps/pep-0008
35 .. _pep8: https://peps.python.org/pep-0008/
39 .. _numpy_coding_guide: https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
40
36
41 .. Licenses
37 .. Licenses
42 .. _GPL: http://www.gnu.org/licenses/gpl.html
38 .. _GPL: http://www.gnu.org/licenses/gpl.html
43 .. _BSD: http://www.opensource.org/licenses/bsd-license.php
39 .. _BSD: http://www.opensource.org/licenses/bsd-license.php
44 .. _LGPL: http://www.gnu.org/copyleft/lesser.html
40 .. _LGPL: http://www.gnu.org/copyleft/lesser.html
45
41
46 .. Other python projects
42 .. Other python projects
47 .. _numpy: http://numpy.scipy.org
43 .. _numpy: http://numpy.scipy.org
48 .. _scipy: http://www.scipy.org
44 .. _scipy: http://www.scipy.org
49 .. _scipy_conference: http://conference.scipy.org
45 .. _scipy_conference: http://conference.scipy.org
50 .. _matplotlib: http://matplotlib.org
46 .. _matplotlib: http://matplotlib.org
51 .. _pythonxy: https://code.google.com/p/pythonxy/
47 .. _pythonxy: https://code.google.com/p/pythonxy/
52 .. _ETS: http://code.enthought.com/projects/tool-suite.php
48 .. _ETS: http://code.enthought.com/projects/tool-suite.php
53 .. _EPD: http://www.enthought.com/products/epd.php
49 .. _EPD: http://www.enthought.com/products/epd.php
54 .. _python: http://www.python.org
50 .. _python: http://www.python.org
55 .. _mayavi: http://code.enthought.com/projects/mayavi
51 .. _mayavi: http://code.enthought.com/projects/mayavi
56 .. _sympy: http://code.google.com/p/sympy
52 .. _sympy: http://code.google.com/p/sympy
57 .. _sage: http://sagemath.org
53 .. _sage: http://sagemath.org
58 .. _pydy: http://code.google.com/p/pydy
54 .. _pydy: http://code.google.com/p/pydy
59 .. _vpython: http://vpython.org
55 .. _vpython: http://vpython.org
60 .. _cython: http://cython.org
56 .. _cython: http://cython.org
61 .. _software carpentry: http://software-carpentry.org
57 .. _software carpentry: http://software-carpentry.org
62
58
63 .. Not so python scientific computing tools
59 .. Not so python scientific computing tools
64 .. _matlab: http://www.mathworks.com
60 .. _matlab: http://www.mathworks.com
65 .. _VTK: http://vtk.org
61 .. _VTK: http://vtk.org
66
62
67 .. Other organizations
63 .. Other organizations
68 .. _enthought: http://www.enthought.com
64 .. _enthought: http://www.enthought.com
69 .. _kitware: http://www.kitware.com
65 .. _kitware: http://www.kitware.com
70 .. _netlib: http://netlib.org
66 .. _netlib: http://netlib.org
71
67
72 .. Other tools and projects
68 .. Other tools and projects
73 .. _indefero: http://www.indefero.net
69 .. _indefero: http://www.indefero.net
74 .. _git: http://git-scm.com
70 .. _git: http://git-scm.com
75 .. _github: http://github.com
71 .. _github: http://github.com
76 .. _Markdown: http://daringfireball.net/projects/markdown/syntax
72 .. _Markdown: http://daringfireball.net/projects/markdown/syntax
77
73
78 .. _Running Code in the IPython Notebook: notebook_p1_
74 .. _Running Code in the IPython Notebook: notebook_p1_
79 .. _notebook_p1: http://nbviewer.ipython.org/urls/raw.github.com/ipython/ipython/1.x/examples/notebooks/Part%25201%2520-%2520Running%2520Code.ipynb
75 .. _notebook_p1: http://nbviewer.ipython.org/urls/raw.github.com/ipython/ipython/1.x/examples/notebooks/Part%25201%2520-%2520Running%2520Code.ipynb
80
76
81 .. _Basic Output: notebook_p2_
77 .. _Basic Output: notebook_p2_
82 .. _notebook_p2: http://nbviewer.ipython.org/urls/raw.github.com/ipython/ipython/1.x/examples/notebooks/Part%202%20-%20Basic%20Output.ipynb
78 .. _notebook_p2: http://nbviewer.ipython.org/urls/raw.github.com/ipython/ipython/1.x/examples/notebooks/Part%202%20-%20Basic%20Output.ipynb
83
79
84 .. _Plotting with Matplotlib: notebook_p3_
80 .. _Plotting with Matplotlib: notebook_p3_
85 .. _notebook_p3: http://nbviewer.ipython.org/urls/raw.github.com/ipython/ipython/1.x/examples/notebooks/Part%203%20-%20Plotting%20with%20Matplotlib.ipynb
81 .. _notebook_p3: http://nbviewer.ipython.org/urls/raw.github.com/ipython/ipython/1.x/examples/notebooks/Part%203%20-%20Plotting%20with%20Matplotlib.ipynb
86
82
87 .. _Markdown Cells: notebook_p4_
83 .. _Markdown Cells: notebook_p4_
88 .. _notebook_p4: http://nbviewer.ipython.org/urls/raw.github.com/ipython/ipython/1.x/examples/notebooks/Part%204%20-%20Markdown%20Cells.ipynb
84 .. _notebook_p4: http://nbviewer.ipython.org/urls/raw.github.com/ipython/ipython/1.x/examples/notebooks/Part%204%20-%20Markdown%20Cells.ipynb
89
85
90 .. _Rich Display System: notebook_p5_
86 .. _Rich Display System: notebook_p5_
91 .. _notebook_p5: http://nbviewer.ipython.org/urls/raw.github.com/ipython/ipython/1.x/examples/notebooks/Part%205%20-%20Rich%20Display%20System.ipynb
87 .. _notebook_p5: http://nbviewer.ipython.org/urls/raw.github.com/ipython/ipython/1.x/examples/notebooks/Part%205%20-%20Rich%20Display%20System.ipynb
92
88
93 .. _notebook_custom_display: http://nbviewer.ipython.org/urls/raw.github.com/ipython/ipython/1.x/examples/notebooks/Custom%20Display%20Logic.ipynb
89 .. _notebook_custom_display: http://nbviewer.ipython.org/urls/raw.github.com/ipython/ipython/1.x/examples/notebooks/Custom%20Display%20Logic.ipynb
94
90
95 .. _Frontend/Kernel Model: notebook_two_proc_
91 .. _Frontend/Kernel Model: notebook_two_proc_
96 .. _notebook_two_proc: http://nbviewer.ipython.org/urls/raw.github.com/ipython/ipython/1.x/examples/notebooks/Frontend-Kernel%20Model.ipynb
92 .. _notebook_two_proc: http://nbviewer.ipython.org/urls/raw.github.com/ipython/ipython/1.x/examples/notebooks/Frontend-Kernel%20Model.ipynb
97
93
98 .. _Cell magics: notebook_cell_magics_
94 .. _Cell magics: notebook_cell_magics_
99 .. _notebook_cell_magics: http://nbviewer.ipython.org/urls/raw.github.com/ipython/ipython/1.x/examples/notebooks/Cell%20Magics.ipynb
95 .. _notebook_cell_magics: http://nbviewer.ipython.org/urls/raw.github.com/ipython/ipython/1.x/examples/notebooks/Cell%20Magics.ipynb
100
96
101
97
@@ -1,364 +1,364 b''
1 ============
1 ============
2 6.x Series
2 6.x Series
3 ============
3 ============
4
4
5 .. _whatsnew650:
5 .. _whatsnew650:
6
6
7 IPython 6.5.0
7 IPython 6.5.0
8 =============
8 =============
9
9
10 Miscellaneous bug fixes and compatibility with Python 3.7.
10 Miscellaneous bug fixes and compatibility with Python 3.7.
11
11
12 * Autocompletion fix for modules with out ``__init__.py`` :ghpull:`11227`
12 * Autocompletion fix for modules with out ``__init__.py`` :ghpull:`11227`
13 * update the ``%pastebin`` magic to use ``dpaste.com`` instead og GitHub Gist
13 * update the ``%pastebin`` magic to use ``dpaste.com`` instead og GitHub Gist
14 which now requires authentication :ghpull:`11182`
14 which now requires authentication :ghpull:`11182`
15 * Fix crash with multiprocessing :ghpull:`11185`
15 * Fix crash with multiprocessing :ghpull:`11185`
16
16
17 .. _whatsnew640:
17 .. _whatsnew640:
18
18
19 IPython 6.4.0
19 IPython 6.4.0
20 =============
20 =============
21
21
22 Everything new in :ref:`IPython 5.7 <whatsnew570>`
22 Everything new in :ref:`IPython 5.7 <whatsnew570>`
23
23
24 * Fix display object not emitting metadata :ghpull:`11106`
24 * Fix display object not emitting metadata :ghpull:`11106`
25 * Comments failing Jedi test :ghpull:`11110`
25 * Comments failing Jedi test :ghpull:`11110`
26
26
27
27
28 .. _whatsnew631:
28 .. _whatsnew631:
29
29
30 IPython 6.3.1
30 IPython 6.3.1
31 =============
31 =============
32
32
33 This is a bugfix release to switch the default completions back to IPython's
33 This is a bugfix release to switch the default completions back to IPython's
34 own completion machinery. We discovered some problems with the completions
34 own completion machinery. We discovered some problems with the completions
35 from Jedi, including completing column names on pandas data frames.
35 from Jedi, including completing column names on pandas data frames.
36
36
37 You can switch the completions source with the config option
37 You can switch the completions source with the config option
38 :configtrait:`Completer.use_jedi`.
38 :configtrait:`Completer.use_jedi`.
39
39
40 .. _whatsnew630:
40 .. _whatsnew630:
41
41
42 IPython 6.3
42 IPython 6.3
43 ===========
43 ===========
44
44
45 IPython 6.3 contains all the bug fixes and features in
45 IPython 6.3 contains all the bug fixes and features in
46 :ref:`IPython 5.6 <whatsnew560>`. In addition:
46 :ref:`IPython 5.6 <whatsnew560>`. In addition:
47
47
48 * A new display class :class:`IPython.display.Code` can be used to display
48 * A new display class :class:`IPython.display.Code` can be used to display
49 syntax highlighted code in a notebook (:ghpull:`10978`).
49 syntax highlighted code in a notebook (:ghpull:`10978`).
50 * The :cellmagic:`html` magic now takes a ``--isolated`` option to put the
50 * The :cellmagic:`html` magic now takes a ``--isolated`` option to put the
51 content in an iframe (:ghpull:`10962`).
51 content in an iframe (:ghpull:`10962`).
52 * The code to find completions using the Jedi library has had various
52 * The code to find completions using the Jedi library has had various
53 adjustments. This is still a work in progress, but we hope this version has
53 adjustments. This is still a work in progress, but we hope this version has
54 fewer annoyances (:ghpull:`10956`, :ghpull:`10969`, :ghpull:`10999`,
54 fewer annoyances (:ghpull:`10956`, :ghpull:`10969`, :ghpull:`10999`,
55 :ghpull:`11035`, :ghpull:`11063`, :ghpull:`11065`).
55 :ghpull:`11035`, :ghpull:`11063`, :ghpull:`11065`).
56 * The *post* event callbacks are now always called, even when the execution failed
56 * The *post* event callbacks are now always called, even when the execution failed
57 (for example because of a ``SyntaxError``).
57 (for example because of a ``SyntaxError``).
58 * The execution info and result objects are now made available in the
58 * The execution info and result objects are now made available in the
59 corresponding *pre* or *post* ``*_run_cell`` :doc:`event callbacks </config/callbacks>`
59 corresponding *pre* or *post* ``*_run_cell`` :doc:`event callbacks </config/callbacks>`
60 in a backward compatible manner (:ghissue:`10774` and :ghpull:`10795`).
60 in a backward compatible manner (:ghissue:`10774` and :ghpull:`10795`).
61 * Performance with very long code cells (hundreds of lines) is greatly improved
61 * Performance with very long code cells (hundreds of lines) is greatly improved
62 (:ghpull:`10898`). Further improvements are planned for IPython 7.
62 (:ghpull:`10898`). Further improvements are planned for IPython 7.
63
63
64 You can see all `pull requests for the 6.3 milestone
64 You can see all `pull requests for the 6.3 milestone
65 <https://github.com/ipython/ipython/pulls?utf8=%E2%9C%93&q=is%3Apr+milestone%3A6.3+is%3Aclosed>`__.
65 <https://github.com/ipython/ipython/pulls?utf8=%E2%9C%93&q=is%3Apr+milestone%3A6.3+is%3Aclosed>`__.
66
66
67 .. _whatsnew620:
67 .. _whatsnew620:
68
68
69 IPython 6.2
69 IPython 6.2
70 ===========
70 ===========
71
71
72 IPython 6.2 contains all the bugs fixes and features :ref:`available in IPython 5.5 <whatsnew550>`,
72 IPython 6.2 contains all the bugs fixes and features :ref:`available in IPython 5.5 <whatsnew550>`,
73 like built in progress bar support, and system-wide configuration
73 like built in progress bar support, and system-wide configuration
74
74
75 The following features are specific to IPython 6.2:
75 The following features are specific to IPython 6.2:
76
76
77 Function signature in completions
77 Function signature in completions
78 ---------------------------------
78 ---------------------------------
79
79
80 Terminal IPython will now show the signature of the function while completing.
80 Terminal IPython will now show the signature of the function while completing.
81 Only the currently highlighted function will show its signature on the line
81 Only the currently highlighted function will show its signature on the line
82 below the completer by default. This functionality is recent, so it might be
82 below the completer by default. This functionality is recent, so it might be
83 limited; we welcome bug reports and requests for enhancements. :ghpull:`10507`
83 limited; we welcome bug reports and requests for enhancements. :ghpull:`10507`
84
84
85 Assignments return values
85 Assignments return values
86 -------------------------
86 -------------------------
87
87
88 IPython can now trigger the display hook on the last assignment of cells.
88 IPython can now trigger the display hook on the last assignment of cells.
89 Up until 6.2 the following code wouldn't show the value of the assigned
89 Up until 6.2 the following code wouldn't show the value of the assigned
90 variable::
90 variable::
91
91
92 In[1]: xyz = "something"
92 In[1]: xyz = "something"
93 # nothing shown
93 # nothing shown
94
94
95 You would have to actually make it the last statement::
95 You would have to actually make it the last statement::
96
96
97 In [2]: xyz = "something else"
97 In [2]: xyz = "something else"
98 ... : xyz
98 ... : xyz
99 Out[2]: "something else"
99 Out[2]: "something else"
100
100
101 With the option ``InteractiveShell.ast_node_interactivity='last_expr_or_assign'``
101 With the option ``InteractiveShell.ast_node_interactivity='last_expr_or_assign'``
102 you can now do::
102 you can now do::
103
103
104 In [2]: xyz = "something else"
104 In [2]: xyz = "something else"
105 Out[2]: "something else"
105 Out[2]: "something else"
106
106
107 This option can be toggled at runtime with the ``%config`` magic, and will
107 This option can be toggled at runtime with the ``%config`` magic, and will
108 trigger on assignment ``a = 1``, augmented assignment ``+=``, ``-=``, ``|=`` ...
108 trigger on assignment ``a = 1``, augmented assignment ``+=``, ``-=``, ``|=`` ...
109 as well as type annotated assignments: ``a:int = 2``.
109 as well as type annotated assignments: ``a:int = 2``.
110
110
111 See :ghpull:`10598`
111 See :ghpull:`10598`
112
112
113 Recursive Call of ipdb
113 Recursive Call of ipdb
114 ----------------------
114 ----------------------
115
115
116 Advanced users of the debugger can now correctly recursively enter ipdb. This is
116 Advanced users of the debugger can now correctly recursively enter ipdb. This is
117 thanks to ``@segevfiner`` on :ghpull:`10721`.
117 thanks to ``@segevfiner`` on :ghpull:`10721`.
118
118
119 .. _whatsnew610:
119 .. _whatsnew610:
120
120
121 IPython 6.1
121 IPython 6.1
122 ===========
122 ===========
123
123
124 - Quotes in a filename are always escaped during tab-completion on non-Windows.
124 - Quotes in a filename are always escaped during tab-completion on non-Windows.
125 :ghpull:`10069`
125 :ghpull:`10069`
126
126
127 - Variables now shadow magics in autocompletion. See :ghissue:`4877` and :ghpull:`10542`.
127 - Variables now shadow magics in autocompletion. See :ghissue:`4877` and :ghpull:`10542`.
128
128
129 - Added the ability to add parameters to alias_magic. For example::
129 - Added the ability to add parameters to alias_magic. For example::
130
130
131 In [2]: %alias_magic hist history --params "-l 2" --line
131 In [2]: %alias_magic hist history --params "-l 2" --line
132 Created `%hist` as an alias for `%history -l 2`.
132 Created `%hist` as an alias for `%history -l 2`.
133
133
134 In [3]: hist
134 In [3]: hist
135 %alias_magic hist history --params "-l 30" --line
135 %alias_magic hist history --params "-l 30" --line
136 %alias_magic hist history --params "-l 2" --line
136 %alias_magic hist history --params "-l 2" --line
137
137
138 Previously it was only possible to have an alias attached to a single function,
138 Previously it was only possible to have an alias attached to a single function,
139 and you would have to pass in the given parameters every time::
139 and you would have to pass in the given parameters every time::
140
140
141 In [4]: %alias_magic hist history --line
141 In [4]: %alias_magic hist history --line
142 Created `%hist` as an alias for `%history`.
142 Created `%hist` as an alias for `%history`.
143
143
144 In [5]: hist -l 2
144 In [5]: hist -l 2
145 hist
145 hist
146 %alias_magic hist history --line
146 %alias_magic hist history --line
147
147
148 - To suppress log state messages, you can now either use ``%logstart -q``, pass
148 - To suppress log state messages, you can now either use ``%logstart -q``, pass
149 ``--LoggingMagics.quiet=True`` on the command line, or set
149 ``--LoggingMagics.quiet=True`` on the command line, or set
150 ``c.LoggingMagics.quiet=True`` in your configuration file.
150 ``c.LoggingMagics.quiet=True`` in your configuration file.
151
151
152 - An additional flag ``--TerminalInteractiveShell.term_title_format`` is
152 - An additional flag ``--TerminalInteractiveShell.term_title_format`` is
153 introduced to allow the user to control the format of the terminal title. It
153 introduced to allow the user to control the format of the terminal title. It
154 is specified as a python format string, and currently the only variable it
154 is specified as a python format string, and currently the only variable it
155 will format is ``{cwd}``.
155 will format is ``{cwd}``.
156
156
157 - ``??``/``%pinfo2`` will now show object docstrings if the source can't be retrieved. :ghpull:`10532`
157 - ``??``/``%pinfo2`` will now show object docstrings if the source can't be retrieved. :ghpull:`10532`
158 - ``IPython.display`` has gained a ``%markdown`` cell magic. :ghpull:`10563`
158 - ``IPython.display`` has gained a ``%markdown`` cell magic. :ghpull:`10563`
159 - ``%config`` options can now be tab completed. :ghpull:`10555`
159 - ``%config`` options can now be tab completed. :ghpull:`10555`
160 - ``%config`` with no arguments are now unique and sorted. :ghpull:`10548`
160 - ``%config`` with no arguments are now unique and sorted. :ghpull:`10548`
161 - Completion on keyword arguments does not duplicate ``=`` sign if already present. :ghpull:`10547`
161 - Completion on keyword arguments does not duplicate ``=`` sign if already present. :ghpull:`10547`
162 - ``%run -m <module>`` now ``<module>`` passes extra arguments to ``<module>``. :ghpull:`10546`
162 - ``%run -m <module>`` now ``<module>`` passes extra arguments to ``<module>``. :ghpull:`10546`
163 - completer now understand "snake case auto complete": if ``foo_bar_kittens`` is
163 - completer now understand "snake case auto complete": if ``foo_bar_kittens`` is
164 a valid completion, I can type ``f_b<tab>`` will complete to it. :ghpull:`10537`
164 a valid completion, I can type ``f_b<tab>`` will complete to it. :ghpull:`10537`
165 - tracebacks are better standardized and will compress `/path/to/home` to `~`. :ghpull:`10515`
165 - tracebacks are better standardized and will compress `/path/to/home` to `~`. :ghpull:`10515`
166
166
167 The following changes were also added to IPython 5.4, see :ref:`what's new in IPython 5.4 <whatsnew540>`
167 The following changes were also added to IPython 5.4, see :ref:`what's new in IPython 5.4 <whatsnew540>`
168 for more detail description:
168 for more detail description:
169
169
170 - ``TerminalInteractiveShell`` is configurable and can be configured to
170 - ``TerminalInteractiveShell`` is configurable and can be configured to
171 (re)-use the readline interface.
171 (re)-use the readline interface.
172
172
173 - objects can now define a ``_repr_mimebundle_``
173 - objects can now define a ``_repr_mimebundle_``
174
174
175 - Execution heuristics improve for single line statements
175 - Execution heuristics improve for single line statements
176 - ``display()`` can now return a display id to update display areas.
176 - ``display()`` can now return a display id to update display areas.
177
177
178
178
179 .. _whatsnew600:
179 .. _whatsnew600:
180
180
181 IPython 6.0
181 IPython 6.0
182 ===========
182 ===========
183
183
184 Released April 19th, 2017
184 Released April 19th, 2017
185
185
186 IPython 6 features a major improvement in the completion machinery which is now
186 IPython 6 features a major improvement in the completion machinery which is now
187 capable of completing non-executed code. It is also the first version of IPython
187 capable of completing non-executed code. It is also the first version of IPython
188 to stop compatibility with Python 2, which is still supported on the bugfix only
188 to stop compatibility with Python 2, which is still supported on the bugfix only
189 5.x branch. Read below for a non-exhaustive list of new features.
189 5.x branch. Read below for a non-exhaustive list of new features.
190
190
191 Make sure you have pip > 9.0 before upgrading.
191 Make sure you have pip > 9.0 before upgrading.
192 You should be able to update by using:
192 You should be able to update by using:
193
193
194 .. code::
194 .. code::
195
195
196 pip install ipython --upgrade
196 pip install ipython --upgrade
197
197
198
198
199 .. note::
199 .. note::
200
200
201 If your pip version is greater than or equal to pip 9.0.1 you will automatically get
201 If your pip version is greater than or equal to pip 9.0.1 you will automatically get
202 the most recent version of IPython compatible with your system: on Python 2 you
202 the most recent version of IPython compatible with your system: on Python 2 you
203 will get the latest IPython 5.x bugfix, while in Python 3
203 will get the latest IPython 5.x bugfix, while in Python 3
204 you will get the latest 6.x stable version.
204 you will get the latest 6.x stable version.
205
205
206 New completion API and Interface
206 New completion API and Interface
207 --------------------------------
207 --------------------------------
208
208
209 The completer Completion API has seen an overhaul, and the new completer has
209 The completer Completion API has seen an overhaul, and the new completer has
210 plenty of improvements both from the end users of terminal IPython and for
210 plenty of improvements both from the end users of terminal IPython and for
211 consumers of the API.
211 consumers of the API.
212
212
213 This new API is capable of pulling completions from :any:`jedi`, thus allowing
213 This new API is capable of pulling completions from :any:`jedi`, thus allowing
214 type inference on non-executed code. If :any:`jedi` is installed, completions like
214 type inference on non-executed code. If :any:`jedi` is installed, completions like
215 the following are now possible without code evaluation:
215 the following are now possible without code evaluation:
216
216
217 >>> data = ['Number of users', 123_456]
217 >>> data = ['Number of users', 123_456]
218 ... data[0].<tab>
218 ... data[0].<tab>
219
219
220 That is to say, IPython is now capable of inferring that `data[0]` is a string,
220 That is to say, IPython is now capable of inferring that `data[0]` is a string,
221 and will suggest completions like `.capitalize`. The completion power of IPython
221 and will suggest completions like `.capitalize`. The completion power of IPython
222 will increase with new Jedi releases, and a number of bug-fixes and more completions
222 will increase with new Jedi releases, and a number of bug-fixes and more completions
223 are already available on the development version of :any:`jedi` if you are curious.
223 are already available on the development version of :any:`jedi` if you are curious.
224
224
225 With the help of prompt toolkit, types of completions can be shown in the
225 With the help of prompt toolkit, types of completions can be shown in the
226 completer interface:
226 completer interface:
227
227
228 .. image:: ../_images/jedi_type_inference_60.png
228 .. image:: ../_images/jedi_type_inference_60.png
229 :alt: Jedi showing ability to do type inference
229 :alt: Jedi showing ability to do type inference
230 :align: center
230 :align: center
231 :width: 400px
231 :width: 400px
232 :target: ../_images/jedi_type_inference_60.png
232 :target: ../_images/jedi_type_inference_60.png
233
233
234 The appearance of the completer is controlled by the
234 The appearance of the completer is controlled by the
235 ``c.TerminalInteractiveShell.display_completions`` option that will show the
235 ``c.TerminalInteractiveShell.display_completions`` option that will show the
236 type differently depending on the value among ``'column'``, ``'multicolumn'``
236 type differently depending on the value among ``'column'``, ``'multicolumn'``
237 and ``'readlinelike'``
237 and ``'readlinelike'``
238
238
239 The use of Jedi also fulfills a number of requests and fixes a number of bugs
239 The use of Jedi also fulfills a number of requests and fixes a number of bugs
240 like case-insensitive completion and completion after division operator: See
240 like case-insensitive completion and completion after division operator: See
241 :ghpull:`10182`.
241 :ghpull:`10182`.
242
242
243 Extra patches and updates will be needed to the :mod:`ipykernel` package for
243 Extra patches and updates will be needed to the :mod:`ipykernel` package for
244 this feature to be available to other clients like Jupyter Notebook, Lab,
244 this feature to be available to other clients like Jupyter Notebook, Lab,
245 Nteract, Hydrogen...
245 Nteract, Hydrogen...
246
246
247 The use of Jedi should be barely noticeable on recent machines, but
247 The use of Jedi should be barely noticeable on recent machines, but
248 can be slower on older ones. To tweak the performance, the amount
248 can be slower on older ones. To tweak the performance, the amount
249 of time given to Jedi to compute type inference can be adjusted with
249 of time given to Jedi to compute type inference can be adjusted with
250 ``c.IPCompleter.jedi_compute_type_timeout``. The objects whose type were not
250 ``c.IPCompleter.jedi_compute_type_timeout``. The objects whose type were not
251 inferred will be shown as ``<unknown>``. Jedi can also be completely deactivated
251 inferred will be shown as ``<unknown>``. Jedi can also be completely deactivated
252 by using the ``c.Completer.use_jedi=False`` option.
252 by using the ``c.Completer.use_jedi=False`` option.
253
253
254
254
255 The old ``Completer.complete()`` API is waiting deprecation and should be
255 The old ``Completer.complete()`` API is waiting deprecation and should be
256 replaced replaced by ``Completer.completions()`` in the near future. Feedback on
256 replaced replaced by ``Completer.completions()`` in the near future. Feedback on
257 the current state of the API and suggestions are welcome.
257 the current state of the API and suggestions are welcome.
258
258
259 Python 3 only codebase
259 Python 3 only codebase
260 ----------------------
260 ----------------------
261
261
262 One of the large challenges in IPython 6.0 has been the adoption of a pure
262 One of the large challenges in IPython 6.0 has been the adoption of a pure
263 Python 3 codebase, which has led to upstream patches in pip,
263 Python 3 codebase, which has led to upstream patches in pip,
264 pypi and warehouse to make sure Python 2 systems still upgrade to the latest
264 pypi and warehouse to make sure Python 2 systems still upgrade to the latest
265 compatible Python version.
265 compatible Python version.
266
266
267 We remind our Python 2 users that IPython 5 is still compatible with Python 2.7,
267 We remind our Python 2 users that IPython 5 is still compatible with Python 2.7,
268 still maintained and will get regular releases. Using pip 9+, upgrading IPython will
268 still maintained and will get regular releases. Using pip 9+, upgrading IPython will
269 automatically upgrade to the latest version compatible with your system.
269 automatically upgrade to the latest version compatible with your system.
270
270
271 .. warning::
271 .. warning::
272
272
273 If you are on a system using an older version of pip on Python 2, pip may
273 If you are on a system using an older version of pip on Python 2, pip may
274 still install IPython 6.0 on your system, and IPython will refuse to start.
274 still install IPython 6.0 on your system, and IPython will refuse to start.
275 You can fix this by upgrading pip, and reinstalling ipython, or forcing pip to
275 You can fix this by upgrading pip, and reinstalling ipython, or forcing pip to
276 install an earlier version: ``pip install 'ipython<6'``
276 install an earlier version: ``pip install 'ipython<6'``
277
277
278 The ability to use only Python 3 on the code base of IPython brings a number
278 The ability to use only Python 3 on the code base of IPython brings a number
279 of advantages. Most of the newly written code make use of `optional function type
279 of advantages. Most of the newly written code make use of `optional function type
280 annotation <https://www.python.org/dev/peps/pep-0484/>`_ leading to clearer code
280 annotation <https://peps.python.org/pep-0484/>`_ leading to clearer code
281 and better documentation.
281 and better documentation.
282
282
283 The total size of the repository has also decreased by about 1500 lines (for the
283 The total size of the repository has also decreased by about 1500 lines (for the
284 first time excluding the big split for 4.0). The decrease is potentially
284 first time excluding the big split for 4.0). The decrease is potentially
285 a bit more for the sour as some documents like this one are append only and
285 a bit more for the sour as some documents like this one are append only and
286 are about 300 lines long.
286 are about 300 lines long.
287
287
288 The removal of the Python2/Python3 shim layer has made the code quite a lot clearer and
288 The removal of the Python2/Python3 shim layer has made the code quite a lot clearer and
289 more idiomatic in a number of locations, and much friendlier to work with and
289 more idiomatic in a number of locations, and much friendlier to work with and
290 understand. We hope to further embrace Python 3 capabilities in the next release
290 understand. We hope to further embrace Python 3 capabilities in the next release
291 cycle and introduce more of the Python 3 only idioms (yield from, kwarg only,
291 cycle and introduce more of the Python 3 only idioms (yield from, kwarg only,
292 general unpacking) in the IPython code base, and see if we can take advantage
292 general unpacking) in the IPython code base, and see if we can take advantage
293 of these to improve user experience with better error messages and
293 of these to improve user experience with better error messages and
294 hints.
294 hints.
295
295
296
296
297 Configurable TerminalInteractiveShell, readline interface
297 Configurable TerminalInteractiveShell, readline interface
298 ---------------------------------------------------------
298 ---------------------------------------------------------
299
299
300 IPython gained a new ``c.TerminalIPythonApp.interactive_shell_class`` option
300 IPython gained a new ``c.TerminalIPythonApp.interactive_shell_class`` option
301 that allows customizing the class used to start the terminal frontend. This
301 that allows customizing the class used to start the terminal frontend. This
302 should allow a user to use custom interfaces, like reviving the former readline
302 should allow a user to use custom interfaces, like reviving the former readline
303 interface which is now a separate package not actively maintained by the core
303 interface which is now a separate package not actively maintained by the core
304 team. See the project to bring back the readline interface: `rlipython
304 team. See the project to bring back the readline interface: `rlipython
305 <https://github.com/ipython/rlipython>`_.
305 <https://github.com/ipython/rlipython>`_.
306
306
307 This change will be backported to the IPython 5.x series.
307 This change will be backported to the IPython 5.x series.
308
308
309 Misc improvements
309 Misc improvements
310 -----------------
310 -----------------
311
311
312
312
313 - The :cellmagic:`capture` magic can now capture the result of a cell (from
313 - The :cellmagic:`capture` magic can now capture the result of a cell (from
314 an expression on the last line), as well as printed and displayed output.
314 an expression on the last line), as well as printed and displayed output.
315 :ghpull:`9851`.
315 :ghpull:`9851`.
316
316
317 - Pressing Ctrl-Z in the terminal debugger now suspends IPython, as it already
317 - Pressing Ctrl-Z in the terminal debugger now suspends IPython, as it already
318 does in the main terminal prompt.
318 does in the main terminal prompt.
319
319
320 - Autoreload can now reload ``Enum``. See :ghissue:`10232` and :ghpull:`10316`
320 - Autoreload can now reload ``Enum``. See :ghissue:`10232` and :ghpull:`10316`
321
321
322 - IPython.display has gained a :any:`GeoJSON <IPython.display.GeoJSON>` object.
322 - IPython.display has gained a :any:`GeoJSON <IPython.display.GeoJSON>` object.
323 :ghpull:`10288` and :ghpull:`10253`
323 :ghpull:`10288` and :ghpull:`10253`
324
324
325 Functions Deprecated in 6.x Development cycle
325 Functions Deprecated in 6.x Development cycle
326 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
326 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
327
327
328 - Loading extensions from ``ipython_extension_dir`` prints a warning that this
328 - Loading extensions from ``ipython_extension_dir`` prints a warning that this
329 location is pending deprecation. This should only affect users still having
329 location is pending deprecation. This should only affect users still having
330 extensions installed with ``%install_ext`` which has been deprecated since
330 extensions installed with ``%install_ext`` which has been deprecated since
331 IPython 4.0, and removed in 5.0. Extensions still present in
331 IPython 4.0, and removed in 5.0. Extensions still present in
332 ``ipython_extension_dir`` may shadow more recently installed versions using
332 ``ipython_extension_dir`` may shadow more recently installed versions using
333 pip. It is thus recommended to clean ``ipython_extension_dir`` of any
333 pip. It is thus recommended to clean ``ipython_extension_dir`` of any
334 extension now available as a package.
334 extension now available as a package.
335
335
336
336
337 - ``IPython.utils.warn`` was deprecated in IPython 4.0, and has now been removed.
337 - ``IPython.utils.warn`` was deprecated in IPython 4.0, and has now been removed.
338 instead of ``IPython.utils.warn`` inbuilt :any:`warnings` module is used.
338 instead of ``IPython.utils.warn`` inbuilt :any:`warnings` module is used.
339
339
340
340
341 - The function `IPython.core.oinspect.py:call_tip` is unused, was marked as
341 - The function `IPython.core.oinspect.py:call_tip` is unused, was marked as
342 deprecated (raising a `DeprecationWarning`) and marked for later removal.
342 deprecated (raising a `DeprecationWarning`) and marked for later removal.
343 :ghpull:`10104`
343 :ghpull:`10104`
344
344
345 Backward incompatible changes
345 Backward incompatible changes
346 ------------------------------
346 ------------------------------
347
347
348 Functions Removed in 6.x Development cycle
348 Functions Removed in 6.x Development cycle
349 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
349 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
350
350
351 The following functions have been removed in the
351 The following functions have been removed in the
352 development cycle marked for Milestone 6.0.
352 development cycle marked for Milestone 6.0.
353
353
354 - ``IPython/utils/process.py`` - ``is_cmd_found``
354 - ``IPython/utils/process.py`` - ``is_cmd_found``
355 - ``IPython/utils/process.py`` - ``pycmd2argv``
355 - ``IPython/utils/process.py`` - ``pycmd2argv``
356
356
357 - The `--deep-reload` flag and the corresponding options to inject `dreload` or
357 - The `--deep-reload` flag and the corresponding options to inject `dreload` or
358 `reload` into the interactive namespace have been removed. You have to
358 `reload` into the interactive namespace have been removed. You have to
359 explicitly import `reload` from `IPython.lib.deepreload` to use it.
359 explicitly import `reload` from `IPython.lib.deepreload` to use it.
360
360
361 - The :magic:`profile` used to print the current IPython profile, and which
361 - The :magic:`profile` used to print the current IPython profile, and which
362 was deprecated in IPython 2.0 does now raise a `DeprecationWarning` error when
362 was deprecated in IPython 2.0 does now raise a `DeprecationWarning` error when
363 used. It is often confused with the :magic:`prun` and the deprecation removal
363 used. It is often confused with the :magic:`prun` and the deprecation removal
364 should free up the ``profile`` name in future versions.
364 should free up the ``profile`` name in future versions.
@@ -1,763 +1,763 b''
1 {
1 {
2 "cells": [
2 "cells": [
3 {
3 {
4 "cell_type": "markdown",
4 "cell_type": "markdown",
5 "metadata": {},
5 "metadata": {},
6 "source": [
6 "source": [
7 "# Importing IPython Notebooks as Modules"
7 "# Importing IPython Notebooks as Modules"
8 ]
8 ]
9 },
9 },
10 {
10 {
11 "cell_type": "markdown",
11 "cell_type": "markdown",
12 "metadata": {},
12 "metadata": {},
13 "source": [
13 "source": [
14 "It is a common problem that people want to import code from IPython Notebooks.\n",
14 "It is a common problem that people want to import code from IPython Notebooks.\n",
15 "This is made difficult by the fact that Notebooks are not plain Python files,\n",
15 "This is made difficult by the fact that Notebooks are not plain Python files,\n",
16 "and thus cannot be imported by the regular Python machinery.\n",
16 "and thus cannot be imported by the regular Python machinery.\n",
17 "\n",
17 "\n",
18 "Fortunately, Python provides some fairly sophisticated [hooks](http://www.python.org/dev/peps/pep-0302/) into the import machinery,\n",
18 "Fortunately, Python provides some fairly sophisticated [hooks](https://peps.python.org/pep-0302/) into the import machinery,\n",
19 "so we can actually make IPython notebooks importable without much difficulty,\n",
19 "so we can actually make IPython notebooks importable without much difficulty,\n",
20 "and only using public APIs."
20 "and only using public APIs."
21 ]
21 ]
22 },
22 },
23 {
23 {
24 "cell_type": "code",
24 "cell_type": "code",
25 "execution_count": 1,
25 "execution_count": 1,
26 "metadata": {
26 "metadata": {
27 "collapsed": false
27 "collapsed": false
28 },
28 },
29 "outputs": [],
29 "outputs": [],
30 "source": [
30 "source": [
31 "import io, os, sys, types"
31 "import io, os, sys, types"
32 ]
32 ]
33 },
33 },
34 {
34 {
35 "cell_type": "code",
35 "cell_type": "code",
36 "execution_count": 2,
36 "execution_count": 2,
37 "metadata": {
37 "metadata": {
38 "collapsed": false
38 "collapsed": false
39 },
39 },
40 "outputs": [],
40 "outputs": [],
41 "source": [
41 "source": [
42 "import nbformat\n",
42 "import nbformat\n",
43 "\n",
43 "\n",
44 "from IPython import get_ipython\n",
44 "from IPython import get_ipython\n",
45 "from IPython.core.interactiveshell import InteractiveShell"
45 "from IPython.core.interactiveshell import InteractiveShell"
46 ]
46 ]
47 },
47 },
48 {
48 {
49 "cell_type": "markdown",
49 "cell_type": "markdown",
50 "metadata": {},
50 "metadata": {},
51 "source": [
51 "source": [
52 "Import hooks typically take the form of two objects:\n",
52 "Import hooks typically take the form of two objects:\n",
53 "\n",
53 "\n",
54 "1. a Module **Loader**, which takes a module name (e.g. `'IPython.display'`), and returns a Module\n",
54 "1. a Module **Loader**, which takes a module name (e.g. `'IPython.display'`), and returns a Module\n",
55 "2. a Module **Finder**, which figures out whether a module might exist, and tells Python what **Loader** to use"
55 "2. a Module **Finder**, which figures out whether a module might exist, and tells Python what **Loader** to use"
56 ]
56 ]
57 },
57 },
58 {
58 {
59 "cell_type": "code",
59 "cell_type": "code",
60 "execution_count": 3,
60 "execution_count": 3,
61 "metadata": {
61 "metadata": {
62 "collapsed": false
62 "collapsed": false
63 },
63 },
64 "outputs": [],
64 "outputs": [],
65 "source": [
65 "source": [
66 "def find_notebook(fullname, path=None):\n",
66 "def find_notebook(fullname, path=None):\n",
67 " \"\"\"find a notebook, given its fully qualified name and an optional path\n",
67 " \"\"\"find a notebook, given its fully qualified name and an optional path\n",
68 " \n",
68 " \n",
69 " This turns \"foo.bar\" into \"foo/bar.ipynb\"\n",
69 " This turns \"foo.bar\" into \"foo/bar.ipynb\"\n",
70 " and tries turning \"Foo_Bar\" into \"Foo Bar\" if Foo_Bar\n",
70 " and tries turning \"Foo_Bar\" into \"Foo Bar\" if Foo_Bar\n",
71 " does not exist.\n",
71 " does not exist.\n",
72 " \"\"\"\n",
72 " \"\"\"\n",
73 " name = fullname.rsplit('.', 1)[-1]\n",
73 " name = fullname.rsplit('.', 1)[-1]\n",
74 " if not path:\n",
74 " if not path:\n",
75 " path = ['']\n",
75 " path = ['']\n",
76 " for d in path:\n",
76 " for d in path:\n",
77 " nb_path = os.path.join(d, name + \".ipynb\")\n",
77 " nb_path = os.path.join(d, name + \".ipynb\")\n",
78 " if os.path.isfile(nb_path):\n",
78 " if os.path.isfile(nb_path):\n",
79 " return nb_path\n",
79 " return nb_path\n",
80 " # let import Notebook_Name find \"Notebook Name.ipynb\"\n",
80 " # let import Notebook_Name find \"Notebook Name.ipynb\"\n",
81 " nb_path = nb_path.replace(\"_\", \" \")\n",
81 " nb_path = nb_path.replace(\"_\", \" \")\n",
82 " if os.path.isfile(nb_path):\n",
82 " if os.path.isfile(nb_path):\n",
83 " return nb_path\n",
83 " return nb_path\n",
84 " "
84 " "
85 ]
85 ]
86 },
86 },
87 {
87 {
88 "cell_type": "markdown",
88 "cell_type": "markdown",
89 "metadata": {},
89 "metadata": {},
90 "source": [
90 "source": [
91 "## Notebook Loader"
91 "## Notebook Loader"
92 ]
92 ]
93 },
93 },
94 {
94 {
95 "cell_type": "markdown",
95 "cell_type": "markdown",
96 "metadata": {},
96 "metadata": {},
97 "source": [
97 "source": [
98 "Here we have our Notebook Loader.\n",
98 "Here we have our Notebook Loader.\n",
99 "It's actually quite simple - once we figure out the filename of the module,\n",
99 "It's actually quite simple - once we figure out the filename of the module,\n",
100 "all it does is:\n",
100 "all it does is:\n",
101 "\n",
101 "\n",
102 "1. load the notebook document into memory\n",
102 "1. load the notebook document into memory\n",
103 "2. create an empty Module\n",
103 "2. create an empty Module\n",
104 "3. execute every cell in the Module namespace\n",
104 "3. execute every cell in the Module namespace\n",
105 "\n",
105 "\n",
106 "Since IPython cells can have extended syntax,\n",
106 "Since IPython cells can have extended syntax,\n",
107 "the IPython transform is applied to turn each of these cells into their pure-Python counterparts before executing them.\n",
107 "the IPython transform is applied to turn each of these cells into their pure-Python counterparts before executing them.\n",
108 "If all of your notebook cells are pure-Python,\n",
108 "If all of your notebook cells are pure-Python,\n",
109 "this step is unnecessary."
109 "this step is unnecessary."
110 ]
110 ]
111 },
111 },
112 {
112 {
113 "cell_type": "code",
113 "cell_type": "code",
114 "execution_count": 4,
114 "execution_count": 4,
115 "metadata": {
115 "metadata": {
116 "collapsed": false
116 "collapsed": false
117 },
117 },
118 "outputs": [],
118 "outputs": [],
119 "source": [
119 "source": [
120 "class NotebookLoader(object):\n",
120 "class NotebookLoader(object):\n",
121 " \"\"\"Module Loader for IPython Notebooks\"\"\"\n",
121 " \"\"\"Module Loader for IPython Notebooks\"\"\"\n",
122 " def __init__(self, path=None):\n",
122 " def __init__(self, path=None):\n",
123 " self.shell = InteractiveShell.instance()\n",
123 " self.shell = InteractiveShell.instance()\n",
124 " self.path = path\n",
124 " self.path = path\n",
125 " \n",
125 " \n",
126 " def load_module(self, fullname):\n",
126 " def load_module(self, fullname):\n",
127 " \"\"\"import a notebook as a module\"\"\"\n",
127 " \"\"\"import a notebook as a module\"\"\"\n",
128 " path = find_notebook(fullname, self.path)\n",
128 " path = find_notebook(fullname, self.path)\n",
129 " \n",
129 " \n",
130 " print (\"importing notebook from %s\" % path)\n",
130 " print (\"importing notebook from %s\" % path)\n",
131 " \n",
131 " \n",
132 " # load the notebook object\n",
132 " # load the notebook object\n",
133 " nb = nbformat.read(path, as_version=4)\n",
133 " nb = nbformat.read(path, as_version=4)\n",
134 " \n",
134 " \n",
135 " \n",
135 " \n",
136 " # create the module and add it to sys.modules\n",
136 " # create the module and add it to sys.modules\n",
137 " # if name in sys.modules:\n",
137 " # if name in sys.modules:\n",
138 " # return sys.modules[name]\n",
138 " # return sys.modules[name]\n",
139 " mod = types.ModuleType(fullname)\n",
139 " mod = types.ModuleType(fullname)\n",
140 " mod.__file__ = path\n",
140 " mod.__file__ = path\n",
141 " mod.__loader__ = self\n",
141 " mod.__loader__ = self\n",
142 " mod.__dict__['get_ipython'] = get_ipython\n",
142 " mod.__dict__['get_ipython'] = get_ipython\n",
143 " sys.modules[fullname] = mod\n",
143 " sys.modules[fullname] = mod\n",
144 " \n",
144 " \n",
145 " # extra work to ensure that magics that would affect the user_ns\n",
145 " # extra work to ensure that magics that would affect the user_ns\n",
146 " # actually affect the notebook module's ns\n",
146 " # actually affect the notebook module's ns\n",
147 " save_user_ns = self.shell.user_ns\n",
147 " save_user_ns = self.shell.user_ns\n",
148 " self.shell.user_ns = mod.__dict__\n",
148 " self.shell.user_ns = mod.__dict__\n",
149 " \n",
149 " \n",
150 " try:\n",
150 " try:\n",
151 " for cell in nb.cells:\n",
151 " for cell in nb.cells:\n",
152 " if cell.cell_type == 'code':\n",
152 " if cell.cell_type == 'code':\n",
153 " # transform the input to executable Python\n",
153 " # transform the input to executable Python\n",
154 " code = self.shell.input_transformer_manager.transform_cell(cell.source)\n",
154 " code = self.shell.input_transformer_manager.transform_cell(cell.source)\n",
155 " # run the code in themodule\n",
155 " # run the code in themodule\n",
156 " exec(code, mod.__dict__)\n",
156 " exec(code, mod.__dict__)\n",
157 " finally:\n",
157 " finally:\n",
158 " self.shell.user_ns = save_user_ns\n",
158 " self.shell.user_ns = save_user_ns\n",
159 " return mod\n"
159 " return mod\n"
160 ]
160 ]
161 },
161 },
162 {
162 {
163 "cell_type": "markdown",
163 "cell_type": "markdown",
164 "metadata": {},
164 "metadata": {},
165 "source": [
165 "source": [
166 "## The Module Finder"
166 "## The Module Finder"
167 ]
167 ]
168 },
168 },
169 {
169 {
170 "cell_type": "markdown",
170 "cell_type": "markdown",
171 "metadata": {},
171 "metadata": {},
172 "source": [
172 "source": [
173 "The finder is a simple object that tells you whether a name can be imported,\n",
173 "The finder is a simple object that tells you whether a name can be imported,\n",
174 "and returns the appropriate loader.\n",
174 "and returns the appropriate loader.\n",
175 "All this one does is check, when you do:\n",
175 "All this one does is check, when you do:\n",
176 "\n",
176 "\n",
177 "```python\n",
177 "```python\n",
178 "import mynotebook\n",
178 "import mynotebook\n",
179 "```\n",
179 "```\n",
180 "\n",
180 "\n",
181 "it checks whether `mynotebook.ipynb` exists.\n",
181 "it checks whether `mynotebook.ipynb` exists.\n",
182 "If a notebook is found, then it returns a NotebookLoader.\n",
182 "If a notebook is found, then it returns a NotebookLoader.\n",
183 "\n",
183 "\n",
184 "Any extra logic is just for resolving paths within packages."
184 "Any extra logic is just for resolving paths within packages."
185 ]
185 ]
186 },
186 },
187 {
187 {
188 "cell_type": "code",
188 "cell_type": "code",
189 "execution_count": 5,
189 "execution_count": 5,
190 "metadata": {
190 "metadata": {
191 "collapsed": false
191 "collapsed": false
192 },
192 },
193 "outputs": [],
193 "outputs": [],
194 "source": [
194 "source": [
195 "class NotebookFinder(object):\n",
195 "class NotebookFinder(object):\n",
196 " \"\"\"Module finder that locates IPython Notebooks\"\"\"\n",
196 " \"\"\"Module finder that locates IPython Notebooks\"\"\"\n",
197 " def __init__(self):\n",
197 " def __init__(self):\n",
198 " self.loaders = {}\n",
198 " self.loaders = {}\n",
199 " \n",
199 " \n",
200 " def find_module(self, fullname, path=None):\n",
200 " def find_module(self, fullname, path=None):\n",
201 " nb_path = find_notebook(fullname, path)\n",
201 " nb_path = find_notebook(fullname, path)\n",
202 " if not nb_path:\n",
202 " if not nb_path:\n",
203 " return\n",
203 " return\n",
204 " \n",
204 " \n",
205 " key = path\n",
205 " key = path\n",
206 " if path:\n",
206 " if path:\n",
207 " # lists aren't hashable\n",
207 " # lists aren't hashable\n",
208 " key = os.path.sep.join(path)\n",
208 " key = os.path.sep.join(path)\n",
209 " \n",
209 " \n",
210 " if key not in self.loaders:\n",
210 " if key not in self.loaders:\n",
211 " self.loaders[key] = NotebookLoader(path)\n",
211 " self.loaders[key] = NotebookLoader(path)\n",
212 " return self.loaders[key]\n"
212 " return self.loaders[key]\n"
213 ]
213 ]
214 },
214 },
215 {
215 {
216 "cell_type": "markdown",
216 "cell_type": "markdown",
217 "metadata": {},
217 "metadata": {},
218 "source": [
218 "source": [
219 "## Register the hook"
219 "## Register the hook"
220 ]
220 ]
221 },
221 },
222 {
222 {
223 "cell_type": "markdown",
223 "cell_type": "markdown",
224 "metadata": {},
224 "metadata": {},
225 "source": [
225 "source": [
226 "Now we register the `NotebookFinder` with `sys.meta_path`"
226 "Now we register the `NotebookFinder` with `sys.meta_path`"
227 ]
227 ]
228 },
228 },
229 {
229 {
230 "cell_type": "code",
230 "cell_type": "code",
231 "execution_count": 6,
231 "execution_count": 6,
232 "metadata": {
232 "metadata": {
233 "collapsed": false
233 "collapsed": false
234 },
234 },
235 "outputs": [],
235 "outputs": [],
236 "source": [
236 "source": [
237 "sys.meta_path.append(NotebookFinder())"
237 "sys.meta_path.append(NotebookFinder())"
238 ]
238 ]
239 },
239 },
240 {
240 {
241 "cell_type": "markdown",
241 "cell_type": "markdown",
242 "metadata": {},
242 "metadata": {},
243 "source": [
243 "source": [
244 "After this point, my notebooks should be importable.\n",
244 "After this point, my notebooks should be importable.\n",
245 "\n",
245 "\n",
246 "Let's look at what we have in the CWD:"
246 "Let's look at what we have in the CWD:"
247 ]
247 ]
248 },
248 },
249 {
249 {
250 "cell_type": "code",
250 "cell_type": "code",
251 "execution_count": 7,
251 "execution_count": 7,
252 "metadata": {
252 "metadata": {
253 "collapsed": false
253 "collapsed": false
254 },
254 },
255 "outputs": [
255 "outputs": [
256 {
256 {
257 "name": "stdout",
257 "name": "stdout",
258 "output_type": "stream",
258 "output_type": "stream",
259 "text": [
259 "text": [
260 "__init__.py \u001b[34m__pycache__\u001b[m\u001b[m/ mynotebook.ipynb \u001b[34mnbs\u001b[m\u001b[m/\r\n"
260 "__init__.py \u001b[34m__pycache__\u001b[m\u001b[m/ mynotebook.ipynb \u001b[34mnbs\u001b[m\u001b[m/\r\n"
261 ]
261 ]
262 }
262 }
263 ],
263 ],
264 "source": [
264 "source": [
265 "ls nbpackage"
265 "ls nbpackage"
266 ]
266 ]
267 },
267 },
268 {
268 {
269 "cell_type": "markdown",
269 "cell_type": "markdown",
270 "metadata": {},
270 "metadata": {},
271 "source": [
271 "source": [
272 "So I should be able to `import nbimp.mynotebook`.\n"
272 "So I should be able to `import nbimp.mynotebook`.\n"
273 ]
273 ]
274 },
274 },
275 {
275 {
276 "cell_type": "markdown",
276 "cell_type": "markdown",
277 "metadata": {},
277 "metadata": {},
278 "source": [
278 "source": [
279 "### Aside: displaying notebooks"
279 "### Aside: displaying notebooks"
280 ]
280 ]
281 },
281 },
282 {
282 {
283 "cell_type": "markdown",
283 "cell_type": "markdown",
284 "metadata": {},
284 "metadata": {},
285 "source": [
285 "source": [
286 "Here is some simple code to display the contents of a notebook\n",
286 "Here is some simple code to display the contents of a notebook\n",
287 "with syntax highlighting, etc."
287 "with syntax highlighting, etc."
288 ]
288 ]
289 },
289 },
290 {
290 {
291 "cell_type": "code",
291 "cell_type": "code",
292 "execution_count": 8,
292 "execution_count": 8,
293 "metadata": {
293 "metadata": {
294 "collapsed": false
294 "collapsed": false
295 },
295 },
296 "outputs": [
296 "outputs": [
297 {
297 {
298 "data": {
298 "data": {
299 "text/html": [
299 "text/html": [
300 "\n",
300 "\n",
301 "<style type='text/css'>\n",
301 "<style type='text/css'>\n",
302 ".hll { background-color: #ffffcc }\n",
302 ".hll { background-color: #ffffcc }\n",
303 ".c { color: #408080; font-style: italic } /* Comment */\n",
303 ".c { color: #408080; font-style: italic } /* Comment */\n",
304 ".err { border: 1px solid #FF0000 } /* Error */\n",
304 ".err { border: 1px solid #FF0000 } /* Error */\n",
305 ".k { color: #008000; font-weight: bold } /* Keyword */\n",
305 ".k { color: #008000; font-weight: bold } /* Keyword */\n",
306 ".o { color: #666666 } /* Operator */\n",
306 ".o { color: #666666 } /* Operator */\n",
307 ".cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
307 ".cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
308 ".cp { color: #BC7A00 } /* Comment.Preproc */\n",
308 ".cp { color: #BC7A00 } /* Comment.Preproc */\n",
309 ".c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
309 ".c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
310 ".cs { color: #408080; font-style: italic } /* Comment.Special */\n",
310 ".cs { color: #408080; font-style: italic } /* Comment.Special */\n",
311 ".gd { color: #A00000 } /* Generic.Deleted */\n",
311 ".gd { color: #A00000 } /* Generic.Deleted */\n",
312 ".ge { font-style: italic } /* Generic.Emph */\n",
312 ".ge { font-style: italic } /* Generic.Emph */\n",
313 ".gr { color: #FF0000 } /* Generic.Error */\n",
313 ".gr { color: #FF0000 } /* Generic.Error */\n",
314 ".gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
314 ".gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
315 ".gi { color: #00A000 } /* Generic.Inserted */\n",
315 ".gi { color: #00A000 } /* Generic.Inserted */\n",
316 ".go { color: #888888 } /* Generic.Output */\n",
316 ".go { color: #888888 } /* Generic.Output */\n",
317 ".gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
317 ".gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
318 ".gs { font-weight: bold } /* Generic.Strong */\n",
318 ".gs { font-weight: bold } /* Generic.Strong */\n",
319 ".gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
319 ".gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
320 ".gt { color: #0044DD } /* Generic.Traceback */\n",
320 ".gt { color: #0044DD } /* Generic.Traceback */\n",
321 ".kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
321 ".kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
322 ".kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
322 ".kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
323 ".kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
323 ".kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
324 ".kp { color: #008000 } /* Keyword.Pseudo */\n",
324 ".kp { color: #008000 } /* Keyword.Pseudo */\n",
325 ".kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
325 ".kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
326 ".kt { color: #B00040 } /* Keyword.Type */\n",
326 ".kt { color: #B00040 } /* Keyword.Type */\n",
327 ".m { color: #666666 } /* Literal.Number */\n",
327 ".m { color: #666666 } /* Literal.Number */\n",
328 ".s { color: #BA2121 } /* Literal.String */\n",
328 ".s { color: #BA2121 } /* Literal.String */\n",
329 ".na { color: #7D9029 } /* Name.Attribute */\n",
329 ".na { color: #7D9029 } /* Name.Attribute */\n",
330 ".nb { color: #008000 } /* Name.Builtin */\n",
330 ".nb { color: #008000 } /* Name.Builtin */\n",
331 ".nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
331 ".nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
332 ".no { color: #880000 } /* Name.Constant */\n",
332 ".no { color: #880000 } /* Name.Constant */\n",
333 ".nd { color: #AA22FF } /* Name.Decorator */\n",
333 ".nd { color: #AA22FF } /* Name.Decorator */\n",
334 ".ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
334 ".ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
335 ".ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
335 ".ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
336 ".nf { color: #0000FF } /* Name.Function */\n",
336 ".nf { color: #0000FF } /* Name.Function */\n",
337 ".nl { color: #A0A000 } /* Name.Label */\n",
337 ".nl { color: #A0A000 } /* Name.Label */\n",
338 ".nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
338 ".nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
339 ".nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
339 ".nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
340 ".nv { color: #19177C } /* Name.Variable */\n",
340 ".nv { color: #19177C } /* Name.Variable */\n",
341 ".ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
341 ".ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
342 ".w { color: #bbbbbb } /* Text.Whitespace */\n",
342 ".w { color: #bbbbbb } /* Text.Whitespace */\n",
343 ".mb { color: #666666 } /* Literal.Number.Bin */\n",
343 ".mb { color: #666666 } /* Literal.Number.Bin */\n",
344 ".mf { color: #666666 } /* Literal.Number.Float */\n",
344 ".mf { color: #666666 } /* Literal.Number.Float */\n",
345 ".mh { color: #666666 } /* Literal.Number.Hex */\n",
345 ".mh { color: #666666 } /* Literal.Number.Hex */\n",
346 ".mi { color: #666666 } /* Literal.Number.Integer */\n",
346 ".mi { color: #666666 } /* Literal.Number.Integer */\n",
347 ".mo { color: #666666 } /* Literal.Number.Oct */\n",
347 ".mo { color: #666666 } /* Literal.Number.Oct */\n",
348 ".sb { color: #BA2121 } /* Literal.String.Backtick */\n",
348 ".sb { color: #BA2121 } /* Literal.String.Backtick */\n",
349 ".sc { color: #BA2121 } /* Literal.String.Char */\n",
349 ".sc { color: #BA2121 } /* Literal.String.Char */\n",
350 ".sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
350 ".sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
351 ".s2 { color: #BA2121 } /* Literal.String.Double */\n",
351 ".s2 { color: #BA2121 } /* Literal.String.Double */\n",
352 ".se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
352 ".se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
353 ".sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
353 ".sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
354 ".si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
354 ".si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
355 ".sx { color: #008000 } /* Literal.String.Other */\n",
355 ".sx { color: #008000 } /* Literal.String.Other */\n",
356 ".sr { color: #BB6688 } /* Literal.String.Regex */\n",
356 ".sr { color: #BB6688 } /* Literal.String.Regex */\n",
357 ".s1 { color: #BA2121 } /* Literal.String.Single */\n",
357 ".s1 { color: #BA2121 } /* Literal.String.Single */\n",
358 ".ss { color: #19177C } /* Literal.String.Symbol */\n",
358 ".ss { color: #19177C } /* Literal.String.Symbol */\n",
359 ".bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
359 ".bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
360 ".vc { color: #19177C } /* Name.Variable.Class */\n",
360 ".vc { color: #19177C } /* Name.Variable.Class */\n",
361 ".vg { color: #19177C } /* Name.Variable.Global */\n",
361 ".vg { color: #19177C } /* Name.Variable.Global */\n",
362 ".vi { color: #19177C } /* Name.Variable.Instance */\n",
362 ".vi { color: #19177C } /* Name.Variable.Instance */\n",
363 ".il { color: #666666 } /* Literal.Number.Integer.Long */\n",
363 ".il { color: #666666 } /* Literal.Number.Integer.Long */\n",
364 "</style>\n"
364 "</style>\n"
365 ],
365 ],
366 "text/plain": [
366 "text/plain": [
367 "<IPython.core.display.HTML object>"
367 "<IPython.core.display.HTML object>"
368 ]
368 ]
369 },
369 },
370 "metadata": {},
370 "metadata": {},
371 "output_type": "display_data"
371 "output_type": "display_data"
372 }
372 }
373 ],
373 ],
374 "source": [
374 "source": [
375 "from pygments import highlight\n",
375 "from pygments import highlight\n",
376 "from pygments.lexers import PythonLexer\n",
376 "from pygments.lexers import PythonLexer\n",
377 "from pygments.formatters import HtmlFormatter\n",
377 "from pygments.formatters import HtmlFormatter\n",
378 "\n",
378 "\n",
379 "from IPython.display import display, HTML\n",
379 "from IPython.display import display, HTML\n",
380 "\n",
380 "\n",
381 "formatter = HtmlFormatter()\n",
381 "formatter = HtmlFormatter()\n",
382 "lexer = PythonLexer()\n",
382 "lexer = PythonLexer()\n",
383 "\n",
383 "\n",
384 "# publish the CSS for pygments highlighting\n",
384 "# publish the CSS for pygments highlighting\n",
385 "display(HTML(\"\"\"\n",
385 "display(HTML(\"\"\"\n",
386 "<style type='text/css'>\n",
386 "<style type='text/css'>\n",
387 "%s\n",
387 "%s\n",
388 "</style>\n",
388 "</style>\n",
389 "\"\"\" % formatter.get_style_defs()\n",
389 "\"\"\" % formatter.get_style_defs()\n",
390 "))"
390 "))"
391 ]
391 ]
392 },
392 },
393 {
393 {
394 "cell_type": "code",
394 "cell_type": "code",
395 "execution_count": 9,
395 "execution_count": 9,
396 "metadata": {
396 "metadata": {
397 "collapsed": false
397 "collapsed": false
398 },
398 },
399 "outputs": [
399 "outputs": [
400 {
400 {
401 "data": {
401 "data": {
402 "text/html": [
402 "text/html": [
403 "<h4>markdown cell</h4>\n",
403 "<h4>markdown cell</h4>\n",
404 "<pre># My Notebook</pre>\n",
404 "<pre># My Notebook</pre>\n",
405 "<h4>code cell</h4>\n",
405 "<h4>code cell</h4>\n",
406 "<div class=\"highlight\"><pre><span class=\"k\">def</span> <span class=\"nf\">foo</span><span class=\"p\">():</span>\n",
406 "<div class=\"highlight\"><pre><span class=\"k\">def</span> <span class=\"nf\">foo</span><span class=\"p\">():</span>\n",
407 " <span class=\"k\">return</span> <span class=\"s\">&quot;foo&quot;</span>\n",
407 " <span class=\"k\">return</span> <span class=\"s\">&quot;foo&quot;</span>\n",
408 "</pre></div>\n",
408 "</pre></div>\n",
409 "\n",
409 "\n",
410 "<h4>code cell</h4>\n",
410 "<h4>code cell</h4>\n",
411 "<div class=\"highlight\"><pre><span class=\"k\">def</span> <span class=\"nf\">has_ip_syntax</span><span class=\"p\">():</span>\n",
411 "<div class=\"highlight\"><pre><span class=\"k\">def</span> <span class=\"nf\">has_ip_syntax</span><span class=\"p\">():</span>\n",
412 " <span class=\"n\">listing</span> <span class=\"o\">=</span> <span class=\"err\">!</span><span class=\"n\">ls</span>\n",
412 " <span class=\"n\">listing</span> <span class=\"o\">=</span> <span class=\"err\">!</span><span class=\"n\">ls</span>\n",
413 " <span class=\"k\">return</span> <span class=\"n\">listing</span>\n",
413 " <span class=\"k\">return</span> <span class=\"n\">listing</span>\n",
414 "</pre></div>\n",
414 "</pre></div>\n",
415 "\n",
415 "\n",
416 "<h4>code cell</h4>\n",
416 "<h4>code cell</h4>\n",
417 "<div class=\"highlight\"><pre><span class=\"k\">def</span> <span class=\"nf\">whatsmyname</span><span class=\"p\">():</span>\n",
417 "<div class=\"highlight\"><pre><span class=\"k\">def</span> <span class=\"nf\">whatsmyname</span><span class=\"p\">():</span>\n",
418 " <span class=\"k\">return</span> <span class=\"n\">__name__</span>\n",
418 " <span class=\"k\">return</span> <span class=\"n\">__name__</span>\n",
419 "</pre></div>\n"
419 "</pre></div>\n"
420 ],
420 ],
421 "text/plain": [
421 "text/plain": [
422 "<IPython.core.display.HTML object>"
422 "<IPython.core.display.HTML object>"
423 ]
423 ]
424 },
424 },
425 "metadata": {},
425 "metadata": {},
426 "output_type": "display_data"
426 "output_type": "display_data"
427 }
427 }
428 ],
428 ],
429 "source": [
429 "source": [
430 "def show_notebook(fname):\n",
430 "def show_notebook(fname):\n",
431 " \"\"\"display a short summary of the cells of a notebook\"\"\"\n",
431 " \"\"\"display a short summary of the cells of a notebook\"\"\"\n",
432 " nb = nbformat.read(fname, as_version=4)\n",
432 " nb = nbformat.read(fname, as_version=4)\n",
433 " html = []\n",
433 " html = []\n",
434 " for cell in nb.cells:\n",
434 " for cell in nb.cells:\n",
435 " html.append(\"<h4>%s cell</h4>\" % cell.cell_type)\n",
435 " html.append(\"<h4>%s cell</h4>\" % cell.cell_type)\n",
436 " if cell.cell_type == 'code':\n",
436 " if cell.cell_type == 'code':\n",
437 " html.append(highlight(cell.source, lexer, formatter))\n",
437 " html.append(highlight(cell.source, lexer, formatter))\n",
438 " else:\n",
438 " else:\n",
439 " html.append(\"<pre>%s</pre>\" % cell.source)\n",
439 " html.append(\"<pre>%s</pre>\" % cell.source)\n",
440 " display(HTML('\\n'.join(html)))\n",
440 " display(HTML('\\n'.join(html)))\n",
441 "\n",
441 "\n",
442 "show_notebook(os.path.join(\"nbpackage\", \"mynotebook.ipynb\"))"
442 "show_notebook(os.path.join(\"nbpackage\", \"mynotebook.ipynb\"))"
443 ]
443 ]
444 },
444 },
445 {
445 {
446 "cell_type": "markdown",
446 "cell_type": "markdown",
447 "metadata": {},
447 "metadata": {},
448 "source": [
448 "source": [
449 "So my notebook has a heading cell and some code cells,\n",
449 "So my notebook has a heading cell and some code cells,\n",
450 "one of which contains some IPython syntax.\n",
450 "one of which contains some IPython syntax.\n",
451 "\n",
451 "\n",
452 "Let's see what happens when we import it"
452 "Let's see what happens when we import it"
453 ]
453 ]
454 },
454 },
455 {
455 {
456 "cell_type": "code",
456 "cell_type": "code",
457 "execution_count": 10,
457 "execution_count": 10,
458 "metadata": {
458 "metadata": {
459 "collapsed": false
459 "collapsed": false
460 },
460 },
461 "outputs": [
461 "outputs": [
462 {
462 {
463 "name": "stdout",
463 "name": "stdout",
464 "output_type": "stream",
464 "output_type": "stream",
465 "text": [
465 "text": [
466 "importing notebook from /Users/minrk/dev/ip/mine/examples/IPython Kernel/nbpackage/mynotebook.ipynb\n"
466 "importing notebook from /Users/minrk/dev/ip/mine/examples/IPython Kernel/nbpackage/mynotebook.ipynb\n"
467 ]
467 ]
468 }
468 }
469 ],
469 ],
470 "source": [
470 "source": [
471 "from nbpackage import mynotebook"
471 "from nbpackage import mynotebook"
472 ]
472 ]
473 },
473 },
474 {
474 {
475 "cell_type": "markdown",
475 "cell_type": "markdown",
476 "metadata": {},
476 "metadata": {},
477 "source": [
477 "source": [
478 "Hooray, it imported! Does it work?"
478 "Hooray, it imported! Does it work?"
479 ]
479 ]
480 },
480 },
481 {
481 {
482 "cell_type": "code",
482 "cell_type": "code",
483 "execution_count": 11,
483 "execution_count": 11,
484 "metadata": {
484 "metadata": {
485 "collapsed": false
485 "collapsed": false
486 },
486 },
487 "outputs": [
487 "outputs": [
488 {
488 {
489 "data": {
489 "data": {
490 "text/plain": [
490 "text/plain": [
491 "'foo'"
491 "'foo'"
492 ]
492 ]
493 },
493 },
494 "execution_count": 11,
494 "execution_count": 11,
495 "metadata": {},
495 "metadata": {},
496 "output_type": "execute_result"
496 "output_type": "execute_result"
497 }
497 }
498 ],
498 ],
499 "source": [
499 "source": [
500 "mynotebook.foo()"
500 "mynotebook.foo()"
501 ]
501 ]
502 },
502 },
503 {
503 {
504 "cell_type": "markdown",
504 "cell_type": "markdown",
505 "metadata": {},
505 "metadata": {},
506 "source": [
506 "source": [
507 "Hooray again!\n",
507 "Hooray again!\n",
508 "\n",
508 "\n",
509 "Even the function that contains IPython syntax works:"
509 "Even the function that contains IPython syntax works:"
510 ]
510 ]
511 },
511 },
512 {
512 {
513 "cell_type": "code",
513 "cell_type": "code",
514 "execution_count": 12,
514 "execution_count": 12,
515 "metadata": {
515 "metadata": {
516 "collapsed": false
516 "collapsed": false
517 },
517 },
518 "outputs": [
518 "outputs": [
519 {
519 {
520 "data": {
520 "data": {
521 "text/plain": [
521 "text/plain": [
522 "['Animations Using clear_output.ipynb',\n",
522 "['Animations Using clear_output.ipynb',\n",
523 " 'Background Jobs.ipynb',\n",
523 " 'Background Jobs.ipynb',\n",
524 " 'Beyond Plain Python.ipynb',\n",
524 " 'Beyond Plain Python.ipynb',\n",
525 " 'Capturing Output.ipynb',\n",
525 " 'Capturing Output.ipynb',\n",
526 " 'Cell Magics.ipynb',\n",
526 " 'Cell Magics.ipynb',\n",
527 " 'Custom Display Logic.ipynb',\n",
527 " 'Custom Display Logic.ipynb',\n",
528 " 'Importing Notebooks.ipynb',\n",
528 " 'Importing Notebooks.ipynb',\n",
529 " 'Index.ipynb',\n",
529 " 'Index.ipynb',\n",
530 " 'Plotting in the Notebook.ipynb',\n",
530 " 'Plotting in the Notebook.ipynb',\n",
531 " 'Raw Input in the Notebook.ipynb',\n",
531 " 'Raw Input in the Notebook.ipynb',\n",
532 " 'Rich Output.ipynb',\n",
532 " 'Rich Output.ipynb',\n",
533 " 'Script Magics.ipynb',\n",
533 " 'Script Magics.ipynb',\n",
534 " 'SymPy.ipynb',\n",
534 " 'SymPy.ipynb',\n",
535 " 'Terminal Usage.ipynb',\n",
535 " 'Terminal Usage.ipynb',\n",
536 " 'Third Party Rich Output.ipynb',\n",
536 " 'Third Party Rich Output.ipynb',\n",
537 " 'Trapezoid Rule.ipynb',\n",
537 " 'Trapezoid Rule.ipynb',\n",
538 " 'Working With External Code.ipynb',\n",
538 " 'Working With External Code.ipynb',\n",
539 " '__pycache__',\n",
539 " '__pycache__',\n",
540 " 'data',\n",
540 " 'data',\n",
541 " 'example-demo.py',\n",
541 " 'example-demo.py',\n",
542 " 'gui',\n",
542 " 'gui',\n",
543 " 'ipython-completion.bash',\n",
543 " 'ipython-completion.bash',\n",
544 " 'ipython-get-history.py',\n",
544 " 'ipython-get-history.py',\n",
545 " 'ipython.desktop',\n",
545 " 'ipython.desktop',\n",
546 " 'nbpackage']"
546 " 'nbpackage']"
547 ]
547 ]
548 },
548 },
549 "execution_count": 12,
549 "execution_count": 12,
550 "metadata": {},
550 "metadata": {},
551 "output_type": "execute_result"
551 "output_type": "execute_result"
552 }
552 }
553 ],
553 ],
554 "source": [
554 "source": [
555 "mynotebook.has_ip_syntax()"
555 "mynotebook.has_ip_syntax()"
556 ]
556 ]
557 },
557 },
558 {
558 {
559 "cell_type": "markdown",
559 "cell_type": "markdown",
560 "metadata": {},
560 "metadata": {},
561 "source": [
561 "source": [
562 "## Notebooks in packages"
562 "## Notebooks in packages"
563 ]
563 ]
564 },
564 },
565 {
565 {
566 "cell_type": "markdown",
566 "cell_type": "markdown",
567 "metadata": {},
567 "metadata": {},
568 "source": [
568 "source": [
569 "We also have a notebook inside the `nb` package,\n",
569 "We also have a notebook inside the `nb` package,\n",
570 "so let's make sure that works as well."
570 "so let's make sure that works as well."
571 ]
571 ]
572 },
572 },
573 {
573 {
574 "cell_type": "code",
574 "cell_type": "code",
575 "execution_count": 13,
575 "execution_count": 13,
576 "metadata": {
576 "metadata": {
577 "collapsed": false
577 "collapsed": false
578 },
578 },
579 "outputs": [
579 "outputs": [
580 {
580 {
581 "name": "stdout",
581 "name": "stdout",
582 "output_type": "stream",
582 "output_type": "stream",
583 "text": [
583 "text": [
584 "__init__.py \u001b[34m__pycache__\u001b[m\u001b[m/ other.ipynb\r\n"
584 "__init__.py \u001b[34m__pycache__\u001b[m\u001b[m/ other.ipynb\r\n"
585 ]
585 ]
586 }
586 }
587 ],
587 ],
588 "source": [
588 "source": [
589 "ls nbpackage/nbs"
589 "ls nbpackage/nbs"
590 ]
590 ]
591 },
591 },
592 {
592 {
593 "cell_type": "markdown",
593 "cell_type": "markdown",
594 "metadata": {},
594 "metadata": {},
595 "source": [
595 "source": [
596 "Note that the `__init__.py` is necessary for `nb` to be considered a package,\n",
596 "Note that the `__init__.py` is necessary for `nb` to be considered a package,\n",
597 "just like usual."
597 "just like usual."
598 ]
598 ]
599 },
599 },
600 {
600 {
601 "cell_type": "code",
601 "cell_type": "code",
602 "execution_count": 14,
602 "execution_count": 14,
603 "metadata": {
603 "metadata": {
604 "collapsed": false
604 "collapsed": false
605 },
605 },
606 "outputs": [
606 "outputs": [
607 {
607 {
608 "data": {
608 "data": {
609 "text/html": [
609 "text/html": [
610 "<h4>markdown cell</h4>\n",
610 "<h4>markdown cell</h4>\n",
611 "<pre>This notebook just defines `bar`</pre>\n",
611 "<pre>This notebook just defines `bar`</pre>\n",
612 "<h4>code cell</h4>\n",
612 "<h4>code cell</h4>\n",
613 "<div class=\"highlight\"><pre><span class=\"k\">def</span> <span class=\"nf\">bar</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">):</span>\n",
613 "<div class=\"highlight\"><pre><span class=\"k\">def</span> <span class=\"nf\">bar</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">):</span>\n",
614 " <span class=\"k\">return</span> <span class=\"s\">&quot;bar&quot;</span> <span class=\"o\">*</span> <span class=\"n\">x</span>\n",
614 " <span class=\"k\">return</span> <span class=\"s\">&quot;bar&quot;</span> <span class=\"o\">*</span> <span class=\"n\">x</span>\n",
615 "</pre></div>\n"
615 "</pre></div>\n"
616 ],
616 ],
617 "text/plain": [
617 "text/plain": [
618 "<IPython.core.display.HTML object>"
618 "<IPython.core.display.HTML object>"
619 ]
619 ]
620 },
620 },
621 "metadata": {},
621 "metadata": {},
622 "output_type": "display_data"
622 "output_type": "display_data"
623 }
623 }
624 ],
624 ],
625 "source": [
625 "source": [
626 "show_notebook(os.path.join(\"nbpackage\", \"nbs\", \"other.ipynb\"))"
626 "show_notebook(os.path.join(\"nbpackage\", \"nbs\", \"other.ipynb\"))"
627 ]
627 ]
628 },
628 },
629 {
629 {
630 "cell_type": "code",
630 "cell_type": "code",
631 "execution_count": 15,
631 "execution_count": 15,
632 "metadata": {
632 "metadata": {
633 "collapsed": false
633 "collapsed": false
634 },
634 },
635 "outputs": [
635 "outputs": [
636 {
636 {
637 "name": "stdout",
637 "name": "stdout",
638 "output_type": "stream",
638 "output_type": "stream",
639 "text": [
639 "text": [
640 "importing notebook from /Users/minrk/dev/ip/mine/examples/IPython Kernel/nbpackage/nbs/other.ipynb\n"
640 "importing notebook from /Users/minrk/dev/ip/mine/examples/IPython Kernel/nbpackage/nbs/other.ipynb\n"
641 ]
641 ]
642 },
642 },
643 {
643 {
644 "data": {
644 "data": {
645 "text/plain": [
645 "text/plain": [
646 "'barbarbarbarbar'"
646 "'barbarbarbarbar'"
647 ]
647 ]
648 },
648 },
649 "execution_count": 15,
649 "execution_count": 15,
650 "metadata": {},
650 "metadata": {},
651 "output_type": "execute_result"
651 "output_type": "execute_result"
652 }
652 }
653 ],
653 ],
654 "source": [
654 "source": [
655 "from nbpackage.nbs import other\n",
655 "from nbpackage.nbs import other\n",
656 "other.bar(5)"
656 "other.bar(5)"
657 ]
657 ]
658 },
658 },
659 {
659 {
660 "cell_type": "markdown",
660 "cell_type": "markdown",
661 "metadata": {},
661 "metadata": {},
662 "source": [
662 "source": [
663 "So now we have importable notebooks, from both the local directory and inside packages.\n",
663 "So now we have importable notebooks, from both the local directory and inside packages.\n",
664 "\n",
664 "\n",
665 "I can even put a notebook inside IPython, to further demonstrate that this is working properly:"
665 "I can even put a notebook inside IPython, to further demonstrate that this is working properly:"
666 ]
666 ]
667 },
667 },
668 {
668 {
669 "cell_type": "code",
669 "cell_type": "code",
670 "execution_count": 16,
670 "execution_count": 16,
671 "metadata": {
671 "metadata": {
672 "collapsed": false
672 "collapsed": false
673 },
673 },
674 "outputs": [
674 "outputs": [
675 {
675 {
676 "data": {
676 "data": {
677 "text/plain": [
677 "text/plain": [
678 "'/Users/minrk/dev/ip/mine/IPython/utils/inside_ipython.ipynb'"
678 "'/Users/minrk/dev/ip/mine/IPython/utils/inside_ipython.ipynb'"
679 ]
679 ]
680 },
680 },
681 "execution_count": 16,
681 "execution_count": 16,
682 "metadata": {},
682 "metadata": {},
683 "output_type": "execute_result"
683 "output_type": "execute_result"
684 }
684 }
685 ],
685 ],
686 "source": [
686 "source": [
687 "import shutil\n",
687 "import shutil\n",
688 "from IPython.paths import get_ipython_package_dir\n",
688 "from IPython.paths import get_ipython_package_dir\n",
689 "\n",
689 "\n",
690 "utils = os.path.join(get_ipython_package_dir(), 'utils')\n",
690 "utils = os.path.join(get_ipython_package_dir(), 'utils')\n",
691 "shutil.copy(os.path.join(\"nbpackage\", \"mynotebook.ipynb\"),\n",
691 "shutil.copy(os.path.join(\"nbpackage\", \"mynotebook.ipynb\"),\n",
692 " os.path.join(utils, \"inside_ipython.ipynb\")\n",
692 " os.path.join(utils, \"inside_ipython.ipynb\")\n",
693 ")"
693 ")"
694 ]
694 ]
695 },
695 },
696 {
696 {
697 "cell_type": "markdown",
697 "cell_type": "markdown",
698 "metadata": {},
698 "metadata": {},
699 "source": [
699 "source": [
700 "and import the notebook from `IPython.utils`"
700 "and import the notebook from `IPython.utils`"
701 ]
701 ]
702 },
702 },
703 {
703 {
704 "cell_type": "code",
704 "cell_type": "code",
705 "execution_count": 17,
705 "execution_count": 17,
706 "metadata": {
706 "metadata": {
707 "collapsed": false
707 "collapsed": false
708 },
708 },
709 "outputs": [
709 "outputs": [
710 {
710 {
711 "name": "stdout",
711 "name": "stdout",
712 "output_type": "stream",
712 "output_type": "stream",
713 "text": [
713 "text": [
714 "importing notebook from /Users/minrk/dev/ip/mine/IPython/utils/inside_ipython.ipynb\n"
714 "importing notebook from /Users/minrk/dev/ip/mine/IPython/utils/inside_ipython.ipynb\n"
715 ]
715 ]
716 },
716 },
717 {
717 {
718 "data": {
718 "data": {
719 "text/plain": [
719 "text/plain": [
720 "'IPython.utils.inside_ipython'"
720 "'IPython.utils.inside_ipython'"
721 ]
721 ]
722 },
722 },
723 "execution_count": 17,
723 "execution_count": 17,
724 "metadata": {},
724 "metadata": {},
725 "output_type": "execute_result"
725 "output_type": "execute_result"
726 }
726 }
727 ],
727 ],
728 "source": [
728 "source": [
729 "from IPython.utils import inside_ipython\n",
729 "from IPython.utils import inside_ipython\n",
730 "inside_ipython.whatsmyname()"
730 "inside_ipython.whatsmyname()"
731 ]
731 ]
732 },
732 },
733 {
733 {
734 "cell_type": "markdown",
734 "cell_type": "markdown",
735 "metadata": {},
735 "metadata": {},
736 "source": [
736 "source": [
737 "This approach can even import functions and classes that are defined in a notebook using the `%%cython` magic."
737 "This approach can even import functions and classes that are defined in a notebook using the `%%cython` magic."
738 ]
738 ]
739 }
739 }
740 ],
740 ],
741 "metadata": {
741 "metadata": {
742 "gist_id": "6011986",
742 "gist_id": "6011986",
743 "kernelspec": {
743 "kernelspec": {
744 "display_name": "Python 3",
744 "display_name": "Python 3",
745 "language": "python",
745 "language": "python",
746 "name": "python3"
746 "name": "python3"
747 },
747 },
748 "language_info": {
748 "language_info": {
749 "codemirror_mode": {
749 "codemirror_mode": {
750 "name": "ipython",
750 "name": "ipython",
751 "version": 3
751 "version": 3
752 },
752 },
753 "file_extension": ".py",
753 "file_extension": ".py",
754 "mimetype": "text/x-python",
754 "mimetype": "text/x-python",
755 "name": "python",
755 "name": "python",
756 "nbconvert_exporter": "python",
756 "nbconvert_exporter": "python",
757 "pygments_lexer": "ipython3",
757 "pygments_lexer": "ipython3",
758 "version": "3.4.3"
758 "version": "3.4.3"
759 }
759 }
760 },
760 },
761 "nbformat": 4,
761 "nbformat": 4,
762 "nbformat_minor": 0
762 "nbformat_minor": 0
763 }
763 }
General Comments 0
You need to be logged in to leave comments. Login now