##// END OF EJS Templates
updating my code to incorporate upstream changes; resolved a merge conflict in IPython/lib/display.py
Greg Caporaso -
r8798:c1e52e56 merge
parent child Browse files
Show More
@@ -0,0 +1,14 b''
1 # encoding: utf-8
2 """Terminal-based IPython entry point.
3 """
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2012, IPython Development Team.
6 #
7 # Distributed under the terms of the Modified BSD License.
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
11
12 from IPython.frontend.terminal.ipapp import launch_new_instance
13
14 launch_new_instance()
@@ -0,0 +1,73 b''
1 import os.path
2
3 import nose.tools as nt
4
5 import IPython.testing.tools as tt
6 from IPython.utils.syspathcontext import prepended_to_syspath
7 from IPython.utils.tempdir import TemporaryDirectory
8
9 ext1_content = """
10 def load_ipython_extension(ip):
11 print("Running ext1 load")
12
13 def unload_ipython_extension(ip):
14 print("Running ext1 unload")
15 """
16
17 ext2_content = """
18 def load_ipython_extension(ip):
19 print("Running ext2 load")
20 """
21
22 def test_extension_loading():
23 em = get_ipython().extension_manager
24 with TemporaryDirectory() as td:
25 ext1 = os.path.join(td, 'ext1.py')
26 with open(ext1, 'w') as f:
27 f.write(ext1_content)
28
29 ext2 = os.path.join(td, 'ext2.py')
30 with open(ext2, 'w') as f:
31 f.write(ext2_content)
32
33 with prepended_to_syspath(td):
34 assert 'ext1' not in em.loaded
35 assert 'ext2' not in em.loaded
36
37 # Load extension
38 with tt.AssertPrints("Running ext1 load"):
39 assert em.load_extension('ext1') is None
40 assert 'ext1' in em.loaded
41
42 # Should refuse to load it again
43 with tt.AssertNotPrints("Running ext1 load"):
44 assert em.load_extension('ext1') == 'already loaded'
45
46 # Reload
47 with tt.AssertPrints("Running ext1 unload"):
48 with tt.AssertPrints("Running ext1 load", suppress=False):
49 em.reload_extension('ext1')
50
51 # Unload
52 with tt.AssertPrints("Running ext1 unload"):
53 assert em.unload_extension('ext1') is None
54
55 # Can't unload again
56 with tt.AssertNotPrints("Running ext1 unload"):
57 assert em.unload_extension('ext1') == 'not loaded'
58 assert em.unload_extension('ext2') == 'not loaded'
59
60 # Load extension 2
61 with tt.AssertPrints("Running ext2 load"):
62 assert em.load_extension('ext2') is None
63
64 # Can't unload this
65 assert em.unload_extension('ext2') == 'no unload function'
66
67 # But can reload it
68 with tt.AssertPrints("Running ext2 load"):
69 em.reload_extension('ext2')
70
71 def test_non_extension():
72 em = get_ipython().extension_manager
73 nt.assert_equal(em.load_extension('sys'), "no load function")
@@ -477,23 +477,51 b' class Pdb(OldPdb):'
477 477 do_l = do_list
478 478
479 479 def do_pdef(self, arg):
480 """The debugger interface to magic_pdef"""
480 """Print the call signature for any callable object.
481
482 The debugger interface to %pdef"""
481 483 namespaces = [('Locals', self.curframe.f_locals),
482 484 ('Globals', self.curframe.f_globals)]
483 485 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
484 486
485 487 def do_pdoc(self, arg):
486 """The debugger interface to magic_pdoc"""
488 """Print the docstring for an object.
489
490 The debugger interface to %pdoc."""
487 491 namespaces = [('Locals', self.curframe.f_locals),
488 492 ('Globals', self.curframe.f_globals)]
489 493 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
490 494
495 def do_pfile(self, arg):
496 """Print (or run through pager) the file where an object is defined.
497
498 The debugger interface to %pfile.
499 """
500 namespaces = [('Locals', self.curframe.f_locals),
501 ('Globals', self.curframe.f_globals)]
502 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
503
491 504 def do_pinfo(self, arg):
492 """The debugger equivalant of ?obj"""
505 """Provide detailed information about an object.
506
507 The debugger interface to %pinfo, i.e., obj?."""
508 namespaces = [('Locals', self.curframe.f_locals),
509 ('Globals', self.curframe.f_globals)]
510 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
511
512 def do_pinfo2(self, arg):
513 """Provide extra detailed information about an object.
514
515 The debugger interface to %pinfo2, i.e., obj??."""
516 namespaces = [('Locals', self.curframe.f_locals),
517 ('Globals', self.curframe.f_globals)]
518 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
519
520 def do_psource(self, arg):
521 """Print (or run through pager) the source code for an object."""
493 522 namespaces = [('Locals', self.curframe.f_locals),
494 523 ('Globals', self.curframe.f_globals)]
495 self.shell.find_line_magic('pinfo')("pinfo %s" % arg,
496 namespaces=namespaces)
524 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
497 525
498 526 def checkline(self, filename, lineno):
499 527 """Check whether specified line seems to be executable.
@@ -23,8 +23,12 b' import sys'
23 23 from urllib import urlretrieve
24 24 from urlparse import urlparse
25 25
26 from IPython.core.error import UsageError
26 27 from IPython.config.configurable import Configurable
27 28 from IPython.utils.traitlets import Instance
29 from IPython.utils.py3compat import PY3
30 if PY3:
31 from imp import reload
28 32
29 33 #-----------------------------------------------------------------------------
30 34 # Main class
@@ -44,10 +48,11 b' class ExtensionManager(Configurable):'
44 48 the only argument. You can do anything you want with IPython at
45 49 that point, including defining new magic and aliases, adding new
46 50 components, etc.
47
48 The :func:`load_ipython_extension` will be called again is you
49 load or reload the extension again. It is up to the extension
50 author to add code to manage that.
51
52 You can also optionaly define an :func:`unload_ipython_extension(ipython)`
53 function, which will be called if the user unloads or reloads the extension.
54 The extension manager will only call :func:`load_ipython_extension` again
55 if the extension is reloaded.
51 56
52 57 You can put your extension modules anywhere you want, as long as
53 58 they can be imported by Python's standard import mechanism. However,
@@ -63,6 +68,7 b' class ExtensionManager(Configurable):'
63 68 self.shell.on_trait_change(
64 69 self._on_ipython_dir_changed, 'ipython_dir'
65 70 )
71 self.loaded = set()
66 72
67 73 def __del__(self):
68 74 self.shell.on_trait_change(
@@ -80,26 +86,43 b' class ExtensionManager(Configurable):'
80 86 def load_extension(self, module_str):
81 87 """Load an IPython extension by its module name.
82 88
83 If :func:`load_ipython_extension` returns anything, this function
84 will return that object.
89 Returns the string "already loaded" if the extension is already loaded,
90 "no load function" if the module doesn't have a load_ipython_extension
91 function, or None if it succeeded.
85 92 """
93 if module_str in self.loaded:
94 return "already loaded"
95
86 96 from IPython.utils.syspathcontext import prepended_to_syspath
87 97
88 98 if module_str not in sys.modules:
89 99 with prepended_to_syspath(self.ipython_extension_dir):
90 100 __import__(module_str)
91 101 mod = sys.modules[module_str]
92 return self._call_load_ipython_extension(mod)
102 if self._call_load_ipython_extension(mod):
103 self.loaded.add(module_str)
104 else:
105 return "no load function"
93 106
94 107 def unload_extension(self, module_str):
95 108 """Unload an IPython extension by its module name.
96 109
97 110 This function looks up the extension's name in ``sys.modules`` and
98 111 simply calls ``mod.unload_ipython_extension(self)``.
112
113 Returns the string "no unload function" if the extension doesn't define
114 a function to unload itself, "not loaded" if the extension isn't loaded,
115 otherwise None.
99 116 """
117 if module_str not in self.loaded:
118 return "not loaded"
119
100 120 if module_str in sys.modules:
101 121 mod = sys.modules[module_str]
102 self._call_unload_ipython_extension(mod)
122 if self._call_unload_ipython_extension(mod):
123 self.loaded.discard(module_str)
124 else:
125 return "no unload function"
103 126
104 127 def reload_extension(self, module_str):
105 128 """Reload an IPython extension by calling reload.
@@ -111,21 +134,25 b' class ExtensionManager(Configurable):'
111 134 """
112 135 from IPython.utils.syspathcontext import prepended_to_syspath
113 136
114 with prepended_to_syspath(self.ipython_extension_dir):
115 if module_str in sys.modules:
116 mod = sys.modules[module_str]
137 if (module_str in self.loaded) and (module_str in sys.modules):
138 self.unload_extension(module_str)
139 mod = sys.modules[module_str]
140 with prepended_to_syspath(self.ipython_extension_dir):
117 141 reload(mod)
118 self._call_load_ipython_extension(mod)
119 else:
120 self.load_extension(module_str)
142 if self._call_load_ipython_extension(mod):
143 self.loaded.add(module_str)
144 else:
145 self.load_extension(module_str)
121 146
122 147 def _call_load_ipython_extension(self, mod):
123 148 if hasattr(mod, 'load_ipython_extension'):
124 return mod.load_ipython_extension(self.shell)
149 mod.load_ipython_extension(self.shell)
150 return True
125 151
126 152 def _call_unload_ipython_extension(self, mod):
127 153 if hasattr(mod, 'unload_ipython_extension'):
128 return mod.unload_ipython_extension(self.shell)
154 mod.unload_ipython_extension(self.shell)
155 return True
129 156
130 157 def install_extension(self, url, filename=None):
131 158 """Download and install an IPython extension.
@@ -629,7 +629,7 b' class InteractiveShell(SingletonConfigurable):'
629 629 # override sys.stdout and sys.stderr themselves, you need to do that
630 630 # *before* instantiating this class, because io holds onto
631 631 # references to the underlying streams.
632 if sys.platform == 'win32' and self.has_readline:
632 if (sys.platform == 'win32' or sys.platform == 'cli') and self.has_readline:
633 633 io.stdout = io.stderr = io.IOStream(self.readline._outputfile)
634 634 else:
635 635 io.stdout = io.IOStream(sys.stdout)
@@ -173,11 +173,17 b' class magic_arguments(ArgDecorator):'
173 173 return func
174 174
175 175
176 class argument(ArgDecorator):
177 """ Store arguments and keywords to pass to add_argument().
176 class ArgMethodWrapper(ArgDecorator):
177
178 """
179 Base class to define a wrapper for ArgumentParser method.
180
181 Child class must define either `_method_name` or `add_to_parser`.
178 182
179 Instances also serve to decorate command methods.
180 183 """
184
185 _method_name = None
186
181 187 def __init__(self, *args, **kwds):
182 188 self.args = args
183 189 self.kwds = kwds
@@ -187,18 +193,31 b' class argument(ArgDecorator):'
187 193 """
188 194 if group is not None:
189 195 parser = group
190 parser.add_argument(*self.args, **self.kwds)
196 getattr(parser, self._method_name)(*self.args, **self.kwds)
191 197 return None
192 198
193 199
194 class argument_group(ArgDecorator):
200 class argument(ArgMethodWrapper):
201 """ Store arguments and keywords to pass to add_argument().
202
203 Instances also serve to decorate command methods.
204 """
205 _method_name = 'add_argument'
206
207
208 class defaults(ArgMethodWrapper):
209 """ Store arguments and keywords to pass to set_defaults().
210
211 Instances also serve to decorate command methods.
212 """
213 _method_name = 'set_defaults'
214
215
216 class argument_group(ArgMethodWrapper):
195 217 """ Store arguments and keywords to pass to add_argument_group().
196 218
197 219 Instances also serve to decorate command methods.
198 220 """
199 def __init__(self, *args, **kwds):
200 self.args = args
201 self.kwds = kwds
202 221
203 222 def add_to_parser(self, parser, group):
204 223 """ Add this object's information to the parser.
@@ -313,7 +313,8 b' Currently the magic system has the following functions:""",'
313 313 import IPython.utils.rlineimpl as readline
314 314
315 315 if not shell.colors_force and \
316 not readline.have_readline and sys.platform == "win32":
316 not readline.have_readline and \
317 (sys.platform == "win32" or sys.platform == "cli"):
317 318 msg = """\
318 319 Proper color support under MS Windows requires the pyreadline library.
319 320 You can find it at:
@@ -563,6 +563,11 b' python-profiler package from non-free.""")'
563 563 return
564 564 # if we find a good linenumber, set the breakpoint
565 565 deb.do_break('%s:%s' % (filename, bp))
566
567 # Mimic Pdb._runscript(...)
568 deb._wait_for_mainpyfile = True
569 deb.mainpyfile = deb.canonic(filename)
570
566 571 # Start file run
567 572 print "NOTE: Enter 'c' at the",
568 573 print "%s prompt to start your script." % deb.prompt
@@ -59,14 +59,30 b' class ExtensionMagics(Magics):'
59 59 """Load an IPython extension by its module name."""
60 60 if not module_str:
61 61 raise UsageError('Missing module name.')
62 return self.shell.extension_manager.load_extension(module_str)
62 res = self.shell.extension_manager.load_extension(module_str)
63
64 if res == 'already loaded':
65 print "The %s extension is already loaded. To reload it, use:" % module_str
66 print " %reload_ext", module_str
67 elif res == 'no load function':
68 print "The %s module is not an IPython extension." % module_str
63 69
64 70 @line_magic
65 71 def unload_ext(self, module_str):
66 """Unload an IPython extension by its module name."""
72 """Unload an IPython extension by its module name.
73
74 Not all extensions can be unloaded, only those which define an
75 ``unload_ipython_extension`` function.
76 """
67 77 if not module_str:
68 78 raise UsageError('Missing module name.')
69 self.shell.extension_manager.unload_extension(module_str)
79
80 res = self.shell.extension_manager.unload_extension(module_str)
81
82 if res == 'no unload function':
83 print "The %s extension doesn't define how to unload it." % module_str
84 elif res == "not loaded":
85 print "The %s extension is not loaded." % module_str
70 86
71 87 @line_magic
72 88 def reload_ext(self, module_str):
@@ -16,10 +16,13 b' from __future__ import print_function'
16 16 # Stdlib
17 17 import os
18 18 from io import open as io_open
19 from IPython.external.argparse import Action
19 20
20 21 # Our own packages
21 22 from IPython.core.error import StdinNotImplementedError
22 23 from IPython.core.magic import Magics, magics_class, line_magic
24 from IPython.core.magic_arguments import (argument, magic_arguments,
25 parse_argstring)
23 26 from IPython.testing.skipdoctest import skip_doctest
24 27 from IPython.utils import io
25 28
@@ -27,16 +30,71 b' from IPython.utils import io'
27 30 # Magics class implementation
28 31 #-----------------------------------------------------------------------------
29 32
33
34 _unspecified = object()
35
36
30 37 @magics_class
31 38 class HistoryMagics(Magics):
32 39
40 @magic_arguments()
41 @argument(
42 '-n', dest='print_nums', action='store_true', default=False,
43 help="""
44 print line numbers for each input.
45 This feature is only available if numbered prompts are in use.
46 """)
47 @argument(
48 '-o', dest='get_output', action='store_true', default=False,
49 help="also print outputs for each input.")
50 @argument(
51 '-p', dest='pyprompts', action='store_true', default=False,
52 help="""
53 print classic '>>>' python prompts before each input.
54 This is useful for making documentation, and in conjunction
55 with -o, for producing doctest-ready output.
56 """)
57 @argument(
58 '-t', dest='raw', action='store_false', default=True,
59 help="""
60 print the 'translated' history, as IPython understands it.
61 IPython filters your input and converts it all into valid Python
62 source before executing it (things like magics or aliases are turned
63 into function calls, for example). With this option, you'll see the
64 native history instead of the user-entered version: '%%cd /' will be
65 seen as 'get_ipython().magic("%%cd /")' instead of '%%cd /'.
66 """)
67 @argument(
68 '-f', dest='filename',
69 help="""
70 FILENAME: instead of printing the output to the screen, redirect
71 it to the given file. The file is always overwritten, though *when
72 it can*, IPython asks for confirmation first. In particular, running
73 the command 'history -f FILENAME' from the IPython Notebook
74 interface will replace FILENAME even if it already exists *without*
75 confirmation.
76 """)
77 @argument(
78 '-g', dest='pattern', nargs='*', default=None,
79 help="""
80 treat the arg as a glob pattern to search for in (full) history.
81 This includes the saved history (almost all commands ever written).
82 The pattern may contain '?' to match one unknown character and '*'
83 to match any number of unknown characters. Use '%%hist -g' to show
84 full saved history (may be very long).
85 """)
86 @argument(
87 '-l', dest='limit', type=int, nargs='?', default=_unspecified,
88 help="""
89 get the last n lines from all sessions. Specify n as a single
90 arg, or the default is the last 10 lines.
91 """)
92 @argument('range', nargs='*')
33 93 @skip_doctest
34 94 @line_magic
35 95 def history(self, parameter_s = ''):
36 96 """Print input history (_i<n> variables), with most recent last.
37 97
38 %history [-o -p -t -n] [-f filename] [range | -g pattern | -l number]
39
40 98 By default, input history is printed without line numbers so it can be
41 99 directly pasted into an editor. Use -n to show them.
42 100
@@ -52,43 +110,6 b' class HistoryMagics(Magics):'
52 110
53 111 The same syntax is used by %macro, %save, %edit, %rerun
54 112
55 Options:
56
57 -n: print line numbers for each input.
58 This feature is only available if numbered prompts are in use.
59
60 -o: also print outputs for each input.
61
62 -p: print classic '>>>' python prompts before each input. This is
63 useful for making documentation, and in conjunction with -o, for
64 producing doctest-ready output.
65
66 -r: (default) print the 'raw' history, i.e. the actual commands you
67 typed.
68
69 -t: print the 'translated' history, as IPython understands it.
70 IPython filters your input and converts it all into valid Python
71 source before executing it (things like magics or aliases are turned
72 into function calls, for example). With this option, you'll see the
73 native history instead of the user-entered version: '%cd /' will be
74 seen as 'get_ipython().magic("%cd /")' instead of '%cd /'.
75
76 -g: treat the arg as a pattern to grep for in (full) history.
77 This includes the saved history (almost all commands ever written).
78 The pattern may contain '?' to match one unknown character and '*'
79 to match any number of unknown characters. Use '%hist -g' to show
80 full saved history (may be very long).
81
82 -l: get the last n lines from all sessions. Specify n as a single
83 arg, or the default is the last 10 lines.
84
85 -f FILENAME: instead of printing the output to the screen, redirect
86 it to the given file. The file is always overwritten, though *when
87 it can*, IPython asks for confirmation first. In particular, running
88 the command 'history -f FILENAME' from the IPython Notebook
89 interface will replace FILENAME even if it already exists *without*
90 confirmation.
91
92 113 Examples
93 114 --------
94 115 ::
@@ -100,11 +121,7 b' class HistoryMagics(Magics):'
100 121
101 122 """
102 123
103 if not self.shell.displayhook.do_full_cache:
104 print('This feature is only available if numbered prompts '
105 'are in use.')
106 return
107 opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string')
124 args = parse_argstring(self.history, parameter_s)
108 125
109 126 # For brevity
110 127 history_manager = self.shell.history_manager
@@ -116,9 +133,8 b' class HistoryMagics(Magics):'
116 133 return "%s/%s" % (session, line)
117 134
118 135 # Check if output to specific file was requested.
119 try:
120 outfname = opts['f']
121 except KeyError:
136 outfname = args.filename
137 if not outfname:
122 138 outfile = io.stdout # default
123 139 # We don't want to close stdout at the end!
124 140 close_at_end = False
@@ -135,27 +151,29 b' class HistoryMagics(Magics):'
135 151 outfile = io_open(outfname, 'w', encoding='utf-8')
136 152 close_at_end = True
137 153
138 print_nums = 'n' in opts
139 get_output = 'o' in opts
140 pyprompts = 'p' in opts
141 # Raw history is the default
142 raw = not('t' in opts)
154 print_nums = args.print_nums
155 get_output = args.get_output
156 pyprompts = args.pyprompts
157 raw = args.raw
143 158
144 159 pattern = None
160 limit = None if args.limit is _unspecified else args.limit
145 161
146 if 'g' in opts: # Glob search
147 pattern = "*" + args + "*" if args else "*"
148 hist = history_manager.search(pattern, raw=raw, output=get_output)
162 if args.pattern is not None:
163 if args.pattern:
164 pattern = "*" + " ".join(args.pattern) + "*"
165 else:
166 pattern = "*"
167 hist = history_manager.search(pattern, raw=raw, output=get_output,
168 n=limit)
149 169 print_nums = True
150 elif 'l' in opts: # Get 'tail'
151 try:
152 n = int(args)
153 except (ValueError, IndexError):
154 n = 10
170 elif args.limit is not _unspecified:
171 n = 10 if limit is None else limit
155 172 hist = history_manager.get_tail(n, raw=raw, output=get_output)
156 173 else:
157 if args: # Get history by ranges
158 hist = history_manager.get_range_by_str(args, raw, get_output)
174 if args.range: # Get history by ranges
175 hist = history_manager.get_range_by_str(" ".join(args.range),
176 raw, get_output)
159 177 else: # Just get history for the current session
160 178 hist = history_manager.get_range(raw=raw, output=get_output)
161 179
@@ -69,7 +69,7 b' class NamespaceMagics(Magics):'
69 69 @skip_doctest
70 70 @line_magic
71 71 def pdef(self, parameter_s='', namespaces=None):
72 """Print the definition header for any callable object.
72 """Print the call signature for any callable object.
73 73
74 74 If the object is a class, print the constructor information.
75 75
@@ -98,7 +98,7 b' class NamespaceMagics(Magics):'
98 98 self.shell._inspect('psource',parameter_s, namespaces)
99 99
100 100 @line_magic
101 def pfile(self, parameter_s=''):
101 def pfile(self, parameter_s='', namespaces=None):
102 102 """Print (or run through pager) the file where an object is defined.
103 103
104 104 The file opens at the line where the object definition begins. IPython
@@ -111,7 +111,7 b' class NamespaceMagics(Magics):'
111 111 viewer."""
112 112
113 113 # first interpret argument as an object name
114 out = self.shell._inspect('pfile',parameter_s)
114 out = self.shell._inspect('pfile',parameter_s, namespaces)
115 115 # if not, try the input as a filename
116 116 if out == 'not found':
117 117 try:
@@ -344,7 +344,7 b' class Inspector:'
344 344 self.set_active_scheme(scheme)
345 345
346 346 def _getdef(self,obj,oname=''):
347 """Return the definition header for any callable object.
347 """Return the call signature for any callable object.
348 348
349 349 If any exception is generated, None is returned instead and the
350 350 exception is suppressed."""
@@ -373,7 +373,7 b' class Inspector:'
373 373 print()
374 374
375 375 def pdef(self, obj, oname=''):
376 """Print the definition header for any callable object.
376 """Print the call signature for any callable object.
377 377
378 378 If the object is a class, print the constructor information."""
379 379
@@ -96,13 +96,41 b' def doctest_run_option_parser():'
96 96 In [2]: %run print_argv.py print*.py
97 97 ['print_argv.py']
98 98
99 In [3]: %run print_argv.py print\\*.py
99 In [3]: %run -G print_argv.py print*.py
100 100 ['print*.py']
101 101
102 In [4]: %run print_argv.py 'print*.py'
102 """
103
104
105 @dec.skip_win32
106 def doctest_run_option_parser_for_posix():
107 r"""Test option parser in %run (Linux/OSX specific).
108
109 You need double quote to escape glob in POSIX systems:
110
111 In [1]: %run print_argv.py print\\*.py
112 ['print*.py']
113
114 You can't use quote to escape glob in POSIX systems:
115
116 In [2]: %run print_argv.py 'print*.py'
103 117 ['print_argv.py']
104 118
105 In [5]: %run -G print_argv.py print*.py
119 """
120
121
122 @dec.skip_if_not_win32
123 def doctest_run_option_parser_for_windows():
124 r"""Test option parser in %run (Windows specific).
125
126 In Windows, you can't escape ``*` `by backslash:
127
128 In [1]: %run print_argv.py print\\*.py
129 ['print\\*.py']
130
131 You can use quote to escape glob:
132
133 In [2]: %run print_argv.py 'print*.py'
106 134 ['print*.py']
107 135
108 136 """
@@ -514,14 +514,8 b' class AutoreloadMagics(Magics):'
514 514 pass
515 515
516 516
517 _loaded = False
518
519
520 517 def load_ipython_extension(ip):
521 518 """Load the extension in IPython."""
522 global _loaded
523 if not _loaded:
524 auto_reload = AutoreloadMagics(ip)
525 ip.register_magics(auto_reload)
526 ip.set_hook('pre_run_code_hook', auto_reload.pre_run_code_hook)
527 _loaded = True
519 auto_reload = AutoreloadMagics(ip)
520 ip.register_magics(auto_reload)
521 ip.set_hook('pre_run_code_hook', auto_reload.pre_run_code_hook)
@@ -273,11 +273,7 b' class CythonMagics(Magics):'
273 273 html = '\n'.join(l for l in html.splitlines() if not r.match(l))
274 274 return html
275 275
276 _loaded = False
277 276
278 277 def load_ipython_extension(ip):
279 278 """Load the extension in IPython."""
280 global _loaded
281 if not _loaded:
282 ip.register_magics(CythonMagics)
283 _loaded = True
279 ip.register_magics(CythonMagics)
@@ -362,10 +362,6 b' __doc__ = __doc__.format('
362 362 )
363 363
364 364
365 _loaded = False
366 365 def load_ipython_extension(ip):
367 366 """Load the extension in IPython."""
368 global _loaded
369 if not _loaded:
370 ip.register_magics(OctaveMagics)
371 _loaded = True
367 ip.register_magics(OctaveMagics)
@@ -588,10 +588,6 b' __doc__ = __doc__.format('
588 588 )
589 589
590 590
591 _loaded = False
592 591 def load_ipython_extension(ip):
593 592 """Load the extension in IPython."""
594 global _loaded
595 if not _loaded:
596 ip.register_magics(RMagics)
597 _loaded = True
593 ip.register_magics(RMagics)
@@ -209,12 +209,6 b' class StoreMagics(Magics):'
209 209 print "Stored '%s' (%s)" % (args[0], obj.__class__.__name__)
210 210
211 211
212 _loaded = False
213
214
215 212 def load_ipython_extension(ip):
216 213 """Load the extension in IPython."""
217 global _loaded
218 if not _loaded:
219 ip.register_magics(StoreMagics)
220 _loaded = True
214 ip.register_magics(StoreMagics)
@@ -22,6 +22,7 b' Authors'
22 22 from __future__ import print_function
23 23
24 24 import os,sys, atexit
25 import signal
25 26 import socket
26 27 from multiprocessing import Process
27 28 from getpass import getpass, getuser
@@ -331,9 +332,10 b' def _paramiko_tunnel(lport, rport, server, remoteip, keyfile=None, password=None'
331 332 except Exception as e:
332 333 print ('*** Failed to connect to %s:%d: %r' % (server, port, e))
333 334 sys.exit(1)
334
335 # print ('Now forwarding port %d to %s:%d ...' % (lport, server, rport))
336
335
336 # Don't let SIGINT kill the tunnel subprocess
337 signal.signal(signal.SIGINT, signal.SIG_IGN)
338
337 339 try:
338 340 forward_tunnel(lport, remoteip, rport, client.get_transport())
339 341 except KeyboardInterrupt:
@@ -470,11 +470,14 b' class NotebookApp(BaseIPythonApplication):'
470 470 ssl_options = None
471 471 self.web_app.password = self.password
472 472 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options)
473 if ssl_options is None and not self.ip and not (self.read_only and not self.password):
474 self.log.critical('WARNING: the notebook server is listening on all IP addresses '
475 'but not using any encryption or authentication. This is highly '
476 'insecure and not recommended.')
477
473 if not self.ip:
474 warning = "WARNING: The notebook server is listening on all IP addresses"
475 if ssl_options is None:
476 self.log.critical(warning + " and not using encryption. This"
477 "is not recommended.")
478 if not self.password and not self.read_only:
479 self.log.critical(warning + "and not using authentication."
480 "This is highly insecure and not recommended.")
478 481 success = None
479 482 for port in random_ports(self.port, self.port_retries+1):
480 483 try:
@@ -50,15 +50,13 b' var IPython = (function (IPython) {'
50 50 });
51 51 };
52 52
53
54 // typeset with MathJax if MathJax is available
55 53 Cell.prototype.typeset = function () {
56 54 if (window.MathJax){
57 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
55 var cell_math = this.element.get(0);
56 MathJax.Hub.Queue(["Typeset",MathJax.Hub,cell_math]);
58 57 }
59 58 };
60 59
61
62 60 Cell.prototype.select = function () {
63 61 this.element.addClass('ui-widget-content ui-corner-all');
64 62 this.selected = true;
@@ -123,6 +123,7 b' var IPython = (function (IPython) {'
123 123 } else if (event.keyCode === key.TAB && event.type == 'keydown') {
124 124 // Tab completion.
125 125 //Do not trim here because of tooltip
126 if (editor.somethingSelected()){return false}
126 127 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
127 128 if (pre_cursor.trim() === "") {
128 129 // Don't autocomplete if the part of the line before the cursor
@@ -64,7 +64,7 b' var IPython = (function (IPython) {'
64 64
65 65
66 66 Kernel.prototype.restart = function () {
67 $([IPython.events]).trigger({type: 'status_restarting.Kernel', kernel: this});
67 $([IPython.events]).trigger('status_restarting.Kernel', {kernel: this});
68 68 var that = this;
69 69 if (this.running) {
70 70 this.stop_channels();
@@ -86,6 +86,7 b' var IPython = (function (IPython) {'
86 86 this.start_channels();
87 87 this.shell_channel.onmessage = $.proxy(this._handle_shell_reply,this);
88 88 this.iopub_channel.onmessage = $.proxy(this._handle_iopub_reply,this);
89 $([IPython.events]).trigger('status_started.Kernel', {kernel: this});
89 90 };
90 91
91 92
@@ -245,7 +246,8 b' var IPython = (function (IPython) {'
245 246 user_expressions : {},
246 247 allow_stdin : false
247 248 };
248 $.extend(true, content, options)
249 $.extend(true, content, options)
250 $([IPython.events]).trigger('execution_request.Kernel', {kernel: this, content:content});
249 251 var msg = this._get_msg("execute_request", content);
250 252 this.shell_channel.send(JSON.stringify(msg));
251 253 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
@@ -279,7 +281,7 b' var IPython = (function (IPython) {'
279 281
280 282 Kernel.prototype.interrupt = function () {
281 283 if (this.running) {
282 $([IPython.events]).trigger({type: 'status_interrupting.Kernel', kernel: this});
284 $([IPython.events]).trigger('status_interrupting.Kernel', {kernel: this});
283 285 $.post(this.kernel_url + "/interrupt");
284 286 };
285 287 };
@@ -312,6 +314,7 b' var IPython = (function (IPython) {'
312 314
313 315 Kernel.prototype._handle_shell_reply = function (e) {
314 316 reply = $.parseJSON(e.data);
317 $([IPython.events]).trigger('shell_reply.Kernel', {kernel: this, reply:reply});
315 318 var header = reply.header;
316 319 var content = reply.content;
317 320 var metadata = reply.metadata;
@@ -367,12 +370,12 b' var IPython = (function (IPython) {'
367 370 }
368 371 } else if (msg_type === 'status') {
369 372 if (content.execution_state === 'busy') {
370 $([IPython.events]).trigger({type: 'status_busy.Kernel', kernel: this});
373 $([IPython.events]).trigger('status_busy.Kernel', {kernel: this});
371 374 } else if (content.execution_state === 'idle') {
372 $([IPython.events]).trigger({type: 'status_idle.Kernel', kernel: this});
375 $([IPython.events]).trigger('status_idle.Kernel', {kernel: this});
373 376 } else if (content.execution_state === 'dead') {
374 377 this.stop_channels();
375 $([IPython.events]).trigger({type: 'status_dead.Kernel', kernel: this});
378 $([IPython.events]).trigger('status_dead.Kernel', {kernel: this});
376 379 };
377 380 } else if (msg_type === 'clear_output') {
378 381 var cb = callbacks['clear_output'];
@@ -51,10 +51,10 b' var IPython = (function (IPython) {'
51 51 },
52 52 {
53 53 id : 'paste_b',
54 label : 'Paste Cell',
54 label : 'Paste Cell Below',
55 55 icon : 'ui-icon-clipboard',
56 56 callback : function () {
57 IPython.notebook.paste_cell();
57 IPython.notebook.paste_cell_below();
58 58 }
59 59 }
60 60 ],'cut_copy_paste');
@@ -14,10 +14,9 b" IPython.namespace('IPython.mathjaxutils');"
14 14 IPython.mathjaxutils = (function (IPython) {
15 15
16 16 var init = function () {
17 if (window.MathJax) {
17 if (window.MathJax) {
18 18 // MathJax loaded
19 19 MathJax.Hub.Config({
20 TeX: { equationNumbers: { autoNumber: "AMS", useLabelIds: true } },
21 20 tex2jax: {
22 21 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
23 22 displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
@@ -28,6 +27,7 b' IPython.mathjaxutils = (function (IPython) {'
28 27 styles: {'.MathJax_Display': {"margin": 0}}
29 28 }
30 29 });
30 MathJax.Hub.Configured();
31 31 } else if (window.mathjax_url != "") {
32 32 // Don't have MathJax, but should. Show dialog.
33 33 var dialog = $('<div></div>')
@@ -88,7 +88,6 b' IPython.mathjaxutils = (function (IPython) {'
88 88 var inline = "$"; // the inline math delimiter
89 89 var blocks, start, end, last, braces; // used in searching for math
90 90 var math; // stores math until pagedown (Markdown parser) is done
91 var HUB = MathJax.Hub;
92 91
93 92 // MATHSPLIT contains the pattern for math delimiters and special symbols
94 93 // needed for searching for math in the text input.
@@ -102,11 +101,12 b' IPython.mathjaxutils = (function (IPython) {'
102 101 // math, then push the math string onto the storage array.
103 102 // The preProcess function is called on all blocks if it has been passed in
104 103 var process_math = function (i, j, pre_process) {
104 var hub = MathJax.Hub;
105 105 var block = blocks.slice(i, j + 1).join("").replace(/&/g, "&amp;") // use HTML entity for &
106 106 .replace(/</g, "&lt;") // use HTML entity for <
107 107 .replace(/>/g, "&gt;") // use HTML entity for >
108 108 ;
109 if (HUB.Browser.isMSIE) {
109 if (hub.Browser.isMSIE) {
110 110 block = block.replace(/(%[^\n]*)\n/g, "$1<br/>\n")
111 111 }
112 112 while (j > i) {
@@ -127,6 +127,10 b' IPython.mathjaxutils = (function (IPython) {'
127 127 // (which will be a paragraph).
128 128 //
129 129 var remove_math = function (text) {
130 if (!window.MathJax) {
131 return text;
132 }
133
130 134 start = end = last = null; // for tracking math delimiters
131 135 math = []; // stores math strings for later
132 136
@@ -216,6 +220,10 b' IPython.mathjaxutils = (function (IPython) {'
216 220 // and clear the math array (no need to keep it around).
217 221 //
218 222 var replace_math = function (text) {
223 if (!window.MathJax) {
224 return text;
225 }
226
219 227 text = text.replace(/@@(\d+)@@/g, function (match, n) {
220 228 return math[n]
221 229 });
@@ -223,21 +231,11 b' IPython.mathjaxutils = (function (IPython) {'
223 231 return text;
224 232 }
225 233
226 var queue_render = function () {
227 // see https://groups.google.com/forum/?fromgroups=#!topic/mathjax-users/cpwy5eCH1ZQ
228 MathJax.Hub.Queue(
229 ["resetEquationNumbers",MathJax.InputJax.TeX],
230 ["PreProcess",MathJax.Hub],
231 ["Reprocess",MathJax.Hub]
232 );
233 }
234
235 234 return {
236 235 init : init,
237 236 process_math : process_math,
238 237 remove_math : remove_math,
239 replace_math : replace_math,
240 queue_render : queue_render
238 replace_math : replace_math
241 239 };
242 240
243 241 }(IPython)); No newline at end of file
@@ -128,7 +128,13 b' var IPython = (function (IPython) {'
128 128 });
129 129 this.element.find('#run_all_cells').click(function () {
130 130 IPython.notebook.execute_all_cells();
131 });
131 }).attr('title', 'Run all cells in the notebook');
132 this.element.find('#run_all_cells_above').click(function () {
133 IPython.notebook.execute_cells_above();
134 }).attr('title', 'Run all cells above (but not including) this cell');
135 this.element.find('#run_all_cells_below').click(function () {
136 IPython.notebook.execute_cells_below();
137 }).attr('title', 'Run this cell and all cells below it');
132 138 this.element.find('#to_code').click(function () {
133 139 IPython.notebook.to_code();
134 140 });
@@ -22,6 +22,9 b' var IPython = (function (IPython) {'
22 22 this.next_prompt_number = 1;
23 23 this.kernel = null;
24 24 this.clipboard = null;
25 this.undelete_backup = null;
26 this.undelete_index = null;
27 this.undelete_below = false;
25 28 this.paste_enabled = false;
26 29 this.dirty = false;
27 30 this.metadata = {};
@@ -139,8 +142,8 b' var IPython = (function (IPython) {'
139 142 that.control_key_active = false;
140 143 return false;
141 144 } else if (event.which === 86 && that.control_key_active) {
142 // Paste selected cell = v
143 that.paste_cell();
145 // Paste below selected cell = v
146 that.paste_cell_below();
144 147 that.control_key_active = false;
145 148 return false;
146 149 } else if (event.which === 68 && that.control_key_active) {
@@ -257,6 +260,11 b' var IPython = (function (IPython) {'
257 260 IPython.quick_help.show_keyboard_shortcuts();
258 261 that.control_key_active = false;
259 262 return false;
263 } else if (event.which === 90 && that.control_key_active) {
264 // Undo last cell delete = z
265 that.undelete();
266 that.control_key_active = false;
267 return false;
260 268 } else if (that.control_key_active) {
261 269 that.control_key_active = false;
262 270 return true;
@@ -536,13 +544,19 b' var IPython = (function (IPython) {'
536 544
537 545 Notebook.prototype.delete_cell = function (index) {
538 546 var i = this.index_or_selected(index);
547 var cell = this.get_selected_cell();
548 this.undelete_backup = cell.toJSON();
539 549 if (this.is_valid_cell_index(i)) {
540 550 var ce = this.get_cell_element(i);
541 551 ce.remove();
542 552 if (i === (this.ncells())) {
543 553 this.select(i-1);
554 this.undelete_index = i - 1;
555 this.undelete_below = true;
544 556 } else {
545 557 this.select(i);
558 this.undelete_index = i;
559 this.undelete_below = false;
546 560 };
547 561 this.dirty = true;
548 562 };
@@ -560,6 +574,11 b' var IPython = (function (IPython) {'
560 574 // index = cell index or undefined to insert below selected
561 575 index = this.index_or_selected(index);
562 576 var cell = null;
577 // This is intentionally < rather than <= for the sake of more
578 // sensible behavior in some cases.
579 if (this.undelete_index !== null && index < this.undelete_index) {
580 this.undelete_index = this.undelete_index + 1;
581 }
563 582 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
564 583 if (type === 'code') {
565 584 cell = new IPython.CodeCell(this.kernel);
@@ -594,6 +613,9 b' var IPython = (function (IPython) {'
594 613 // index = cell index or undefined to insert above selected
595 614 index = this.index_or_selected(index);
596 615 var cell = null;
616 if (this.undelete_index !== null && index <= this.undelete_index) {
617 this.undelete_index = this.undelete_index + 1;
618 }
597 619 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
598 620 if (type === 'code') {
599 621 cell = new IPython.CodeCell(this.kernel);
@@ -756,8 +778,8 b' var IPython = (function (IPython) {'
756 778 Notebook.prototype.enable_paste = function () {
757 779 var that = this;
758 780 if (!this.paste_enabled) {
759 $('#paste_cell').removeClass('ui-state-disabled')
760 .on('click', function () {that.paste_cell();});
781 $('#paste_cell_replace').removeClass('ui-state-disabled')
782 .on('click', function () {that.paste_cell_replace();});
761 783 $('#paste_cell_above').removeClass('ui-state-disabled')
762 784 .on('click', function () {that.paste_cell_above();});
763 785 $('#paste_cell_below').removeClass('ui-state-disabled')
@@ -769,7 +791,7 b' var IPython = (function (IPython) {'
769 791
770 792 Notebook.prototype.disable_paste = function () {
771 793 if (this.paste_enabled) {
772 $('#paste_cell').addClass('ui-state-disabled').off('click');
794 $('#paste_cell_replace').addClass('ui-state-disabled').off('click');
773 795 $('#paste_cell_above').addClass('ui-state-disabled').off('click');
774 796 $('#paste_cell_below').addClass('ui-state-disabled').off('click');
775 797 this.paste_enabled = false;
@@ -789,7 +811,7 b' var IPython = (function (IPython) {'
789 811 };
790 812
791 813
792 Notebook.prototype.paste_cell = function () {
814 Notebook.prototype.paste_cell_replace = function () {
793 815 if (this.clipboard !== null && this.paste_enabled) {
794 816 var cell_data = this.clipboard;
795 817 var new_cell = this.insert_cell_above(cell_data.cell_type);
@@ -818,6 +840,33 b' var IPython = (function (IPython) {'
818 840 };
819 841 };
820 842
843 // Cell undelete
844
845 Notebook.prototype.undelete = function() {
846 if (this.undelete_backup !== null && this.undelete_index !== null) {
847 var current_index = this.get_selected_index();
848 if (this.undelete_index < current_index) {
849 current_index = current_index + 1;
850 }
851 if (this.undelete_index >= this.ncells()) {
852 this.select(this.ncells() - 1);
853 }
854 else {
855 this.select(this.undelete_index);
856 }
857 var cell_data = this.undelete_backup;
858 var new_cell = null;
859 if (this.undelete_below) {
860 new_cell = this.insert_cell_below(cell_data.cell_type);
861 } else {
862 new_cell = this.insert_cell_above(cell_data.cell_type);
863 }
864 new_cell.fromJSON(cell_data);
865 this.select(current_index);
866 this.undelete_backup = null;
867 this.undelete_index = null;
868 }
869 }
821 870
822 871 // Split/merge
823 872
@@ -1049,13 +1098,25 b' var IPython = (function (IPython) {'
1049 1098 };
1050 1099
1051 1100
1101 Notebook.prototype.execute_cells_below = function () {
1102 this.execute_cell_range(this.get_selected_index(), this.ncells());
1103 that.scroll_to_bottom();
1104 };
1105
1106 Notebook.prototype.execute_cells_above = function () {
1107 this.execute_cell_range(0, this.get_selected_index());
1108 };
1109
1052 1110 Notebook.prototype.execute_all_cells = function () {
1053 var ncells = this.ncells();
1054 for (var i=0; i<ncells; i++) {
1111 this.execute_cell_range(0, this.ncells());
1112 that.scroll_to_bottom();
1113 };
1114
1115 Notebook.prototype.execute_cell_range = function (start, end) {
1116 for (var i=start; i<end; i++) {
1055 1117 this.select(i);
1056 1118 this.execute_selected_cell({add_new:false});
1057 1119 };
1058 this.scroll_to_bottom();
1059 1120 };
1060 1121
1061 1122 // Persistance and loading
@@ -379,8 +379,10 b' var IPython = (function (IPython) {'
379 379 OutputArea.prototype.append_text = function (data, element, extra_class) {
380 380 var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_text");
381 381 // escape ANSI & HTML specials in plaintext:
382 data = utils.wrapUrls(data);
382 383 data = utils.fixConsole(data);
383 384 data = utils.fixCarriageReturn(data);
385 data = utils.autoLinkUrls(data);
384 386 if (extra_class){
385 387 toinsert.addClass(extra_class);
386 388 }
@@ -33,6 +33,7 b' var IPython = (function (IPython) {'
33 33 {key: 'Ctrl-m c', help: 'copy cell'},
34 34 {key: 'Ctrl-m v', help: 'paste cell'},
35 35 {key: 'Ctrl-m d', help: 'delete cell'},
36 {key: 'Ctrl-m z', help: 'undo last cell deletion'},
36 37 {key: 'Ctrl-m a', help: 'insert cell above'},
37 38 {key: 'Ctrl-m b', help: 'insert cell below'},
38 39 {key: 'Ctrl-m o', help: 'toggle output'},
@@ -221,11 +221,9 b' var IPython = (function (IPython) {'
221 221 if (this.rendered === false) {
222 222 var text = this.get_text();
223 223 if (text === "") { text = this.placeholder; }
224
225 224 text = IPython.mathjaxutils.remove_math(text)
226 225 var html = IPython.markdown_converter.makeHtml(text);
227 226 html = IPython.mathjaxutils.replace_math(html)
228
229 227 try {
230 228 this.set_rendered(html);
231 229 } catch (e) {
@@ -235,7 +233,6 b' var IPython = (function (IPython) {'
235 233 "Error rendering Markdown!<br/>" + e.toString())
236 234 );
237 235 }
238 this.typeset()
239 236 this.element.find('div.text_cell_input').hide();
240 237 this.element.find("div.text_cell_render").show();
241 238 var code_snippets = this.element.find("pre > code");
@@ -250,8 +247,7 b' var IPython = (function (IPython) {'
250 247
251 248 return '<code class="prettyprint">' + code + '</code>';
252 249 });
253
254 IPython.mathjaxutils.queue_render()
250 this.typeset()
255 251 this.rendered = true;
256 252 }
257 253 };
@@ -195,11 +195,30 b' IPython.utils = (function (IPython) {'
195 195 tmp = txt;
196 196 do {
197 197 txt = tmp;
198 tmp = txt.replace(/^.*\r(?!\n)/gm, '');
198 tmp = txt.replace(/\r+\n/gm, '\n'); // \r followed by \n --> newline
199 tmp = tmp.replace(/^.*\r+/gm, ''); // Other \r --> clear line
199 200 } while (tmp.length < txt.length);
200 201 return txt;
201 202 }
202 203
204 // Locate URLs in plain text and wrap them in spaces so that they can be
205 // better picked out by autoLinkUrls even after the text has been
206 // converted to HTML
207 function wrapUrls(txt) {
208 // Note this regexp is a modified version of one from
209 // Markdown.Converter For now it only supports http(s) and ftp URLs,
210 // but could easily support others (though file:// should maybe be
211 // avoided)
212 var url_re = /(^|\W)(https?|ftp)(:\/\/[-A-Z0-9+&@#\/%?=~_|\[\]\(\)!:,\.;]*[-A-Z0-9+&@#\/%=~_|\[\]])($|\W)/gi;
213 return txt.replace(url_re, "$1 $2$3 $4");
214 }
215
216 // Locate a URL with spaces around it and convert that to a anchor tag
217 function autoLinkUrls(txt) {
218 return txt.replace(/ ((https?|ftp):[^'">\s]+) /gi,
219 "<a target=\"_blank\" href=\"$1\">$1</a>");
220 }
221
203 222 grow = function(element) {
204 223 // Grow the cell by hand. This is used upon reloading from JSON, when the
205 224 // autogrow handler is not called.
@@ -261,6 +280,8 b' IPython.utils = (function (IPython) {'
261 280 keycodes : keycodes,
262 281 grow : grow,
263 282 fixCarriageReturn : fixCarriageReturn,
283 wrapUrls : wrapUrls,
284 autoLinkUrls : autoLinkUrls,
264 285 points_to_pixels : points_to_pixels
265 286 };
266 287
@@ -2,7 +2,7 b''
2 2 {% block stylesheet %}
3 3
4 4 {% if mathjax_url %}
5 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML" charset="utf-8"></script>
5 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML-full&delayStartupUntil=configured" charset="utf-8"></script>
6 6 {% end %}
7 7 <script type="text/javascript">
8 8 // MathJax disabled, set as null to distingish from *missing* MathJax,
@@ -75,9 +75,9 b' data-notebook-id={{notebook_id}}'
75 75 <ul>
76 76 <li id="cut_cell"><a href="#">Cut Cell</a></li>
77 77 <li id="copy_cell"><a href="#">Copy Cell</a></li>
78 <li id="paste_cell" class="ui-state-disabled"><a href="#">Paste Cell</a></li>
79 78 <li id="paste_cell_above" class="ui-state-disabled"><a href="#">Paste Cell Above</a></li>
80 79 <li id="paste_cell_below" class="ui-state-disabled"><a href="#">Paste Cell Below</a></li>
80 <li id="paste_cell_replace" class="ui-state-disabled"><a href="#">Paste Cell &amp; Replace</a></li>
81 81 <li id="delete_cell"><a href="#">Delete</a></li>
82 82 <hr/>
83 83 <li id="split_cell"><a href="#">Split Cell</a></li>
@@ -108,6 +108,8 b' data-notebook-id={{notebook_id}}'
108 108 <li id="run_cell"><a href="#">Run</a></li>
109 109 <li id="run_cell_in_place"><a href="#">Run in Place</a></li>
110 110 <li id="run_all_cells"><a href="#">Run All</a></li>
111 <li id="run_all_cells_above"><a href="#">Run All Above</a></li>
112 <li id="run_all_cells_below"><a href="#">Run All Below</a></li>
111 113 <hr/>
112 114 <li id="to_code"><a href="#">Code</a></li>
113 115 <li id="to_markdown"><a href="#">Markdown </a></li>
@@ -3,7 +3,7 b''
3 3 {% block stylesheet %}
4 4
5 5 {% if mathjax_url %}
6 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML" charset="utf-8"></script>
6 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML-full&delayStartupUntil=configured" charset="utf-8"></script>
7 7 {% end %}
8 8 <script type="text/javascript">
9 9 // MathJax disabled, set as null to distingish from *missing* MathJax,
@@ -268,7 +268,6 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
268 268 self._continuation_prompt = '> '
269 269 self._continuation_prompt_html = None
270 270 self._executing = False
271 self._filter_drag = False
272 271 self._filter_resize = False
273 272 self._html_exporter = HtmlExporter(self._control)
274 273 self._input_buffer_executing = ''
@@ -343,7 +342,51 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
343 342 triggered=self.reset_font)
344 343 self.addAction(self.reset_font_size)
345 344
345 # Accept drag and drop events here. Drops were already turned off
346 # in self._control when that widget was created.
347 self.setAcceptDrops(True)
346 348
349 #---------------------------------------------------------------------------
350 # Drag and drop support
351 #---------------------------------------------------------------------------
352
353 def dragEnterEvent(self, e):
354 if e.mimeData().hasUrls():
355 # The link action should indicate to that the drop will insert
356 # the file anme.
357 e.setDropAction(QtCore.Qt.LinkAction)
358 e.accept()
359 elif e.mimeData().hasText():
360 # By changing the action to copy we don't need to worry about
361 # the user accidentally moving text around in the widget.
362 e.setDropAction(QtCore.Qt.CopyAction)
363 e.accept()
364
365 def dragMoveEvent(self, e):
366 if e.mimeData().hasUrls():
367 pass
368 elif e.mimeData().hasText():
369 cursor = self._control.cursorForPosition(e.pos())
370 if self._in_buffer(cursor.position()):
371 e.setDropAction(QtCore.Qt.CopyAction)
372 self._control.setTextCursor(cursor)
373 else:
374 e.setDropAction(QtCore.Qt.IgnoreAction)
375 e.accept()
376
377 def dropEvent(self, e):
378 if e.mimeData().hasUrls():
379 self._keep_cursor_in_buffer()
380 cursor = self._control.textCursor()
381 filenames = [url.toLocalFile() for url in e.mimeData().urls()]
382 text = ', '.join("'" + f.replace("'", "'\"'\"'") + "'"
383 for f in filenames)
384 self._insert_plain_text_into_buffer(cursor, text)
385 elif e.mimeData().hasText():
386 cursor = self._control.cursorForPosition(e.pos())
387 if self._in_buffer(cursor.position()):
388 text = e.mimeData().text()
389 self._insert_plain_text_into_buffer(cursor, text)
347 390
348 391 def eventFilter(self, obj, event):
349 392 """ Reimplemented to ensure a console-like behavior in the underlying
@@ -392,39 +435,6 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
392 435 event.key() in self._shortcuts:
393 436 event.accept()
394 437
395 # Ensure that drags are safe. The problem is that the drag starting
396 # logic, which determines whether the drag is a Copy or Move, is locked
397 # down in QTextControl. If the widget is editable, which it must be if
398 # we're not executing, the drag will be a Move. The following hack
399 # prevents QTextControl from deleting the text by clearing the selection
400 # when a drag leave event originating from this widget is dispatched.
401 # The fact that we have to clear the user's selection is unfortunate,
402 # but the alternative--trying to prevent Qt from using its hardwired
403 # drag logic and writing our own--is worse.
404 elif etype == QtCore.QEvent.DragEnter and \
405 obj == self._control.viewport() and \
406 event.source() == self._control.viewport():
407 self._filter_drag = True
408 elif etype == QtCore.QEvent.DragLeave and \
409 obj == self._control.viewport() and \
410 self._filter_drag:
411 cursor = self._control.textCursor()
412 cursor.clearSelection()
413 self._control.setTextCursor(cursor)
414 self._filter_drag = False
415
416 # Ensure that drops are safe.
417 elif etype == QtCore.QEvent.Drop and obj == self._control.viewport():
418 cursor = self._control.cursorForPosition(event.pos())
419 if self._in_buffer(cursor.position()):
420 text = event.mimeData().text()
421 self._insert_plain_text_into_buffer(cursor, text)
422
423 # Qt is expecting to get something here--drag and drop occurs in its
424 # own event loop. Send a DragLeave event to end it.
425 QtGui.qApp.sendEvent(obj, QtGui.QDragLeaveEvent())
426 return True
427
428 438 # Handle scrolling of the vsplit pager. This hack attempts to solve
429 439 # problems with tearing of the help text inside the pager window. This
430 440 # happens only on Mac OS X with both PySide and PyQt. This fix isn't
@@ -1035,8 +1045,12 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1035 1045 control.setAcceptRichText(False)
1036 1046 control.setMouseTracking(True)
1037 1047
1048 # Prevent the widget from handling drops, as we already provide
1049 # the logic in this class.
1050 control.setAcceptDrops(False)
1051
1038 1052 # Install event filters. The filter on the viewport is needed for
1039 # mouse events and drag events.
1053 # mouse events.
1040 1054 control.installEventFilter(self)
1041 1055 control.viewport().installEventFilter(self)
1042 1056
@@ -1773,6 +1787,32 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1773 1787 else:
1774 1788 self._append_plain_text(text)
1775 1789
1790 def _set_paging(self, paging):
1791 """
1792 Change the pager to `paging` style.
1793
1794 XXX: currently, this is limited to switching between 'hsplit' and
1795 'vsplit'.
1796
1797 Parameters:
1798 -----------
1799 paging : string
1800 Either "hsplit", "vsplit", or "inside"
1801 """
1802 if self._splitter is None:
1803 raise NotImplementedError("""can only switch if --paging=hsplit or
1804 --paging=vsplit is used.""")
1805 if paging == 'hsplit':
1806 self._splitter.setOrientation(QtCore.Qt.Horizontal)
1807 elif paging == 'vsplit':
1808 self._splitter.setOrientation(QtCore.Qt.Vertical)
1809 elif paging == 'inside':
1810 raise NotImplementedError("""switching to 'inside' paging not
1811 supported yet.""")
1812 else:
1813 raise ValueError("unknown paging method '%s'" % paging)
1814 self.paging = paging
1815
1776 1816 def _prompt_finished(self):
1777 1817 """ Called immediately after a prompt is finished, i.e. when some input
1778 1818 will be processed and a new prompt displayed.
@@ -528,7 +528,25 b' class MainWindow(QtGui.QMainWindow):'
528 528 statusTip="Clear the console",
529 529 triggered=self.clear_magic_active_frontend)
530 530 self.add_menu_action(self.view_menu, self.clear_action)
531
531
532 self.pager_menu = self.view_menu.addMenu("&Pager")
533
534 hsplit_action = QtGui.QAction(".. &Horizontal Split",
535 self,
536 triggered=lambda: self.set_paging_active_frontend('hsplit'))
537
538 vsplit_action = QtGui.QAction(" : &Vertical Split",
539 self,
540 triggered=lambda: self.set_paging_active_frontend('vsplit'))
541
542 inside_action = QtGui.QAction(" &Inside Pager",
543 self,
544 triggered=lambda: self.set_paging_active_frontend('inside'))
545
546 self.pager_menu.addAction(hsplit_action)
547 self.pager_menu.addAction(vsplit_action)
548 self.pager_menu.addAction(inside_action)
549
532 550 def init_kernel_menu(self):
533 551 self.kernel_menu = self.menuBar().addMenu("&Kernel")
534 552 # Qt on OSX maps Ctrl to Cmd, and Meta to Ctrl
@@ -829,6 +847,9 b' class MainWindow(QtGui.QMainWindow):'
829 847 self.maximizeAct.setEnabled(True)
830 848 self.minimizeAct.setEnabled(True)
831 849
850 def set_paging_active_frontend(self, paging):
851 self.active_frontend._set_paging(paging)
852
832 853 def close_active_frontend(self):
833 854 self.close_tab(self.active_frontend)
834 855
@@ -1,7 +1,8 b''
1 1 """Various display related classes.
2 2
3 Authors : MinRK, gregcaporaso
3 Authors : MinRK, gregcaporaso, dannystaple
4 4 """
5 import urllib
5 6
6 7 from os.path import exists, isfile, splitext, abspath, join, isdir, walk
7 8
@@ -17,24 +18,40 b' class YouTubeVideo(object):'
17 18
18 19 vid = YouTubeVideo("foo")
19 20 display(vid)
21
22 To start from 30 seconds:
23
24 vid = YouTubeVideo("abc", start=30)
25 display(vid)
26
27 To calculate seconds from time as hours, minutes, seconds use:
28 start=int(timedelta(hours=1, minutes=46, seconds=40).total_seconds())
29
30 Other parameters can be provided as documented at
31 https://developers.google.com/youtube/player_parameters#parameter-subheader
20 32 """
21 33
22 def __init__(self, id, width=400, height=300):
34 def __init__(self, id, width=400, height=300, **kwargs):
23 35 self.id = id
24 36 self.width = width
25 37 self.height = height
38 self.params = kwargs
26 39
27 40 def _repr_html_(self):
28 41 """return YouTube embed iframe for this video id"""
42 if self.params:
43 params = "?" + urllib.urlencode(self.params)
44 else:
45 params = ""
29 46 return """
30 47 <iframe
31 48 width="%i"
32 49 height="%i"
33 src="http://www.youtube.com/embed/%s"
50 src="http://www.youtube.com/embed/%s%s"
34 51 frameborder="0"
35 52 allowfullscreen
36 53 ></iframe>
37 """%(self.width, self.height, self.id)
54 """ % (self.width, self.height, self.id, params)
38 55
39 56 class FileLink(object):
40 57 """Class for embedding a local file link in an IPython session, based on path
@@ -240,4 +257,4 b' class FileLinks(FileLink):'
240 257 """
241 258 result_lines = []
242 259 walk(self.path, self.terminal_display_formatter, result_lines)
243 return '\n'.join(result_lines) No newline at end of file
260 return '\n'.join(result_lines)
@@ -85,11 +85,33 b' def create_inputhook_qt4(mgr, app=None):'
85 85 return 0
86 86 app.processEvents(QtCore.QEventLoop.AllEvents, 300)
87 87 if not stdin_ready():
88 # Generally a program would run QCoreApplication::exec()
89 # from main() to enter and process the Qt event loop until
90 # quit() or exit() is called and the program terminates.
91 #
92 # For our input hook integration, we need to repeatedly
93 # enter and process the Qt event loop for only a short
94 # amount of time (say 50ms) to ensure that Python stays
95 # responsive to other user inputs.
96 #
97 # A naive approach would be to repeatedly call
98 # QCoreApplication::exec(), using a timer to quit after a
99 # short amount of time. Unfortunately, QCoreApplication
100 # emits an aboutToQuit signal before stopping, which has
101 # the undesirable effect of closing all modal windows.
102 #
103 # To work around this problem, we instead create a
104 # QEventLoop and call QEventLoop::exec(). Other than
105 # setting some state variables which do not seem to be
106 # used anywhere, the only thing QCoreApplication adds is
107 # the aboutToQuit signal which is precisely what we are
108 # trying to avoid.
88 109 timer = QtCore.QTimer()
89 timer.timeout.connect(app.quit)
110 event_loop = QtCore.QEventLoop()
111 timer.timeout.connect(event_loop.quit)
90 112 while not stdin_ready():
91 113 timer.start(50)
92 app.exec_()
114 event_loop.exec_()
93 115 timer.stop()
94 116 except KeyboardInterrupt:
95 117 ignore_CTRL_C()
@@ -41,6 +41,7 b' from IPython.zmq.ipkernel import Kernel, IPKernelApp'
41 41 from IPython.zmq.session import (
42 42 Session, session_aliases, session_flags
43 43 )
44 from IPython.zmq.zmqshell import ZMQInteractiveShell
44 45
45 46 from IPython.config.configurable import Configurable
46 47
@@ -143,7 +144,7 b' class IPEngineApp(BaseParallelApplication):'
143 144 description = _description
144 145 examples = _examples
145 146 config_file_name = Unicode(default_config_file_name)
146 classes = List([ProfileDir, Session, EngineFactory, Kernel, MPI])
147 classes = List([ZMQInteractiveShell, ProfileDir, Session, EngineFactory, Kernel, MPI])
147 148
148 149 startup_script = Unicode(u'', config=True,
149 150 help='specify a script to be run at startup')
@@ -650,18 +650,27 b' class SSHClusterLauncher(SSHLauncher):'
650 650
651 651 If not specified, use calling profile, stripping out possible leading homedir.
652 652 """)
653
654 def _remote_profile_dir_default(self):
655 """turns /home/you/.ipython/profile_foo into .ipython/profile_foo
656 """
653
654 def _profile_dir_changed(self, name, old, new):
655 if not self.remote_profile_dir:
656 # trigger remote_profile_dir_default logic again,
657 # in case it was already triggered before profile_dir was set
658 self.remote_profile_dir = self._strip_home(new)
659
660 @staticmethod
661 def _strip_home(path):
662 """turns /home/you/.ipython/profile_foo into .ipython/profile_foo"""
657 663 home = get_home_dir()
658 664 if not home.endswith('/'):
659 665 home = home+'/'
660 666
661 if self.profile_dir.startswith(home):
662 return self.profile_dir[len(home):]
667 if path.startswith(home):
668 return path[len(home):]
663 669 else:
664 return self.profile_dir
670 return path
671
672 def _remote_profile_dir_default(self):
673 return self._strip_home(self.profile_dir)
665 674
666 675 def _cluster_id_changed(self, name, old, new):
667 676 if new:
@@ -373,8 +373,11 b' def shellglob(args):'
373 373
374 374 """
375 375 expanded = []
376 # Do not unescape backslash in Windows as it is interpreted as
377 # path separator:
378 unescape = unescape_glob if sys.platform != 'win32' else lambda x: x
376 379 for a in args:
377 expanded.extend(glob.glob(a) or [unescape_glob(a)])
380 expanded.extend(glob.glob(a) or [unescape(a)])
378 381 return expanded
379 382
380 383
@@ -73,7 +73,7 b" if have_readline and hasattr(_rl, 'rlmain'):"
73 73 line = lineobj.TextLine(line)
74 74 return _rl.add_history(line)
75 75
76 if sys.platform == 'win32' and have_readline:
76 if (sys.platform == 'win32' or sys.platform == 'cli') and have_readline:
77 77 try:
78 78 _outputfile=_rl.GetOutputFile()
79 79 except AttributeError:
@@ -19,6 +19,7 b' import shutil'
19 19 import sys
20 20 import tempfile
21 21 from io import StringIO
22 from contextlib import contextmanager
22 23
23 24 from os.path import join, abspath, split
24 25
@@ -447,42 +448,73 b' def test_unicode_in_filename():'
447 448 str(ex)
448 449
449 450
450 def test_shellglob():
451 """Test glob expansion for %run magic."""
452 filenames_start_with_a = map('a{0}'.format, range(3))
453 filenames_end_with_b = map('{0}b'.format, range(3))
454 filenames = filenames_start_with_a + filenames_end_with_b
451 class TestShellGlob(object):
455 452
456 with TemporaryDirectory() as td:
457 save = os.getcwdu()
458 try:
459 os.chdir(td)
453 @classmethod
454 def setUpClass(cls):
455 cls.filenames_start_with_a = map('a{0}'.format, range(3))
456 cls.filenames_end_with_b = map('{0}b'.format, range(3))
457 cls.filenames = cls.filenames_start_with_a + cls.filenames_end_with_b
458 cls.tempdir = TemporaryDirectory()
459 td = cls.tempdir.name
460 460
461 with cls.in_tempdir():
461 462 # Create empty files
462 for fname in filenames:
463 for fname in cls.filenames:
463 464 open(os.path.join(td, fname), 'w').close()
464 465
465 def assert_match(patterns, matches):
466 # glob returns unordered list. that's why sorted is required.
467 nt.assert_equals(sorted(path.shellglob(patterns)),
468 sorted(matches))
469
470 assert_match(['*'], filenames)
471 assert_match(['a*'], filenames_start_with_a)
472 assert_match(['*c'], ['*c'])
473 assert_match(['*', 'a*', '*b', '*c'],
474 filenames
475 + filenames_start_with_a
476 + filenames_end_with_b
477 + ['*c'])
478
479 assert_match([r'\*'], ['*'])
480 assert_match([r'a\*', 'a*'], ['a*'] + filenames_start_with_a)
481 assert_match(['a[012]'], filenames_start_with_a)
482 assert_match([r'a\[012]'], ['a[012]'])
466 @classmethod
467 def tearDownClass(cls):
468 cls.tempdir.cleanup()
469
470 @classmethod
471 @contextmanager
472 def in_tempdir(cls):
473 save = os.getcwdu()
474 try:
475 os.chdir(cls.tempdir.name)
476 yield
483 477 finally:
484 478 os.chdir(save)
485 479
480 def check_match(self, patterns, matches):
481 with self.in_tempdir():
482 # glob returns unordered list. that's why sorted is required.
483 nt.assert_equals(sorted(path.shellglob(patterns)),
484 sorted(matches))
485
486 def common_cases(self):
487 return [
488 (['*'], self.filenames),
489 (['a*'], self.filenames_start_with_a),
490 (['*c'], ['*c']),
491 (['*', 'a*', '*b', '*c'], self.filenames
492 + self.filenames_start_with_a
493 + self.filenames_end_with_b
494 + ['*c']),
495 (['a[012]'], self.filenames_start_with_a),
496 ]
497
498 @skip_win32
499 def test_match_posix(self):
500 for (patterns, matches) in self.common_cases() + [
501 ([r'\*'], ['*']),
502 ([r'a\*', 'a*'], ['a*'] + self.filenames_start_with_a),
503 ([r'a\[012]'], ['a[012]']),
504 ]:
505 yield (self.check_match, patterns, matches)
506
507 @skip_if_not_win32
508 def test_match_windows(self):
509 for (patterns, matches) in self.common_cases() + [
510 # In windows, backslash is interpreted as path
511 # separator. Therefore, you can't escape glob
512 # using it.
513 ([r'a\*', 'a*'], [r'a\*'] + self.filenames_start_with_a),
514 ([r'a\[012]'], [r'a\[012]']),
515 ]:
516 yield (self.check_match, patterns, matches)
517
486 518
487 519 def test_unescape_glob():
488 520 nt.assert_equals(path.unescape_glob(r'\*\[\!\]\?'), '*[!]?')
@@ -1,4 +1,5 b''
1 1 include README.rst
2 include COPYING.txt
2 3 include ipython.py
3 4 include setupbase.py
4 5 include setupegg.py
@@ -162,87 +162,7 b''
162 162 "\n",
163 163 "---\n",
164 164 "\n",
165 "These equation reference examples are adapted from an [example page in the MathJax documentation](http://cdn.mathjax.org/mathjax/latest/test/sample-eqrefs.html). Note that it's okay to reference equations across cells. Click inside this cell to see the source.\n",
166 "\n",
167 "## Labeled equations and references\n",
168 "\n",
169 "Here is a labeled equation:\n",
170 "\\begin{equation}\n",
171 "x+1\\over\\sqrt{1-x^2}\\label{ref1}\n",
172 "\\end{equation}\n",
173 "\n",
174 "with a reference to ref1: \\ref{ref1},\n",
175 "and another numbered one with no label:\n",
176 "\\begin{equation}\n",
177 "x+1\\over\\sqrt{1-x^2}\n",
178 "\\end{equation}"
179 ]
180 },
181 {
182 "cell_type": "markdown",
183 "metadata": {},
184 "source": [
185 "## \\nonumber and equation*\n",
186 "\n",
187 "This one uses \\nonumber:\n",
188 "\\begin{equation}\n",
189 "x+1\\over\\sqrt{1-x^2}\\nonumber\n",
190 "\\end{equation}\n",
191 "\n",
192 "Here's one with the equation* environment:\n",
193 "\\begin{equation*}\n",
194 "x+1\\over\\sqrt{1-x^2}\n",
195 "\\end{equation*}"
196 ]
197 },
198 {
199 "cell_type": "markdown",
200 "metadata": {},
201 "source": [
202 "## Forward references\n",
203 "\n",
204 "This is a forward reference [\\ref{ref2}] and another \\eqref{ref2} for the \n",
205 "following equation:\n",
206 "\n",
207 "\\begin{equation}\n",
208 "x+1\\over\\sqrt{1-x^2}\\label{ref2}\n",
209 "\\end{equation}\n",
210 "\n",
211 "More math:\n",
212 "\\begin{equation}\n",
213 "x+1\\over\\sqrt{1-x^2}\n",
214 "\\end{equation}"
215 ]
216 },
217 {
218 "cell_type": "markdown",
219 "metadata": {},
220 "source": [
221 "### References inline and in environments\n",
222 "\n",
223 "Here is a ref inside math: $\\ref{ref2}+1$ and text after it.\n",
224 "\n",
225 "\\begin{align} \n",
226 "x& = y_1-y_2+y_3-y_5+y_8-\\dots \n",
227 "&& \\text{by \\eqref{ref1}}\\\\ \n",
228 "& = y'\\circ y^* && \\text{(by \\eqref{ref3})}\\\\ \n",
229 "& = y(0) y' && \\text {by Axiom 1.} \n",
230 "\\end{align} \n",
231 "\n",
232 "### Missing references\n",
233 "Here's a bad ref [\\ref{ref4}] to a nonexistent label.\n",
234 "\n",
235 "### Numbering align environments\n",
236 "An alignment:\n",
237 "\\begin{align}\n",
238 "a&=b\\label{ref3}\\cr\n",
239 "&=c+d\n",
240 "\\end{align}\n",
241 "and a starred one:\n",
242 "\\begin{align*}\n",
243 "a&=b\\cr\n",
244 "&=c+d\n",
245 "\\end{align*}"
165 "Equation numbering and referencing will be available in a future version of IPython."
246 166 ]
247 167 },
248 168 {
@@ -331,14 +251,6 b''
331 251 "x=4\n",
332 252 "$$"
333 253 ]
334 },
335 {
336 "cell_type": "code",
337 "collapsed": false,
338 "input": [],
339 "language": "python",
340 "metadata": {},
341 "outputs": []
342 254 }
343 255 ],
344 256 "metadata": {}
@@ -337,7 +337,7 b' this is just a summary:'
337 337 * **%pdoc <object>**: Print (or run through a pager if too long) the
338 338 docstring for an object. If the given object is a class, it will
339 339 print both the class and the constructor docstrings.
340 * **%pdef <object>**: Print the definition header for any callable
340 * **%pdef <object>**: Print the call signature for any callable
341 341 object. If the object is a class, print the constructor information.
342 342 * **%psource <object>**: Print (or run through a pager if too long)
343 343 the source code for an object.
@@ -6,6 +6,7 b' This should ONLY be run at real release time.'
6 6 from __future__ import print_function
7 7
8 8 from toollib import *
9 from gh_api import post_download
9 10
10 11 # Get main ipython dir, this will raise if it doesn't pass some checks
11 12 ipdir = get_ipdir()
@@ -53,6 +54,11 b" sh(sdists + ' upload')"
53 54 cd(distdir)
54 55 print( 'Uploading distribution files...')
55 56
57 for fname in os.listdir('.'):
58 print('uploading %s to GitHub' % fname)
59 desc = "IPython %s source distribution" % version
60 post_download("ipython/ipython", fname, description=desc)
61
56 62 # Make target dir if it doesn't exist
57 63 sh('ssh %s "mkdir -p %s/release/%s" ' % (archive_user, archive_dir, version))
58 64 sh('scp * %s' % release_site)
@@ -23,20 +23,34 b' except ImportError:'
23 23
24 24 github = '--github' in sys.argv
25 25
26 cmd_t = "{py} setup.py bdist_wininst --plat-name={plat}"
26 cmd_t = "{py} setup.py bdist_wininst"
27 27
28 28 pypi = '--pypi' in sys.argv
29 29 pypi_cmd_t = "python setup.py upload_wininst -f {fname}"
30 30
31 for py in ['python', 'python3']:
31 # Windows Python cannot normally cross-compile,
32 # so you must have 4 Pythons to make 4 installers:
33 # http://docs.python.org/2/distutils/builtdist.html#cross-compiling-on-windows
34
35 pythons = {
36 2: {
37 'win32' : r'C:\\Python27\Python.exe',
38 'win-amd64': r'C:\\Python27_64\Python.exe',
39 },
40 3: {
41 'win32' : r'C:\\Python33\Python.exe',
42 'win-amd64': r'C:\\Python33_64\Python.exe',
43 },
44 }
45
46 for v,plat_py in pythons.items():
32 47 # deliberately mangle the name,
33 48 # so easy_install doesn't find these and do horrible wrong things
34 v = 3 if py.endswith('3') else 2
35 49 try:
36 50 shutil.rmtree('build')
37 51 except OSError:
38 52 pass
39 for plat in ['win32', 'win-amd64']:
53 for plat,py in plat_py.items():
40 54 cmd = cmd_t.format(**locals())
41 55 sh(cmd)
42 56 orig = glob.glob(os.path.join('dist', 'ipython-*.{plat}.exe'.format(**locals())))[0]
General Comments 0
You need to be logged in to leave comments. Login now