Show More
1 | NO CONTENT: new file 100644, binary diff hidden |
|
NO CONTENT: new file 100644, binary diff hidden |
@@ -1,65 +1,57 b'' | |||||
1 | # encoding: utf-8 |
|
1 | # encoding: utf-8 | |
2 | """ |
|
2 | """ | |
3 | IPython: tools for interactive and parallel computing in Python. |
|
3 | IPython: tools for interactive and parallel computing in Python. | |
4 |
|
4 | |||
5 | http://ipython.org |
|
5 | http://ipython.org | |
6 | """ |
|
6 | """ | |
7 | #----------------------------------------------------------------------------- |
|
7 | #----------------------------------------------------------------------------- | |
8 | # Copyright (c) 2008-2011, IPython Development Team. |
|
8 | # Copyright (c) 2008-2011, IPython Development Team. | |
9 | # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu> |
|
9 | # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu> | |
10 | # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de> |
|
10 | # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de> | |
11 | # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu> |
|
11 | # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu> | |
12 | # |
|
12 | # | |
13 | # Distributed under the terms of the Modified BSD License. |
|
13 | # Distributed under the terms of the Modified BSD License. | |
14 | # |
|
14 | # | |
15 | # The full license is in the file COPYING.txt, distributed with this software. |
|
15 | # The full license is in the file COPYING.txt, distributed with this software. | |
16 | #----------------------------------------------------------------------------- |
|
16 | #----------------------------------------------------------------------------- | |
17 |
|
17 | |||
18 | #----------------------------------------------------------------------------- |
|
18 | #----------------------------------------------------------------------------- | |
19 | # Imports |
|
19 | # Imports | |
20 | #----------------------------------------------------------------------------- |
|
20 | #----------------------------------------------------------------------------- | |
21 | from __future__ import absolute_import |
|
21 | from __future__ import absolute_import | |
22 |
|
22 | |||
23 | import os |
|
23 | import os | |
24 | import sys |
|
24 | import sys | |
25 |
|
25 | |||
26 | #----------------------------------------------------------------------------- |
|
26 | #----------------------------------------------------------------------------- | |
27 | # Setup everything |
|
27 | # Setup everything | |
28 | #----------------------------------------------------------------------------- |
|
28 | #----------------------------------------------------------------------------- | |
29 |
|
29 | |||
30 | # Don't forget to also update setup.py when this changes! |
|
30 | # Don't forget to also update setup.py when this changes! | |
31 | if sys.version[0:3] < '2.6': |
|
31 | if sys.version[0:3] < '2.6': | |
32 | raise ImportError('Python Version 2.6 or above is required for IPython.') |
|
32 | raise ImportError('Python Version 2.6 or above is required for IPython.') | |
33 |
|
33 | |||
34 | # Make it easy to import extensions - they are always directly on pythonpath. |
|
34 | # Make it easy to import extensions - they are always directly on pythonpath. | |
35 | # Therefore, non-IPython modules can be added to extensions directory. |
|
35 | # Therefore, non-IPython modules can be added to extensions directory. | |
36 | # This should probably be in ipapp.py. |
|
36 | # This should probably be in ipapp.py. | |
37 | sys.path.append(os.path.join(os.path.dirname(__file__), "extensions")) |
|
37 | sys.path.append(os.path.join(os.path.dirname(__file__), "extensions")) | |
38 |
|
38 | |||
39 | #----------------------------------------------------------------------------- |
|
39 | #----------------------------------------------------------------------------- | |
40 | # Setup the top level names |
|
40 | # Setup the top level names | |
41 | #----------------------------------------------------------------------------- |
|
41 | #----------------------------------------------------------------------------- | |
42 |
|
42 | |||
43 | from .config.loader import Config |
|
43 | from .config.loader import Config | |
44 | from .core import release |
|
44 | from .core import release | |
45 | from .core.application import Application |
|
45 | from .core.application import Application | |
46 | # Todo: Should these be imported here? We need to rethink what is imported in |
|
|||
47 | # this module. |
|
|||
48 | #from .core.display import ( |
|
|||
49 | # display, display_pretty, display_html, display_latex, |
|
|||
50 | # display_png, display_jpeg, display_svg, display_json, |
|
|||
51 | # display_javascript, HTML, SVG, Math, Image, JSON, |
|
|||
52 | # Javascript, Pretty |
|
|||
53 | #) |
|
|||
54 | from .frontend.terminal.embed import embed |
|
46 | from .frontend.terminal.embed import embed | |
55 | from .core.error import TryNext |
|
47 | from .core.error import TryNext | |
56 | from .core.interactiveshell import InteractiveShell |
|
48 | from .core.interactiveshell import InteractiveShell | |
57 | from .testing import test |
|
49 | from .testing import test | |
58 | from .utils.sysinfo import sys_info |
|
50 | from .utils.sysinfo import sys_info | |
59 |
|
51 | |||
60 | # Release data |
|
52 | # Release data | |
61 | __author__ = '' |
|
53 | __author__ = '' | |
62 | for author, email in release.authors.itervalues(): |
|
54 | for author, email in release.authors.itervalues(): | |
63 | __author__ += author + ' <' + email + '>\n' |
|
55 | __author__ += author + ' <' + email + '>\n' | |
64 | __license__ = release.license |
|
56 | __license__ = release.license | |
65 | __version__ = release.version |
|
57 | __version__ = release.version |
@@ -1,3563 +1,3562 b'' | |||||
1 | # encoding: utf-8 |
|
1 | # encoding: utf-8 | |
2 | """Magic functions for InteractiveShell. |
|
2 | """Magic functions for InteractiveShell. | |
3 | """ |
|
3 | """ | |
4 |
|
4 | |||
5 | #----------------------------------------------------------------------------- |
|
5 | #----------------------------------------------------------------------------- | |
6 | # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and |
|
6 | # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and | |
7 | # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu> |
|
7 | # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu> | |
8 | # Copyright (C) 2008-2009 The IPython Development Team |
|
8 | # Copyright (C) 2008-2009 The IPython Development Team | |
9 |
|
9 | |||
10 | # Distributed under the terms of the BSD License. The full license is in |
|
10 | # Distributed under the terms of the BSD License. The full license is in | |
11 | # the file COPYING, distributed as part of this software. |
|
11 | # the file COPYING, distributed as part of this software. | |
12 | #----------------------------------------------------------------------------- |
|
12 | #----------------------------------------------------------------------------- | |
13 |
|
13 | |||
14 | #----------------------------------------------------------------------------- |
|
14 | #----------------------------------------------------------------------------- | |
15 | # Imports |
|
15 | # Imports | |
16 | #----------------------------------------------------------------------------- |
|
16 | #----------------------------------------------------------------------------- | |
17 |
|
17 | |||
18 | import __builtin__ |
|
18 | import __builtin__ | |
19 | import __future__ |
|
19 | import __future__ | |
20 | import bdb |
|
20 | import bdb | |
21 | import inspect |
|
21 | import inspect | |
22 | import os |
|
22 | import os | |
23 | import sys |
|
23 | import sys | |
24 | import shutil |
|
24 | import shutil | |
25 | import re |
|
25 | import re | |
26 | import time |
|
26 | import time | |
27 | import textwrap |
|
27 | import textwrap | |
28 | from cStringIO import StringIO |
|
28 | from cStringIO import StringIO | |
29 | from getopt import getopt,GetoptError |
|
29 | from getopt import getopt,GetoptError | |
30 | from pprint import pformat |
|
30 | from pprint import pformat | |
31 | from xmlrpclib import ServerProxy |
|
31 | from xmlrpclib import ServerProxy | |
32 |
|
32 | |||
33 | # cProfile was added in Python2.5 |
|
33 | # cProfile was added in Python2.5 | |
34 | try: |
|
34 | try: | |
35 | import cProfile as profile |
|
35 | import cProfile as profile | |
36 | import pstats |
|
36 | import pstats | |
37 | except ImportError: |
|
37 | except ImportError: | |
38 | # profile isn't bundled by default in Debian for license reasons |
|
38 | # profile isn't bundled by default in Debian for license reasons | |
39 | try: |
|
39 | try: | |
40 | import profile,pstats |
|
40 | import profile,pstats | |
41 | except ImportError: |
|
41 | except ImportError: | |
42 | profile = pstats = None |
|
42 | profile = pstats = None | |
43 |
|
43 | |||
44 | import IPython |
|
44 | import IPython | |
45 | from IPython.core import debugger, oinspect |
|
45 | from IPython.core import debugger, oinspect | |
46 | from IPython.core.error import TryNext |
|
46 | from IPython.core.error import TryNext | |
47 | from IPython.core.error import UsageError |
|
47 | from IPython.core.error import UsageError | |
48 | from IPython.core.fakemodule import FakeModule |
|
48 | from IPython.core.fakemodule import FakeModule | |
49 | from IPython.core.profiledir import ProfileDir |
|
49 | from IPython.core.profiledir import ProfileDir | |
50 | from IPython.core.macro import Macro |
|
50 | from IPython.core.macro import Macro | |
51 | from IPython.core import magic_arguments |
|
51 | from IPython.core import magic_arguments, page | |
52 | from IPython.core import page |
|
|||
53 | from IPython.core.prefilter import ESC_MAGIC |
|
52 | from IPython.core.prefilter import ESC_MAGIC | |
54 | from IPython.lib.pylabtools import mpl_runner |
|
53 | from IPython.lib.pylabtools import mpl_runner | |
55 | from IPython.testing.skipdoctest import skip_doctest |
|
54 | from IPython.testing.skipdoctest import skip_doctest | |
56 | from IPython.utils.io import file_read, nlprint |
|
55 | from IPython.utils.io import file_read, nlprint | |
57 | from IPython.utils.path import get_py_filename |
|
56 | from IPython.utils.path import get_py_filename | |
58 | from IPython.utils.process import arg_split, abbrev_cwd |
|
57 | from IPython.utils.process import arg_split, abbrev_cwd | |
59 | from IPython.utils.terminal import set_term_title |
|
58 | from IPython.utils.terminal import set_term_title | |
60 | from IPython.utils.text import LSString, SList, format_screen |
|
59 | from IPython.utils.text import LSString, SList, format_screen | |
61 | from IPython.utils.timing import clock, clock2 |
|
60 | from IPython.utils.timing import clock, clock2 | |
62 | from IPython.utils.warn import warn, error |
|
61 | from IPython.utils.warn import warn, error | |
63 | from IPython.utils.ipstruct import Struct |
|
62 | from IPython.utils.ipstruct import Struct | |
64 | import IPython.utils.generics |
|
63 | import IPython.utils.generics | |
65 |
|
64 | |||
66 | #----------------------------------------------------------------------------- |
|
65 | #----------------------------------------------------------------------------- | |
67 | # Utility functions |
|
66 | # Utility functions | |
68 | #----------------------------------------------------------------------------- |
|
67 | #----------------------------------------------------------------------------- | |
69 |
|
68 | |||
70 | def on_off(tag): |
|
69 | def on_off(tag): | |
71 | """Return an ON/OFF string for a 1/0 input. Simple utility function.""" |
|
70 | """Return an ON/OFF string for a 1/0 input. Simple utility function.""" | |
72 | return ['OFF','ON'][tag] |
|
71 | return ['OFF','ON'][tag] | |
73 |
|
72 | |||
74 | class Bunch: pass |
|
73 | class Bunch: pass | |
75 |
|
74 | |||
76 | def compress_dhist(dh): |
|
75 | def compress_dhist(dh): | |
77 | head, tail = dh[:-10], dh[-10:] |
|
76 | head, tail = dh[:-10], dh[-10:] | |
78 |
|
77 | |||
79 | newhead = [] |
|
78 | newhead = [] | |
80 | done = set() |
|
79 | done = set() | |
81 | for h in head: |
|
80 | for h in head: | |
82 | if h in done: |
|
81 | if h in done: | |
83 | continue |
|
82 | continue | |
84 | newhead.append(h) |
|
83 | newhead.append(h) | |
85 | done.add(h) |
|
84 | done.add(h) | |
86 |
|
85 | |||
87 | return newhead + tail |
|
86 | return newhead + tail | |
88 |
|
87 | |||
89 | def needs_local_scope(func): |
|
88 | def needs_local_scope(func): | |
90 | """Decorator to mark magic functions which need to local scope to run.""" |
|
89 | """Decorator to mark magic functions which need to local scope to run.""" | |
91 | func.needs_local_scope = True |
|
90 | func.needs_local_scope = True | |
92 | return func |
|
91 | return func | |
93 |
|
92 | |||
94 | # Used for exception handling in magic_edit |
|
93 | # Used for exception handling in magic_edit | |
95 | class MacroToEdit(ValueError): pass |
|
94 | class MacroToEdit(ValueError): pass | |
96 |
|
95 | |||
97 | #*************************************************************************** |
|
96 | #*************************************************************************** | |
98 | # Main class implementing Magic functionality |
|
97 | # Main class implementing Magic functionality | |
99 |
|
98 | |||
100 | # XXX - for some odd reason, if Magic is made a new-style class, we get errors |
|
99 | # XXX - for some odd reason, if Magic is made a new-style class, we get errors | |
101 | # on construction of the main InteractiveShell object. Something odd is going |
|
100 | # on construction of the main InteractiveShell object. Something odd is going | |
102 | # on with super() calls, Configurable and the MRO... For now leave it as-is, but |
|
101 | # on with super() calls, Configurable and the MRO... For now leave it as-is, but | |
103 | # eventually this needs to be clarified. |
|
102 | # eventually this needs to be clarified. | |
104 | # BG: This is because InteractiveShell inherits from this, but is itself a |
|
103 | # BG: This is because InteractiveShell inherits from this, but is itself a | |
105 | # Configurable. This messes up the MRO in some way. The fix is that we need to |
|
104 | # Configurable. This messes up the MRO in some way. The fix is that we need to | |
106 | # make Magic a configurable that InteractiveShell does not subclass. |
|
105 | # make Magic a configurable that InteractiveShell does not subclass. | |
107 |
|
106 | |||
108 | class Magic: |
|
107 | class Magic: | |
109 | """Magic functions for InteractiveShell. |
|
108 | """Magic functions for InteractiveShell. | |
110 |
|
109 | |||
111 | Shell functions which can be reached as %function_name. All magic |
|
110 | Shell functions which can be reached as %function_name. All magic | |
112 | functions should accept a string, which they can parse for their own |
|
111 | functions should accept a string, which they can parse for their own | |
113 | needs. This can make some functions easier to type, eg `%cd ../` |
|
112 | needs. This can make some functions easier to type, eg `%cd ../` | |
114 | vs. `%cd("../")` |
|
113 | vs. `%cd("../")` | |
115 |
|
114 | |||
116 | ALL definitions MUST begin with the prefix magic_. The user won't need it |
|
115 | ALL definitions MUST begin with the prefix magic_. The user won't need it | |
117 | at the command line, but it is is needed in the definition. """ |
|
116 | at the command line, but it is is needed in the definition. """ | |
118 |
|
117 | |||
119 | # class globals |
|
118 | # class globals | |
120 | auto_status = ['Automagic is OFF, % prefix IS needed for magic functions.', |
|
119 | auto_status = ['Automagic is OFF, % prefix IS needed for magic functions.', | |
121 | 'Automagic is ON, % prefix NOT needed for magic functions.'] |
|
120 | 'Automagic is ON, % prefix NOT needed for magic functions.'] | |
122 |
|
121 | |||
123 | #...................................................................... |
|
122 | #...................................................................... | |
124 | # some utility functions |
|
123 | # some utility functions | |
125 |
|
124 | |||
126 | def __init__(self,shell): |
|
125 | def __init__(self,shell): | |
127 |
|
126 | |||
128 | self.options_table = {} |
|
127 | self.options_table = {} | |
129 | if profile is None: |
|
128 | if profile is None: | |
130 | self.magic_prun = self.profile_missing_notice |
|
129 | self.magic_prun = self.profile_missing_notice | |
131 | self.shell = shell |
|
130 | self.shell = shell | |
132 |
|
131 | |||
133 | # namespace for holding state we may need |
|
132 | # namespace for holding state we may need | |
134 | self._magic_state = Bunch() |
|
133 | self._magic_state = Bunch() | |
135 |
|
134 | |||
136 | def profile_missing_notice(self, *args, **kwargs): |
|
135 | def profile_missing_notice(self, *args, **kwargs): | |
137 | error("""\ |
|
136 | error("""\ | |
138 | The profile module could not be found. It has been removed from the standard |
|
137 | The profile module could not be found. It has been removed from the standard | |
139 | python packages because of its non-free license. To use profiling, install the |
|
138 | python packages because of its non-free license. To use profiling, install the | |
140 | python-profiler package from non-free.""") |
|
139 | python-profiler package from non-free.""") | |
141 |
|
140 | |||
142 | def default_option(self,fn,optstr): |
|
141 | def default_option(self,fn,optstr): | |
143 | """Make an entry in the options_table for fn, with value optstr""" |
|
142 | """Make an entry in the options_table for fn, with value optstr""" | |
144 |
|
143 | |||
145 | if fn not in self.lsmagic(): |
|
144 | if fn not in self.lsmagic(): | |
146 | error("%s is not a magic function" % fn) |
|
145 | error("%s is not a magic function" % fn) | |
147 | self.options_table[fn] = optstr |
|
146 | self.options_table[fn] = optstr | |
148 |
|
147 | |||
149 | def lsmagic(self): |
|
148 | def lsmagic(self): | |
150 | """Return a list of currently available magic functions. |
|
149 | """Return a list of currently available magic functions. | |
151 |
|
150 | |||
152 | Gives a list of the bare names after mangling (['ls','cd', ...], not |
|
151 | Gives a list of the bare names after mangling (['ls','cd', ...], not | |
153 | ['magic_ls','magic_cd',...]""" |
|
152 | ['magic_ls','magic_cd',...]""" | |
154 |
|
153 | |||
155 | # FIXME. This needs a cleanup, in the way the magics list is built. |
|
154 | # FIXME. This needs a cleanup, in the way the magics list is built. | |
156 |
|
155 | |||
157 | # magics in class definition |
|
156 | # magics in class definition | |
158 | class_magic = lambda fn: fn.startswith('magic_') and \ |
|
157 | class_magic = lambda fn: fn.startswith('magic_') and \ | |
159 | callable(Magic.__dict__[fn]) |
|
158 | callable(Magic.__dict__[fn]) | |
160 | # in instance namespace (run-time user additions) |
|
159 | # in instance namespace (run-time user additions) | |
161 | inst_magic = lambda fn: fn.startswith('magic_') and \ |
|
160 | inst_magic = lambda fn: fn.startswith('magic_') and \ | |
162 | callable(self.__dict__[fn]) |
|
161 | callable(self.__dict__[fn]) | |
163 | # and bound magics by user (so they can access self): |
|
162 | # and bound magics by user (so they can access self): | |
164 | inst_bound_magic = lambda fn: fn.startswith('magic_') and \ |
|
163 | inst_bound_magic = lambda fn: fn.startswith('magic_') and \ | |
165 | callable(self.__class__.__dict__[fn]) |
|
164 | callable(self.__class__.__dict__[fn]) | |
166 | magics = filter(class_magic,Magic.__dict__.keys()) + \ |
|
165 | magics = filter(class_magic,Magic.__dict__.keys()) + \ | |
167 | filter(inst_magic,self.__dict__.keys()) + \ |
|
166 | filter(inst_magic,self.__dict__.keys()) + \ | |
168 | filter(inst_bound_magic,self.__class__.__dict__.keys()) |
|
167 | filter(inst_bound_magic,self.__class__.__dict__.keys()) | |
169 | out = [] |
|
168 | out = [] | |
170 | for fn in set(magics): |
|
169 | for fn in set(magics): | |
171 | out.append(fn.replace('magic_','',1)) |
|
170 | out.append(fn.replace('magic_','',1)) | |
172 | out.sort() |
|
171 | out.sort() | |
173 | return out |
|
172 | return out | |
174 |
|
173 | |||
175 | def extract_input_lines(self, range_str, raw=False): |
|
174 | def extract_input_lines(self, range_str, raw=False): | |
176 | """Return as a string a set of input history slices. |
|
175 | """Return as a string a set of input history slices. | |
177 |
|
176 | |||
178 | Inputs: |
|
177 | Inputs: | |
179 |
|
178 | |||
180 | - range_str: the set of slices is given as a string, like |
|
179 | - range_str: the set of slices is given as a string, like | |
181 | "~5/6-~4/2 4:8 9", since this function is for use by magic functions |
|
180 | "~5/6-~4/2 4:8 9", since this function is for use by magic functions | |
182 | which get their arguments as strings. The number before the / is the |
|
181 | which get their arguments as strings. The number before the / is the | |
183 | session number: ~n goes n back from the current session. |
|
182 | session number: ~n goes n back from the current session. | |
184 |
|
183 | |||
185 | Optional inputs: |
|
184 | Optional inputs: | |
186 |
|
185 | |||
187 | - raw(False): by default, the processed input is used. If this is |
|
186 | - raw(False): by default, the processed input is used. If this is | |
188 | true, the raw input history is used instead. |
|
187 | true, the raw input history is used instead. | |
189 |
|
188 | |||
190 | Note that slices can be called with two notations: |
|
189 | Note that slices can be called with two notations: | |
191 |
|
190 | |||
192 | N:M -> standard python form, means including items N...(M-1). |
|
191 | N:M -> standard python form, means including items N...(M-1). | |
193 |
|
192 | |||
194 | N-M -> include items N..M (closed endpoint).""" |
|
193 | N-M -> include items N..M (closed endpoint).""" | |
195 | lines = self.shell.history_manager.\ |
|
194 | lines = self.shell.history_manager.\ | |
196 | get_range_by_str(range_str, raw=raw) |
|
195 | get_range_by_str(range_str, raw=raw) | |
197 | return "\n".join(x for _, _, x in lines) |
|
196 | return "\n".join(x for _, _, x in lines) | |
198 |
|
197 | |||
199 | def arg_err(self,func): |
|
198 | def arg_err(self,func): | |
200 | """Print docstring if incorrect arguments were passed""" |
|
199 | """Print docstring if incorrect arguments were passed""" | |
201 | print 'Error in arguments:' |
|
200 | print 'Error in arguments:' | |
202 | print oinspect.getdoc(func) |
|
201 | print oinspect.getdoc(func) | |
203 |
|
202 | |||
204 | def format_latex(self,strng): |
|
203 | def format_latex(self,strng): | |
205 | """Format a string for latex inclusion.""" |
|
204 | """Format a string for latex inclusion.""" | |
206 |
|
205 | |||
207 | # Characters that need to be escaped for latex: |
|
206 | # Characters that need to be escaped for latex: | |
208 | escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE) |
|
207 | escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE) | |
209 | # Magic command names as headers: |
|
208 | # Magic command names as headers: | |
210 | cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC, |
|
209 | cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC, | |
211 | re.MULTILINE) |
|
210 | re.MULTILINE) | |
212 | # Magic commands |
|
211 | # Magic commands | |
213 | cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC, |
|
212 | cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC, | |
214 | re.MULTILINE) |
|
213 | re.MULTILINE) | |
215 | # Paragraph continue |
|
214 | # Paragraph continue | |
216 | par_re = re.compile(r'\\$',re.MULTILINE) |
|
215 | par_re = re.compile(r'\\$',re.MULTILINE) | |
217 |
|
216 | |||
218 | # The "\n" symbol |
|
217 | # The "\n" symbol | |
219 | newline_re = re.compile(r'\\n') |
|
218 | newline_re = re.compile(r'\\n') | |
220 |
|
219 | |||
221 | # Now build the string for output: |
|
220 | # Now build the string for output: | |
222 | #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng) |
|
221 | #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng) | |
223 | strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:', |
|
222 | strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:', | |
224 | strng) |
|
223 | strng) | |
225 | strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng) |
|
224 | strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng) | |
226 | strng = par_re.sub(r'\\\\',strng) |
|
225 | strng = par_re.sub(r'\\\\',strng) | |
227 | strng = escape_re.sub(r'\\\1',strng) |
|
226 | strng = escape_re.sub(r'\\\1',strng) | |
228 | strng = newline_re.sub(r'\\textbackslash{}n',strng) |
|
227 | strng = newline_re.sub(r'\\textbackslash{}n',strng) | |
229 | return strng |
|
228 | return strng | |
230 |
|
229 | |||
231 | def parse_options(self,arg_str,opt_str,*long_opts,**kw): |
|
230 | def parse_options(self,arg_str,opt_str,*long_opts,**kw): | |
232 | """Parse options passed to an argument string. |
|
231 | """Parse options passed to an argument string. | |
233 |
|
232 | |||
234 | The interface is similar to that of getopt(), but it returns back a |
|
233 | The interface is similar to that of getopt(), but it returns back a | |
235 | Struct with the options as keys and the stripped argument string still |
|
234 | Struct with the options as keys and the stripped argument string still | |
236 | as a string. |
|
235 | as a string. | |
237 |
|
236 | |||
238 | arg_str is quoted as a true sys.argv vector by using shlex.split. |
|
237 | arg_str is quoted as a true sys.argv vector by using shlex.split. | |
239 | This allows us to easily expand variables, glob files, quote |
|
238 | This allows us to easily expand variables, glob files, quote | |
240 | arguments, etc. |
|
239 | arguments, etc. | |
241 |
|
240 | |||
242 | Options: |
|
241 | Options: | |
243 | -mode: default 'string'. If given as 'list', the argument string is |
|
242 | -mode: default 'string'. If given as 'list', the argument string is | |
244 | returned as a list (split on whitespace) instead of a string. |
|
243 | returned as a list (split on whitespace) instead of a string. | |
245 |
|
244 | |||
246 | -list_all: put all option values in lists. Normally only options |
|
245 | -list_all: put all option values in lists. Normally only options | |
247 | appearing more than once are put in a list. |
|
246 | appearing more than once are put in a list. | |
248 |
|
247 | |||
249 | -posix (True): whether to split the input line in POSIX mode or not, |
|
248 | -posix (True): whether to split the input line in POSIX mode or not, | |
250 | as per the conventions outlined in the shlex module from the |
|
249 | as per the conventions outlined in the shlex module from the | |
251 | standard library.""" |
|
250 | standard library.""" | |
252 |
|
251 | |||
253 | # inject default options at the beginning of the input line |
|
252 | # inject default options at the beginning of the input line | |
254 | caller = sys._getframe(1).f_code.co_name.replace('magic_','') |
|
253 | caller = sys._getframe(1).f_code.co_name.replace('magic_','') | |
255 | arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str) |
|
254 | arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str) | |
256 |
|
255 | |||
257 | mode = kw.get('mode','string') |
|
256 | mode = kw.get('mode','string') | |
258 | if mode not in ['string','list']: |
|
257 | if mode not in ['string','list']: | |
259 | raise ValueError,'incorrect mode given: %s' % mode |
|
258 | raise ValueError,'incorrect mode given: %s' % mode | |
260 | # Get options |
|
259 | # Get options | |
261 | list_all = kw.get('list_all',0) |
|
260 | list_all = kw.get('list_all',0) | |
262 | posix = kw.get('posix', os.name == 'posix') |
|
261 | posix = kw.get('posix', os.name == 'posix') | |
263 |
|
262 | |||
264 | # Check if we have more than one argument to warrant extra processing: |
|
263 | # Check if we have more than one argument to warrant extra processing: | |
265 | odict = {} # Dictionary with options |
|
264 | odict = {} # Dictionary with options | |
266 | args = arg_str.split() |
|
265 | args = arg_str.split() | |
267 | if len(args) >= 1: |
|
266 | if len(args) >= 1: | |
268 | # If the list of inputs only has 0 or 1 thing in it, there's no |
|
267 | # If the list of inputs only has 0 or 1 thing in it, there's no | |
269 | # need to look for options |
|
268 | # need to look for options | |
270 | argv = arg_split(arg_str,posix) |
|
269 | argv = arg_split(arg_str,posix) | |
271 | # Do regular option processing |
|
270 | # Do regular option processing | |
272 | try: |
|
271 | try: | |
273 | opts,args = getopt(argv,opt_str,*long_opts) |
|
272 | opts,args = getopt(argv,opt_str,*long_opts) | |
274 | except GetoptError,e: |
|
273 | except GetoptError,e: | |
275 | raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str, |
|
274 | raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str, | |
276 | " ".join(long_opts))) |
|
275 | " ".join(long_opts))) | |
277 | for o,a in opts: |
|
276 | for o,a in opts: | |
278 | if o.startswith('--'): |
|
277 | if o.startswith('--'): | |
279 | o = o[2:] |
|
278 | o = o[2:] | |
280 | else: |
|
279 | else: | |
281 | o = o[1:] |
|
280 | o = o[1:] | |
282 | try: |
|
281 | try: | |
283 | odict[o].append(a) |
|
282 | odict[o].append(a) | |
284 | except AttributeError: |
|
283 | except AttributeError: | |
285 | odict[o] = [odict[o],a] |
|
284 | odict[o] = [odict[o],a] | |
286 | except KeyError: |
|
285 | except KeyError: | |
287 | if list_all: |
|
286 | if list_all: | |
288 | odict[o] = [a] |
|
287 | odict[o] = [a] | |
289 | else: |
|
288 | else: | |
290 | odict[o] = a |
|
289 | odict[o] = a | |
291 |
|
290 | |||
292 | # Prepare opts,args for return |
|
291 | # Prepare opts,args for return | |
293 | opts = Struct(odict) |
|
292 | opts = Struct(odict) | |
294 | if mode == 'string': |
|
293 | if mode == 'string': | |
295 | args = ' '.join(args) |
|
294 | args = ' '.join(args) | |
296 |
|
295 | |||
297 | return opts,args |
|
296 | return opts,args | |
298 |
|
297 | |||
299 | #...................................................................... |
|
298 | #...................................................................... | |
300 | # And now the actual magic functions |
|
299 | # And now the actual magic functions | |
301 |
|
300 | |||
302 | # Functions for IPython shell work (vars,funcs, config, etc) |
|
301 | # Functions for IPython shell work (vars,funcs, config, etc) | |
303 | def magic_lsmagic(self, parameter_s = ''): |
|
302 | def magic_lsmagic(self, parameter_s = ''): | |
304 | """List currently available magic functions.""" |
|
303 | """List currently available magic functions.""" | |
305 | mesc = ESC_MAGIC |
|
304 | mesc = ESC_MAGIC | |
306 | print 'Available magic functions:\n'+mesc+\ |
|
305 | print 'Available magic functions:\n'+mesc+\ | |
307 | (' '+mesc).join(self.lsmagic()) |
|
306 | (' '+mesc).join(self.lsmagic()) | |
308 | print '\n' + Magic.auto_status[self.shell.automagic] |
|
307 | print '\n' + Magic.auto_status[self.shell.automagic] | |
309 | return None |
|
308 | return None | |
310 |
|
309 | |||
311 | def magic_magic(self, parameter_s = ''): |
|
310 | def magic_magic(self, parameter_s = ''): | |
312 | """Print information about the magic function system. |
|
311 | """Print information about the magic function system. | |
313 |
|
312 | |||
314 | Supported formats: -latex, -brief, -rest |
|
313 | Supported formats: -latex, -brief, -rest | |
315 | """ |
|
314 | """ | |
316 |
|
315 | |||
317 | mode = '' |
|
316 | mode = '' | |
318 | try: |
|
317 | try: | |
319 | if parameter_s.split()[0] == '-latex': |
|
318 | if parameter_s.split()[0] == '-latex': | |
320 | mode = 'latex' |
|
319 | mode = 'latex' | |
321 | if parameter_s.split()[0] == '-brief': |
|
320 | if parameter_s.split()[0] == '-brief': | |
322 | mode = 'brief' |
|
321 | mode = 'brief' | |
323 | if parameter_s.split()[0] == '-rest': |
|
322 | if parameter_s.split()[0] == '-rest': | |
324 | mode = 'rest' |
|
323 | mode = 'rest' | |
325 | rest_docs = [] |
|
324 | rest_docs = [] | |
326 | except: |
|
325 | except: | |
327 | pass |
|
326 | pass | |
328 |
|
327 | |||
329 | magic_docs = [] |
|
328 | magic_docs = [] | |
330 | for fname in self.lsmagic(): |
|
329 | for fname in self.lsmagic(): | |
331 | mname = 'magic_' + fname |
|
330 | mname = 'magic_' + fname | |
332 | for space in (Magic,self,self.__class__): |
|
331 | for space in (Magic,self,self.__class__): | |
333 | try: |
|
332 | try: | |
334 | fn = space.__dict__[mname] |
|
333 | fn = space.__dict__[mname] | |
335 | except KeyError: |
|
334 | except KeyError: | |
336 | pass |
|
335 | pass | |
337 | else: |
|
336 | else: | |
338 | break |
|
337 | break | |
339 | if mode == 'brief': |
|
338 | if mode == 'brief': | |
340 | # only first line |
|
339 | # only first line | |
341 | if fn.__doc__: |
|
340 | if fn.__doc__: | |
342 | fndoc = fn.__doc__.split('\n',1)[0] |
|
341 | fndoc = fn.__doc__.split('\n',1)[0] | |
343 | else: |
|
342 | else: | |
344 | fndoc = 'No documentation' |
|
343 | fndoc = 'No documentation' | |
345 | else: |
|
344 | else: | |
346 | if fn.__doc__: |
|
345 | if fn.__doc__: | |
347 | fndoc = fn.__doc__.rstrip() |
|
346 | fndoc = fn.__doc__.rstrip() | |
348 | else: |
|
347 | else: | |
349 | fndoc = 'No documentation' |
|
348 | fndoc = 'No documentation' | |
350 |
|
349 | |||
351 |
|
350 | |||
352 | if mode == 'rest': |
|
351 | if mode == 'rest': | |
353 | rest_docs.append('**%s%s**::\n\n\t%s\n\n' %(ESC_MAGIC, |
|
352 | rest_docs.append('**%s%s**::\n\n\t%s\n\n' %(ESC_MAGIC, | |
354 | fname,fndoc)) |
|
353 | fname,fndoc)) | |
355 |
|
354 | |||
356 | else: |
|
355 | else: | |
357 | magic_docs.append('%s%s:\n\t%s\n' %(ESC_MAGIC, |
|
356 | magic_docs.append('%s%s:\n\t%s\n' %(ESC_MAGIC, | |
358 | fname,fndoc)) |
|
357 | fname,fndoc)) | |
359 |
|
358 | |||
360 | magic_docs = ''.join(magic_docs) |
|
359 | magic_docs = ''.join(magic_docs) | |
361 |
|
360 | |||
362 | if mode == 'rest': |
|
361 | if mode == 'rest': | |
363 | return "".join(rest_docs) |
|
362 | return "".join(rest_docs) | |
364 |
|
363 | |||
365 | if mode == 'latex': |
|
364 | if mode == 'latex': | |
366 | print self.format_latex(magic_docs) |
|
365 | print self.format_latex(magic_docs) | |
367 | return |
|
366 | return | |
368 | else: |
|
367 | else: | |
369 | magic_docs = format_screen(magic_docs) |
|
368 | magic_docs = format_screen(magic_docs) | |
370 | if mode == 'brief': |
|
369 | if mode == 'brief': | |
371 | return magic_docs |
|
370 | return magic_docs | |
372 |
|
371 | |||
373 | outmsg = """ |
|
372 | outmsg = """ | |
374 | IPython's 'magic' functions |
|
373 | IPython's 'magic' functions | |
375 | =========================== |
|
374 | =========================== | |
376 |
|
375 | |||
377 | The magic function system provides a series of functions which allow you to |
|
376 | The magic function system provides a series of functions which allow you to | |
378 | control the behavior of IPython itself, plus a lot of system-type |
|
377 | control the behavior of IPython itself, plus a lot of system-type | |
379 | features. All these functions are prefixed with a % character, but parameters |
|
378 | features. All these functions are prefixed with a % character, but parameters | |
380 | are given without parentheses or quotes. |
|
379 | are given without parentheses or quotes. | |
381 |
|
380 | |||
382 | NOTE: If you have 'automagic' enabled (via the command line option or with the |
|
381 | NOTE: If you have 'automagic' enabled (via the command line option or with the | |
383 | %automagic function), you don't need to type in the % explicitly. By default, |
|
382 | %automagic function), you don't need to type in the % explicitly. By default, | |
384 | IPython ships with automagic on, so you should only rarely need the % escape. |
|
383 | IPython ships with automagic on, so you should only rarely need the % escape. | |
385 |
|
384 | |||
386 | Example: typing '%cd mydir' (without the quotes) changes you working directory |
|
385 | Example: typing '%cd mydir' (without the quotes) changes you working directory | |
387 | to 'mydir', if it exists. |
|
386 | to 'mydir', if it exists. | |
388 |
|
387 | |||
389 | For a list of the available magic functions, use %lsmagic. For a description |
|
388 | For a list of the available magic functions, use %lsmagic. For a description | |
390 | of any of them, type %magic_name?, e.g. '%cd?'. |
|
389 | of any of them, type %magic_name?, e.g. '%cd?'. | |
391 |
|
390 | |||
392 | Currently the magic system has the following functions:\n""" |
|
391 | Currently the magic system has the following functions:\n""" | |
393 |
|
392 | |||
394 | mesc = ESC_MAGIC |
|
393 | mesc = ESC_MAGIC | |
395 | outmsg = ("%s\n%s\n\nSummary of magic functions (from %slsmagic):" |
|
394 | outmsg = ("%s\n%s\n\nSummary of magic functions (from %slsmagic):" | |
396 | "\n\n%s%s\n\n%s" % (outmsg, |
|
395 | "\n\n%s%s\n\n%s" % (outmsg, | |
397 | magic_docs,mesc,mesc, |
|
396 | magic_docs,mesc,mesc, | |
398 | (' '+mesc).join(self.lsmagic()), |
|
397 | (' '+mesc).join(self.lsmagic()), | |
399 | Magic.auto_status[self.shell.automagic] ) ) |
|
398 | Magic.auto_status[self.shell.automagic] ) ) | |
400 | page.page(outmsg) |
|
399 | page.page(outmsg) | |
401 |
|
400 | |||
402 | def magic_automagic(self, parameter_s = ''): |
|
401 | def magic_automagic(self, parameter_s = ''): | |
403 | """Make magic functions callable without having to type the initial %. |
|
402 | """Make magic functions callable without having to type the initial %. | |
404 |
|
403 | |||
405 | Without argumentsl toggles on/off (when off, you must call it as |
|
404 | Without argumentsl toggles on/off (when off, you must call it as | |
406 | %automagic, of course). With arguments it sets the value, and you can |
|
405 | %automagic, of course). With arguments it sets the value, and you can | |
407 | use any of (case insensitive): |
|
406 | use any of (case insensitive): | |
408 |
|
407 | |||
409 | - on,1,True: to activate |
|
408 | - on,1,True: to activate | |
410 |
|
409 | |||
411 | - off,0,False: to deactivate. |
|
410 | - off,0,False: to deactivate. | |
412 |
|
411 | |||
413 | Note that magic functions have lowest priority, so if there's a |
|
412 | Note that magic functions have lowest priority, so if there's a | |
414 | variable whose name collides with that of a magic fn, automagic won't |
|
413 | variable whose name collides with that of a magic fn, automagic won't | |
415 | work for that function (you get the variable instead). However, if you |
|
414 | work for that function (you get the variable instead). However, if you | |
416 | delete the variable (del var), the previously shadowed magic function |
|
415 | delete the variable (del var), the previously shadowed magic function | |
417 | becomes visible to automagic again.""" |
|
416 | becomes visible to automagic again.""" | |
418 |
|
417 | |||
419 | arg = parameter_s.lower() |
|
418 | arg = parameter_s.lower() | |
420 | if parameter_s in ('on','1','true'): |
|
419 | if parameter_s in ('on','1','true'): | |
421 | self.shell.automagic = True |
|
420 | self.shell.automagic = True | |
422 | elif parameter_s in ('off','0','false'): |
|
421 | elif parameter_s in ('off','0','false'): | |
423 | self.shell.automagic = False |
|
422 | self.shell.automagic = False | |
424 | else: |
|
423 | else: | |
425 | self.shell.automagic = not self.shell.automagic |
|
424 | self.shell.automagic = not self.shell.automagic | |
426 | print '\n' + Magic.auto_status[self.shell.automagic] |
|
425 | print '\n' + Magic.auto_status[self.shell.automagic] | |
427 |
|
426 | |||
428 | @skip_doctest |
|
427 | @skip_doctest | |
429 | def magic_autocall(self, parameter_s = ''): |
|
428 | def magic_autocall(self, parameter_s = ''): | |
430 | """Make functions callable without having to type parentheses. |
|
429 | """Make functions callable without having to type parentheses. | |
431 |
|
430 | |||
432 | Usage: |
|
431 | Usage: | |
433 |
|
432 | |||
434 | %autocall [mode] |
|
433 | %autocall [mode] | |
435 |
|
434 | |||
436 | The mode can be one of: 0->Off, 1->Smart, 2->Full. If not given, the |
|
435 | The mode can be one of: 0->Off, 1->Smart, 2->Full. If not given, the | |
437 | value is toggled on and off (remembering the previous state). |
|
436 | value is toggled on and off (remembering the previous state). | |
438 |
|
437 | |||
439 | In more detail, these values mean: |
|
438 | In more detail, these values mean: | |
440 |
|
439 | |||
441 | 0 -> fully disabled |
|
440 | 0 -> fully disabled | |
442 |
|
441 | |||
443 | 1 -> active, but do not apply if there are no arguments on the line. |
|
442 | 1 -> active, but do not apply if there are no arguments on the line. | |
444 |
|
443 | |||
445 | In this mode, you get: |
|
444 | In this mode, you get: | |
446 |
|
445 | |||
447 | In [1]: callable |
|
446 | In [1]: callable | |
448 | Out[1]: <built-in function callable> |
|
447 | Out[1]: <built-in function callable> | |
449 |
|
448 | |||
450 | In [2]: callable 'hello' |
|
449 | In [2]: callable 'hello' | |
451 | ------> callable('hello') |
|
450 | ------> callable('hello') | |
452 | Out[2]: False |
|
451 | Out[2]: False | |
453 |
|
452 | |||
454 | 2 -> Active always. Even if no arguments are present, the callable |
|
453 | 2 -> Active always. Even if no arguments are present, the callable | |
455 | object is called: |
|
454 | object is called: | |
456 |
|
455 | |||
457 | In [2]: float |
|
456 | In [2]: float | |
458 | ------> float() |
|
457 | ------> float() | |
459 | Out[2]: 0.0 |
|
458 | Out[2]: 0.0 | |
460 |
|
459 | |||
461 | Note that even with autocall off, you can still use '/' at the start of |
|
460 | Note that even with autocall off, you can still use '/' at the start of | |
462 | a line to treat the first argument on the command line as a function |
|
461 | a line to treat the first argument on the command line as a function | |
463 | and add parentheses to it: |
|
462 | and add parentheses to it: | |
464 |
|
463 | |||
465 | In [8]: /str 43 |
|
464 | In [8]: /str 43 | |
466 | ------> str(43) |
|
465 | ------> str(43) | |
467 | Out[8]: '43' |
|
466 | Out[8]: '43' | |
468 |
|
467 | |||
469 | # all-random (note for auto-testing) |
|
468 | # all-random (note for auto-testing) | |
470 | """ |
|
469 | """ | |
471 |
|
470 | |||
472 | if parameter_s: |
|
471 | if parameter_s: | |
473 | arg = int(parameter_s) |
|
472 | arg = int(parameter_s) | |
474 | else: |
|
473 | else: | |
475 | arg = 'toggle' |
|
474 | arg = 'toggle' | |
476 |
|
475 | |||
477 | if not arg in (0,1,2,'toggle'): |
|
476 | if not arg in (0,1,2,'toggle'): | |
478 | error('Valid modes: (0->Off, 1->Smart, 2->Full') |
|
477 | error('Valid modes: (0->Off, 1->Smart, 2->Full') | |
479 | return |
|
478 | return | |
480 |
|
479 | |||
481 | if arg in (0,1,2): |
|
480 | if arg in (0,1,2): | |
482 | self.shell.autocall = arg |
|
481 | self.shell.autocall = arg | |
483 | else: # toggle |
|
482 | else: # toggle | |
484 | if self.shell.autocall: |
|
483 | if self.shell.autocall: | |
485 | self._magic_state.autocall_save = self.shell.autocall |
|
484 | self._magic_state.autocall_save = self.shell.autocall | |
486 | self.shell.autocall = 0 |
|
485 | self.shell.autocall = 0 | |
487 | else: |
|
486 | else: | |
488 | try: |
|
487 | try: | |
489 | self.shell.autocall = self._magic_state.autocall_save |
|
488 | self.shell.autocall = self._magic_state.autocall_save | |
490 | except AttributeError: |
|
489 | except AttributeError: | |
491 | self.shell.autocall = self._magic_state.autocall_save = 1 |
|
490 | self.shell.autocall = self._magic_state.autocall_save = 1 | |
492 |
|
491 | |||
493 | print "Automatic calling is:",['OFF','Smart','Full'][self.shell.autocall] |
|
492 | print "Automatic calling is:",['OFF','Smart','Full'][self.shell.autocall] | |
494 |
|
493 | |||
495 |
|
494 | |||
496 | def magic_page(self, parameter_s=''): |
|
495 | def magic_page(self, parameter_s=''): | |
497 | """Pretty print the object and display it through a pager. |
|
496 | """Pretty print the object and display it through a pager. | |
498 |
|
497 | |||
499 | %page [options] OBJECT |
|
498 | %page [options] OBJECT | |
500 |
|
499 | |||
501 | If no object is given, use _ (last output). |
|
500 | If no object is given, use _ (last output). | |
502 |
|
501 | |||
503 | Options: |
|
502 | Options: | |
504 |
|
503 | |||
505 | -r: page str(object), don't pretty-print it.""" |
|
504 | -r: page str(object), don't pretty-print it.""" | |
506 |
|
505 | |||
507 | # After a function contributed by Olivier Aubert, slightly modified. |
|
506 | # After a function contributed by Olivier Aubert, slightly modified. | |
508 |
|
507 | |||
509 | # Process options/args |
|
508 | # Process options/args | |
510 | opts,args = self.parse_options(parameter_s,'r') |
|
509 | opts,args = self.parse_options(parameter_s,'r') | |
511 | raw = 'r' in opts |
|
510 | raw = 'r' in opts | |
512 |
|
511 | |||
513 | oname = args and args or '_' |
|
512 | oname = args and args or '_' | |
514 | info = self._ofind(oname) |
|
513 | info = self._ofind(oname) | |
515 | if info['found']: |
|
514 | if info['found']: | |
516 | txt = (raw and str or pformat)( info['obj'] ) |
|
515 | txt = (raw and str or pformat)( info['obj'] ) | |
517 | page.page(txt) |
|
516 | page.page(txt) | |
518 | else: |
|
517 | else: | |
519 | print 'Object `%s` not found' % oname |
|
518 | print 'Object `%s` not found' % oname | |
520 |
|
519 | |||
521 | def magic_profile(self, parameter_s=''): |
|
520 | def magic_profile(self, parameter_s=''): | |
522 | """Print your currently active IPython profile.""" |
|
521 | """Print your currently active IPython profile.""" | |
523 | print self.shell.profile |
|
522 | print self.shell.profile | |
524 |
|
523 | |||
525 | def magic_pinfo(self, parameter_s='', namespaces=None): |
|
524 | def magic_pinfo(self, parameter_s='', namespaces=None): | |
526 | """Provide detailed information about an object. |
|
525 | """Provide detailed information about an object. | |
527 |
|
526 | |||
528 | '%pinfo object' is just a synonym for object? or ?object.""" |
|
527 | '%pinfo object' is just a synonym for object? or ?object.""" | |
529 |
|
528 | |||
530 | #print 'pinfo par: <%s>' % parameter_s # dbg |
|
529 | #print 'pinfo par: <%s>' % parameter_s # dbg | |
531 |
|
530 | |||
532 |
|
531 | |||
533 | # detail_level: 0 -> obj? , 1 -> obj?? |
|
532 | # detail_level: 0 -> obj? , 1 -> obj?? | |
534 | detail_level = 0 |
|
533 | detail_level = 0 | |
535 | # We need to detect if we got called as 'pinfo pinfo foo', which can |
|
534 | # We need to detect if we got called as 'pinfo pinfo foo', which can | |
536 | # happen if the user types 'pinfo foo?' at the cmd line. |
|
535 | # happen if the user types 'pinfo foo?' at the cmd line. | |
537 | pinfo,qmark1,oname,qmark2 = \ |
|
536 | pinfo,qmark1,oname,qmark2 = \ | |
538 | re.match('(pinfo )?(\?*)(.*?)(\??$)',parameter_s).groups() |
|
537 | re.match('(pinfo )?(\?*)(.*?)(\??$)',parameter_s).groups() | |
539 | if pinfo or qmark1 or qmark2: |
|
538 | if pinfo or qmark1 or qmark2: | |
540 | detail_level = 1 |
|
539 | detail_level = 1 | |
541 | if "*" in oname: |
|
540 | if "*" in oname: | |
542 | self.magic_psearch(oname) |
|
541 | self.magic_psearch(oname) | |
543 | else: |
|
542 | else: | |
544 | self.shell._inspect('pinfo', oname, detail_level=detail_level, |
|
543 | self.shell._inspect('pinfo', oname, detail_level=detail_level, | |
545 | namespaces=namespaces) |
|
544 | namespaces=namespaces) | |
546 |
|
545 | |||
547 | def magic_pinfo2(self, parameter_s='', namespaces=None): |
|
546 | def magic_pinfo2(self, parameter_s='', namespaces=None): | |
548 | """Provide extra detailed information about an object. |
|
547 | """Provide extra detailed information about an object. | |
549 |
|
548 | |||
550 | '%pinfo2 object' is just a synonym for object?? or ??object.""" |
|
549 | '%pinfo2 object' is just a synonym for object?? or ??object.""" | |
551 | self.shell._inspect('pinfo', parameter_s, detail_level=1, |
|
550 | self.shell._inspect('pinfo', parameter_s, detail_level=1, | |
552 | namespaces=namespaces) |
|
551 | namespaces=namespaces) | |
553 |
|
552 | |||
554 | @skip_doctest |
|
553 | @skip_doctest | |
555 | def magic_pdef(self, parameter_s='', namespaces=None): |
|
554 | def magic_pdef(self, parameter_s='', namespaces=None): | |
556 | """Print the definition header for any callable object. |
|
555 | """Print the definition header for any callable object. | |
557 |
|
556 | |||
558 | If the object is a class, print the constructor information. |
|
557 | If the object is a class, print the constructor information. | |
559 |
|
558 | |||
560 | Examples |
|
559 | Examples | |
561 | -------- |
|
560 | -------- | |
562 | :: |
|
561 | :: | |
563 |
|
562 | |||
564 | In [3]: %pdef urllib.urlopen |
|
563 | In [3]: %pdef urllib.urlopen | |
565 | urllib.urlopen(url, data=None, proxies=None) |
|
564 | urllib.urlopen(url, data=None, proxies=None) | |
566 | """ |
|
565 | """ | |
567 | self._inspect('pdef',parameter_s, namespaces) |
|
566 | self._inspect('pdef',parameter_s, namespaces) | |
568 |
|
567 | |||
569 | def magic_pdoc(self, parameter_s='', namespaces=None): |
|
568 | def magic_pdoc(self, parameter_s='', namespaces=None): | |
570 | """Print the docstring for an object. |
|
569 | """Print the docstring for an object. | |
571 |
|
570 | |||
572 | If the given object is a class, it will print both the class and the |
|
571 | If the given object is a class, it will print both the class and the | |
573 | constructor docstrings.""" |
|
572 | constructor docstrings.""" | |
574 | self._inspect('pdoc',parameter_s, namespaces) |
|
573 | self._inspect('pdoc',parameter_s, namespaces) | |
575 |
|
574 | |||
576 | def magic_psource(self, parameter_s='', namespaces=None): |
|
575 | def magic_psource(self, parameter_s='', namespaces=None): | |
577 | """Print (or run through pager) the source code for an object.""" |
|
576 | """Print (or run through pager) the source code for an object.""" | |
578 | self._inspect('psource',parameter_s, namespaces) |
|
577 | self._inspect('psource',parameter_s, namespaces) | |
579 |
|
578 | |||
580 | def magic_pfile(self, parameter_s=''): |
|
579 | def magic_pfile(self, parameter_s=''): | |
581 | """Print (or run through pager) the file where an object is defined. |
|
580 | """Print (or run through pager) the file where an object is defined. | |
582 |
|
581 | |||
583 | The file opens at the line where the object definition begins. IPython |
|
582 | The file opens at the line where the object definition begins. IPython | |
584 | will honor the environment variable PAGER if set, and otherwise will |
|
583 | will honor the environment variable PAGER if set, and otherwise will | |
585 | do its best to print the file in a convenient form. |
|
584 | do its best to print the file in a convenient form. | |
586 |
|
585 | |||
587 | If the given argument is not an object currently defined, IPython will |
|
586 | If the given argument is not an object currently defined, IPython will | |
588 | try to interpret it as a filename (automatically adding a .py extension |
|
587 | try to interpret it as a filename (automatically adding a .py extension | |
589 | if needed). You can thus use %pfile as a syntax highlighting code |
|
588 | if needed). You can thus use %pfile as a syntax highlighting code | |
590 | viewer.""" |
|
589 | viewer.""" | |
591 |
|
590 | |||
592 | # first interpret argument as an object name |
|
591 | # first interpret argument as an object name | |
593 | out = self._inspect('pfile',parameter_s) |
|
592 | out = self._inspect('pfile',parameter_s) | |
594 | # if not, try the input as a filename |
|
593 | # if not, try the input as a filename | |
595 | if out == 'not found': |
|
594 | if out == 'not found': | |
596 | try: |
|
595 | try: | |
597 | filename = get_py_filename(parameter_s) |
|
596 | filename = get_py_filename(parameter_s) | |
598 | except IOError,msg: |
|
597 | except IOError,msg: | |
599 | print msg |
|
598 | print msg | |
600 | return |
|
599 | return | |
601 | page.page(self.shell.inspector.format(file(filename).read())) |
|
600 | page.page(self.shell.inspector.format(file(filename).read())) | |
602 |
|
601 | |||
603 | def magic_psearch(self, parameter_s=''): |
|
602 | def magic_psearch(self, parameter_s=''): | |
604 | """Search for object in namespaces by wildcard. |
|
603 | """Search for object in namespaces by wildcard. | |
605 |
|
604 | |||
606 | %psearch [options] PATTERN [OBJECT TYPE] |
|
605 | %psearch [options] PATTERN [OBJECT TYPE] | |
607 |
|
606 | |||
608 | Note: ? can be used as a synonym for %psearch, at the beginning or at |
|
607 | Note: ? can be used as a synonym for %psearch, at the beginning or at | |
609 | the end: both a*? and ?a* are equivalent to '%psearch a*'. Still, the |
|
608 | the end: both a*? and ?a* are equivalent to '%psearch a*'. Still, the | |
610 | rest of the command line must be unchanged (options come first), so |
|
609 | rest of the command line must be unchanged (options come first), so | |
611 | for example the following forms are equivalent |
|
610 | for example the following forms are equivalent | |
612 |
|
611 | |||
613 | %psearch -i a* function |
|
612 | %psearch -i a* function | |
614 | -i a* function? |
|
613 | -i a* function? | |
615 | ?-i a* function |
|
614 | ?-i a* function | |
616 |
|
615 | |||
617 | Arguments: |
|
616 | Arguments: | |
618 |
|
617 | |||
619 | PATTERN |
|
618 | PATTERN | |
620 |
|
619 | |||
621 | where PATTERN is a string containing * as a wildcard similar to its |
|
620 | where PATTERN is a string containing * as a wildcard similar to its | |
622 | use in a shell. The pattern is matched in all namespaces on the |
|
621 | use in a shell. The pattern is matched in all namespaces on the | |
623 | search path. By default objects starting with a single _ are not |
|
622 | search path. By default objects starting with a single _ are not | |
624 | matched, many IPython generated objects have a single |
|
623 | matched, many IPython generated objects have a single | |
625 | underscore. The default is case insensitive matching. Matching is |
|
624 | underscore. The default is case insensitive matching. Matching is | |
626 | also done on the attributes of objects and not only on the objects |
|
625 | also done on the attributes of objects and not only on the objects | |
627 | in a module. |
|
626 | in a module. | |
628 |
|
627 | |||
629 | [OBJECT TYPE] |
|
628 | [OBJECT TYPE] | |
630 |
|
629 | |||
631 | Is the name of a python type from the types module. The name is |
|
630 | Is the name of a python type from the types module. The name is | |
632 | given in lowercase without the ending type, ex. StringType is |
|
631 | given in lowercase without the ending type, ex. StringType is | |
633 | written string. By adding a type here only objects matching the |
|
632 | written string. By adding a type here only objects matching the | |
634 | given type are matched. Using all here makes the pattern match all |
|
633 | given type are matched. Using all here makes the pattern match all | |
635 | types (this is the default). |
|
634 | types (this is the default). | |
636 |
|
635 | |||
637 | Options: |
|
636 | Options: | |
638 |
|
637 | |||
639 | -a: makes the pattern match even objects whose names start with a |
|
638 | -a: makes the pattern match even objects whose names start with a | |
640 | single underscore. These names are normally ommitted from the |
|
639 | single underscore. These names are normally ommitted from the | |
641 | search. |
|
640 | search. | |
642 |
|
641 | |||
643 | -i/-c: make the pattern case insensitive/sensitive. If neither of |
|
642 | -i/-c: make the pattern case insensitive/sensitive. If neither of | |
644 | these options is given, the default is read from your ipythonrc |
|
643 | these options is given, the default is read from your ipythonrc | |
645 | file. The option name which sets this value is |
|
644 | file. The option name which sets this value is | |
646 | 'wildcards_case_sensitive'. If this option is not specified in your |
|
645 | 'wildcards_case_sensitive'. If this option is not specified in your | |
647 | ipythonrc file, IPython's internal default is to do a case sensitive |
|
646 | ipythonrc file, IPython's internal default is to do a case sensitive | |
648 | search. |
|
647 | search. | |
649 |
|
648 | |||
650 | -e/-s NAMESPACE: exclude/search a given namespace. The pattern you |
|
649 | -e/-s NAMESPACE: exclude/search a given namespace. The pattern you | |
651 | specifiy can be searched in any of the following namespaces: |
|
650 | specifiy can be searched in any of the following namespaces: | |
652 | 'builtin', 'user', 'user_global','internal', 'alias', where |
|
651 | 'builtin', 'user', 'user_global','internal', 'alias', where | |
653 | 'builtin' and 'user' are the search defaults. Note that you should |
|
652 | 'builtin' and 'user' are the search defaults. Note that you should | |
654 | not use quotes when specifying namespaces. |
|
653 | not use quotes when specifying namespaces. | |
655 |
|
654 | |||
656 | 'Builtin' contains the python module builtin, 'user' contains all |
|
655 | 'Builtin' contains the python module builtin, 'user' contains all | |
657 | user data, 'alias' only contain the shell aliases and no python |
|
656 | user data, 'alias' only contain the shell aliases and no python | |
658 | objects, 'internal' contains objects used by IPython. The |
|
657 | objects, 'internal' contains objects used by IPython. The | |
659 | 'user_global' namespace is only used by embedded IPython instances, |
|
658 | 'user_global' namespace is only used by embedded IPython instances, | |
660 | and it contains module-level globals. You can add namespaces to the |
|
659 | and it contains module-level globals. You can add namespaces to the | |
661 | search with -s or exclude them with -e (these options can be given |
|
660 | search with -s or exclude them with -e (these options can be given | |
662 | more than once). |
|
661 | more than once). | |
663 |
|
662 | |||
664 | Examples: |
|
663 | Examples: | |
665 |
|
664 | |||
666 | %psearch a* -> objects beginning with an a |
|
665 | %psearch a* -> objects beginning with an a | |
667 | %psearch -e builtin a* -> objects NOT in the builtin space starting in a |
|
666 | %psearch -e builtin a* -> objects NOT in the builtin space starting in a | |
668 | %psearch a* function -> all functions beginning with an a |
|
667 | %psearch a* function -> all functions beginning with an a | |
669 | %psearch re.e* -> objects beginning with an e in module re |
|
668 | %psearch re.e* -> objects beginning with an e in module re | |
670 | %psearch r*.e* -> objects that start with e in modules starting in r |
|
669 | %psearch r*.e* -> objects that start with e in modules starting in r | |
671 | %psearch r*.* string -> all strings in modules beginning with r |
|
670 | %psearch r*.* string -> all strings in modules beginning with r | |
672 |
|
671 | |||
673 | Case sensitve search: |
|
672 | Case sensitve search: | |
674 |
|
673 | |||
675 | %psearch -c a* list all object beginning with lower case a |
|
674 | %psearch -c a* list all object beginning with lower case a | |
676 |
|
675 | |||
677 | Show objects beginning with a single _: |
|
676 | Show objects beginning with a single _: | |
678 |
|
677 | |||
679 | %psearch -a _* list objects beginning with a single underscore""" |
|
678 | %psearch -a _* list objects beginning with a single underscore""" | |
680 | try: |
|
679 | try: | |
681 | parameter_s = parameter_s.encode('ascii') |
|
680 | parameter_s = parameter_s.encode('ascii') | |
682 | except UnicodeEncodeError: |
|
681 | except UnicodeEncodeError: | |
683 | print 'Python identifiers can only contain ascii characters.' |
|
682 | print 'Python identifiers can only contain ascii characters.' | |
684 | return |
|
683 | return | |
685 |
|
684 | |||
686 | # default namespaces to be searched |
|
685 | # default namespaces to be searched | |
687 | def_search = ['user','builtin'] |
|
686 | def_search = ['user','builtin'] | |
688 |
|
687 | |||
689 | # Process options/args |
|
688 | # Process options/args | |
690 | opts,args = self.parse_options(parameter_s,'cias:e:',list_all=True) |
|
689 | opts,args = self.parse_options(parameter_s,'cias:e:',list_all=True) | |
691 | opt = opts.get |
|
690 | opt = opts.get | |
692 | shell = self.shell |
|
691 | shell = self.shell | |
693 | psearch = shell.inspector.psearch |
|
692 | psearch = shell.inspector.psearch | |
694 |
|
693 | |||
695 | # select case options |
|
694 | # select case options | |
696 | if opts.has_key('i'): |
|
695 | if opts.has_key('i'): | |
697 | ignore_case = True |
|
696 | ignore_case = True | |
698 | elif opts.has_key('c'): |
|
697 | elif opts.has_key('c'): | |
699 | ignore_case = False |
|
698 | ignore_case = False | |
700 | else: |
|
699 | else: | |
701 | ignore_case = not shell.wildcards_case_sensitive |
|
700 | ignore_case = not shell.wildcards_case_sensitive | |
702 |
|
701 | |||
703 | # Build list of namespaces to search from user options |
|
702 | # Build list of namespaces to search from user options | |
704 | def_search.extend(opt('s',[])) |
|
703 | def_search.extend(opt('s',[])) | |
705 | ns_exclude = ns_exclude=opt('e',[]) |
|
704 | ns_exclude = ns_exclude=opt('e',[]) | |
706 | ns_search = [nm for nm in def_search if nm not in ns_exclude] |
|
705 | ns_search = [nm for nm in def_search if nm not in ns_exclude] | |
707 |
|
706 | |||
708 | # Call the actual search |
|
707 | # Call the actual search | |
709 | try: |
|
708 | try: | |
710 | psearch(args,shell.ns_table,ns_search, |
|
709 | psearch(args,shell.ns_table,ns_search, | |
711 | show_all=opt('a'),ignore_case=ignore_case) |
|
710 | show_all=opt('a'),ignore_case=ignore_case) | |
712 | except: |
|
711 | except: | |
713 | shell.showtraceback() |
|
712 | shell.showtraceback() | |
714 |
|
713 | |||
715 | @skip_doctest |
|
714 | @skip_doctest | |
716 | def magic_who_ls(self, parameter_s=''): |
|
715 | def magic_who_ls(self, parameter_s=''): | |
717 | """Return a sorted list of all interactive variables. |
|
716 | """Return a sorted list of all interactive variables. | |
718 |
|
717 | |||
719 | If arguments are given, only variables of types matching these |
|
718 | If arguments are given, only variables of types matching these | |
720 | arguments are returned. |
|
719 | arguments are returned. | |
721 |
|
720 | |||
722 | Examples |
|
721 | Examples | |
723 | -------- |
|
722 | -------- | |
724 |
|
723 | |||
725 | Define two variables and list them with who_ls:: |
|
724 | Define two variables and list them with who_ls:: | |
726 |
|
725 | |||
727 | In [1]: alpha = 123 |
|
726 | In [1]: alpha = 123 | |
728 |
|
727 | |||
729 | In [2]: beta = 'test' |
|
728 | In [2]: beta = 'test' | |
730 |
|
729 | |||
731 | In [3]: %who_ls |
|
730 | In [3]: %who_ls | |
732 | Out[3]: ['alpha', 'beta'] |
|
731 | Out[3]: ['alpha', 'beta'] | |
733 |
|
732 | |||
734 | In [4]: %who_ls int |
|
733 | In [4]: %who_ls int | |
735 | Out[4]: ['alpha'] |
|
734 | Out[4]: ['alpha'] | |
736 |
|
735 | |||
737 | In [5]: %who_ls str |
|
736 | In [5]: %who_ls str | |
738 | Out[5]: ['beta'] |
|
737 | Out[5]: ['beta'] | |
739 | """ |
|
738 | """ | |
740 |
|
739 | |||
741 | user_ns = self.shell.user_ns |
|
740 | user_ns = self.shell.user_ns | |
742 | internal_ns = self.shell.internal_ns |
|
741 | internal_ns = self.shell.internal_ns | |
743 | user_ns_hidden = self.shell.user_ns_hidden |
|
742 | user_ns_hidden = self.shell.user_ns_hidden | |
744 | out = [ i for i in user_ns |
|
743 | out = [ i for i in user_ns | |
745 | if not i.startswith('_') \ |
|
744 | if not i.startswith('_') \ | |
746 | and not (i in internal_ns or i in user_ns_hidden) ] |
|
745 | and not (i in internal_ns or i in user_ns_hidden) ] | |
747 |
|
746 | |||
748 | typelist = parameter_s.split() |
|
747 | typelist = parameter_s.split() | |
749 | if typelist: |
|
748 | if typelist: | |
750 | typeset = set(typelist) |
|
749 | typeset = set(typelist) | |
751 | out = [i for i in out if type(user_ns[i]).__name__ in typeset] |
|
750 | out = [i for i in out if type(user_ns[i]).__name__ in typeset] | |
752 |
|
751 | |||
753 | out.sort() |
|
752 | out.sort() | |
754 | return out |
|
753 | return out | |
755 |
|
754 | |||
756 | @skip_doctest |
|
755 | @skip_doctest | |
757 | def magic_who(self, parameter_s=''): |
|
756 | def magic_who(self, parameter_s=''): | |
758 | """Print all interactive variables, with some minimal formatting. |
|
757 | """Print all interactive variables, with some minimal formatting. | |
759 |
|
758 | |||
760 | If any arguments are given, only variables whose type matches one of |
|
759 | If any arguments are given, only variables whose type matches one of | |
761 | these are printed. For example: |
|
760 | these are printed. For example: | |
762 |
|
761 | |||
763 | %who function str |
|
762 | %who function str | |
764 |
|
763 | |||
765 | will only list functions and strings, excluding all other types of |
|
764 | will only list functions and strings, excluding all other types of | |
766 | variables. To find the proper type names, simply use type(var) at a |
|
765 | variables. To find the proper type names, simply use type(var) at a | |
767 | command line to see how python prints type names. For example: |
|
766 | command line to see how python prints type names. For example: | |
768 |
|
767 | |||
769 | In [1]: type('hello')\\ |
|
768 | In [1]: type('hello')\\ | |
770 | Out[1]: <type 'str'> |
|
769 | Out[1]: <type 'str'> | |
771 |
|
770 | |||
772 | indicates that the type name for strings is 'str'. |
|
771 | indicates that the type name for strings is 'str'. | |
773 |
|
772 | |||
774 | %who always excludes executed names loaded through your configuration |
|
773 | %who always excludes executed names loaded through your configuration | |
775 | file and things which are internal to IPython. |
|
774 | file and things which are internal to IPython. | |
776 |
|
775 | |||
777 | This is deliberate, as typically you may load many modules and the |
|
776 | This is deliberate, as typically you may load many modules and the | |
778 | purpose of %who is to show you only what you've manually defined. |
|
777 | purpose of %who is to show you only what you've manually defined. | |
779 |
|
778 | |||
780 | Examples |
|
779 | Examples | |
781 | -------- |
|
780 | -------- | |
782 |
|
781 | |||
783 | Define two variables and list them with who:: |
|
782 | Define two variables and list them with who:: | |
784 |
|
783 | |||
785 | In [1]: alpha = 123 |
|
784 | In [1]: alpha = 123 | |
786 |
|
785 | |||
787 | In [2]: beta = 'test' |
|
786 | In [2]: beta = 'test' | |
788 |
|
787 | |||
789 | In [3]: %who |
|
788 | In [3]: %who | |
790 | alpha beta |
|
789 | alpha beta | |
791 |
|
790 | |||
792 | In [4]: %who int |
|
791 | In [4]: %who int | |
793 | alpha |
|
792 | alpha | |
794 |
|
793 | |||
795 | In [5]: %who str |
|
794 | In [5]: %who str | |
796 | beta |
|
795 | beta | |
797 | """ |
|
796 | """ | |
798 |
|
797 | |||
799 | varlist = self.magic_who_ls(parameter_s) |
|
798 | varlist = self.magic_who_ls(parameter_s) | |
800 | if not varlist: |
|
799 | if not varlist: | |
801 | if parameter_s: |
|
800 | if parameter_s: | |
802 | print 'No variables match your requested type.' |
|
801 | print 'No variables match your requested type.' | |
803 | else: |
|
802 | else: | |
804 | print 'Interactive namespace is empty.' |
|
803 | print 'Interactive namespace is empty.' | |
805 | return |
|
804 | return | |
806 |
|
805 | |||
807 | # if we have variables, move on... |
|
806 | # if we have variables, move on... | |
808 | count = 0 |
|
807 | count = 0 | |
809 | for i in varlist: |
|
808 | for i in varlist: | |
810 | print i+'\t', |
|
809 | print i+'\t', | |
811 | count += 1 |
|
810 | count += 1 | |
812 | if count > 8: |
|
811 | if count > 8: | |
813 | count = 0 |
|
812 | count = 0 | |
814 |
|
813 | |||
815 |
|
814 | |||
816 |
|
815 | |||
817 | @skip_doctest |
|
816 | @skip_doctest | |
818 | def magic_whos(self, parameter_s=''): |
|
817 | def magic_whos(self, parameter_s=''): | |
819 | """Like %who, but gives some extra information about each variable. |
|
818 | """Like %who, but gives some extra information about each variable. | |
820 |
|
819 | |||
821 | The same type filtering of %who can be applied here. |
|
820 | The same type filtering of %who can be applied here. | |
822 |
|
821 | |||
823 | For all variables, the type is printed. Additionally it prints: |
|
822 | For all variables, the type is printed. Additionally it prints: | |
824 |
|
823 | |||
825 | - For {},[],(): their length. |
|
824 | - For {},[],(): their length. | |
826 |
|
825 | |||
827 | - For numpy arrays, a summary with shape, number of |
|
826 | - For numpy arrays, a summary with shape, number of | |
828 | elements, typecode and size in memory. |
|
827 | elements, typecode and size in memory. | |
829 |
|
828 | |||
830 | - Everything else: a string representation, snipping their middle if |
|
829 | - Everything else: a string representation, snipping their middle if | |
831 | too long. |
|
830 | too long. | |
832 |
|
831 | |||
833 | Examples |
|
832 | Examples | |
834 | -------- |
|
833 | -------- | |
835 |
|
834 | |||
836 | Define two variables and list them with whos:: |
|
835 | Define two variables and list them with whos:: | |
837 |
|
836 | |||
838 | In [1]: alpha = 123 |
|
837 | In [1]: alpha = 123 | |
839 |
|
838 | |||
840 | In [2]: beta = 'test' |
|
839 | In [2]: beta = 'test' | |
841 |
|
840 | |||
842 | In [3]: %whos |
|
841 | In [3]: %whos | |
843 | Variable Type Data/Info |
|
842 | Variable Type Data/Info | |
844 | -------------------------------- |
|
843 | -------------------------------- | |
845 | alpha int 123 |
|
844 | alpha int 123 | |
846 | beta str test |
|
845 | beta str test | |
847 | """ |
|
846 | """ | |
848 |
|
847 | |||
849 | varnames = self.magic_who_ls(parameter_s) |
|
848 | varnames = self.magic_who_ls(parameter_s) | |
850 | if not varnames: |
|
849 | if not varnames: | |
851 | if parameter_s: |
|
850 | if parameter_s: | |
852 | print 'No variables match your requested type.' |
|
851 | print 'No variables match your requested type.' | |
853 | else: |
|
852 | else: | |
854 | print 'Interactive namespace is empty.' |
|
853 | print 'Interactive namespace is empty.' | |
855 | return |
|
854 | return | |
856 |
|
855 | |||
857 | # if we have variables, move on... |
|
856 | # if we have variables, move on... | |
858 |
|
857 | |||
859 | # for these types, show len() instead of data: |
|
858 | # for these types, show len() instead of data: | |
860 | seq_types = ['dict', 'list', 'tuple'] |
|
859 | seq_types = ['dict', 'list', 'tuple'] | |
861 |
|
860 | |||
862 | # for numpy/Numeric arrays, display summary info |
|
861 | # for numpy/Numeric arrays, display summary info | |
863 | try: |
|
862 | try: | |
864 | import numpy |
|
863 | import numpy | |
865 | except ImportError: |
|
864 | except ImportError: | |
866 | ndarray_type = None |
|
865 | ndarray_type = None | |
867 | else: |
|
866 | else: | |
868 | ndarray_type = numpy.ndarray.__name__ |
|
867 | ndarray_type = numpy.ndarray.__name__ | |
869 | try: |
|
868 | try: | |
870 | import Numeric |
|
869 | import Numeric | |
871 | except ImportError: |
|
870 | except ImportError: | |
872 | array_type = None |
|
871 | array_type = None | |
873 | else: |
|
872 | else: | |
874 | array_type = Numeric.ArrayType.__name__ |
|
873 | array_type = Numeric.ArrayType.__name__ | |
875 |
|
874 | |||
876 | # Find all variable names and types so we can figure out column sizes |
|
875 | # Find all variable names and types so we can figure out column sizes | |
877 | def get_vars(i): |
|
876 | def get_vars(i): | |
878 | return self.shell.user_ns[i] |
|
877 | return self.shell.user_ns[i] | |
879 |
|
878 | |||
880 | # some types are well known and can be shorter |
|
879 | # some types are well known and can be shorter | |
881 | abbrevs = {'IPython.core.macro.Macro' : 'Macro'} |
|
880 | abbrevs = {'IPython.core.macro.Macro' : 'Macro'} | |
882 | def type_name(v): |
|
881 | def type_name(v): | |
883 | tn = type(v).__name__ |
|
882 | tn = type(v).__name__ | |
884 | return abbrevs.get(tn,tn) |
|
883 | return abbrevs.get(tn,tn) | |
885 |
|
884 | |||
886 | varlist = map(get_vars,varnames) |
|
885 | varlist = map(get_vars,varnames) | |
887 |
|
886 | |||
888 | typelist = [] |
|
887 | typelist = [] | |
889 | for vv in varlist: |
|
888 | for vv in varlist: | |
890 | tt = type_name(vv) |
|
889 | tt = type_name(vv) | |
891 |
|
890 | |||
892 | if tt=='instance': |
|
891 | if tt=='instance': | |
893 | typelist.append( abbrevs.get(str(vv.__class__), |
|
892 | typelist.append( abbrevs.get(str(vv.__class__), | |
894 | str(vv.__class__))) |
|
893 | str(vv.__class__))) | |
895 | else: |
|
894 | else: | |
896 | typelist.append(tt) |
|
895 | typelist.append(tt) | |
897 |
|
896 | |||
898 | # column labels and # of spaces as separator |
|
897 | # column labels and # of spaces as separator | |
899 | varlabel = 'Variable' |
|
898 | varlabel = 'Variable' | |
900 | typelabel = 'Type' |
|
899 | typelabel = 'Type' | |
901 | datalabel = 'Data/Info' |
|
900 | datalabel = 'Data/Info' | |
902 | colsep = 3 |
|
901 | colsep = 3 | |
903 | # variable format strings |
|
902 | # variable format strings | |
904 | vformat = "{0:<{varwidth}}{1:<{typewidth}}" |
|
903 | vformat = "{0:<{varwidth}}{1:<{typewidth}}" | |
905 | aformat = "%s: %s elems, type `%s`, %s bytes" |
|
904 | aformat = "%s: %s elems, type `%s`, %s bytes" | |
906 | # find the size of the columns to format the output nicely |
|
905 | # find the size of the columns to format the output nicely | |
907 | varwidth = max(max(map(len,varnames)), len(varlabel)) + colsep |
|
906 | varwidth = max(max(map(len,varnames)), len(varlabel)) + colsep | |
908 | typewidth = max(max(map(len,typelist)), len(typelabel)) + colsep |
|
907 | typewidth = max(max(map(len,typelist)), len(typelabel)) + colsep | |
909 | # table header |
|
908 | # table header | |
910 | print varlabel.ljust(varwidth) + typelabel.ljust(typewidth) + \ |
|
909 | print varlabel.ljust(varwidth) + typelabel.ljust(typewidth) + \ | |
911 | ' '+datalabel+'\n' + '-'*(varwidth+typewidth+len(datalabel)+1) |
|
910 | ' '+datalabel+'\n' + '-'*(varwidth+typewidth+len(datalabel)+1) | |
912 | # and the table itself |
|
911 | # and the table itself | |
913 | kb = 1024 |
|
912 | kb = 1024 | |
914 | Mb = 1048576 # kb**2 |
|
913 | Mb = 1048576 # kb**2 | |
915 | for vname,var,vtype in zip(varnames,varlist,typelist): |
|
914 | for vname,var,vtype in zip(varnames,varlist,typelist): | |
916 | print vformat.format(vname, vtype, varwidth=varwidth, typewidth=typewidth), |
|
915 | print vformat.format(vname, vtype, varwidth=varwidth, typewidth=typewidth), | |
917 | if vtype in seq_types: |
|
916 | if vtype in seq_types: | |
918 | print "n="+str(len(var)) |
|
917 | print "n="+str(len(var)) | |
919 | elif vtype in [array_type,ndarray_type]: |
|
918 | elif vtype in [array_type,ndarray_type]: | |
920 | vshape = str(var.shape).replace(',','').replace(' ','x')[1:-1] |
|
919 | vshape = str(var.shape).replace(',','').replace(' ','x')[1:-1] | |
921 | if vtype==ndarray_type: |
|
920 | if vtype==ndarray_type: | |
922 | # numpy |
|
921 | # numpy | |
923 | vsize = var.size |
|
922 | vsize = var.size | |
924 | vbytes = vsize*var.itemsize |
|
923 | vbytes = vsize*var.itemsize | |
925 | vdtype = var.dtype |
|
924 | vdtype = var.dtype | |
926 | else: |
|
925 | else: | |
927 | # Numeric |
|
926 | # Numeric | |
928 | vsize = Numeric.size(var) |
|
927 | vsize = Numeric.size(var) | |
929 | vbytes = vsize*var.itemsize() |
|
928 | vbytes = vsize*var.itemsize() | |
930 | vdtype = var.typecode() |
|
929 | vdtype = var.typecode() | |
931 |
|
930 | |||
932 | if vbytes < 100000: |
|
931 | if vbytes < 100000: | |
933 | print aformat % (vshape,vsize,vdtype,vbytes) |
|
932 | print aformat % (vshape,vsize,vdtype,vbytes) | |
934 | else: |
|
933 | else: | |
935 | print aformat % (vshape,vsize,vdtype,vbytes), |
|
934 | print aformat % (vshape,vsize,vdtype,vbytes), | |
936 | if vbytes < Mb: |
|
935 | if vbytes < Mb: | |
937 | print '(%s kb)' % (vbytes/kb,) |
|
936 | print '(%s kb)' % (vbytes/kb,) | |
938 | else: |
|
937 | else: | |
939 | print '(%s Mb)' % (vbytes/Mb,) |
|
938 | print '(%s Mb)' % (vbytes/Mb,) | |
940 | else: |
|
939 | else: | |
941 | try: |
|
940 | try: | |
942 | vstr = str(var) |
|
941 | vstr = str(var) | |
943 | except UnicodeEncodeError: |
|
942 | except UnicodeEncodeError: | |
944 | vstr = unicode(var).encode(sys.getdefaultencoding(), |
|
943 | vstr = unicode(var).encode(sys.getdefaultencoding(), | |
945 | 'backslashreplace') |
|
944 | 'backslashreplace') | |
946 | vstr = vstr.replace('\n','\\n') |
|
945 | vstr = vstr.replace('\n','\\n') | |
947 | if len(vstr) < 50: |
|
946 | if len(vstr) < 50: | |
948 | print vstr |
|
947 | print vstr | |
949 | else: |
|
948 | else: | |
950 | print vstr[:25] + "<...>" + vstr[-25:] |
|
949 | print vstr[:25] + "<...>" + vstr[-25:] | |
951 |
|
950 | |||
952 | def magic_reset(self, parameter_s=''): |
|
951 | def magic_reset(self, parameter_s=''): | |
953 | """Resets the namespace by removing all names defined by the user. |
|
952 | """Resets the namespace by removing all names defined by the user. | |
954 |
|
953 | |||
955 | Parameters |
|
954 | Parameters | |
956 | ---------- |
|
955 | ---------- | |
957 | -f : force reset without asking for confirmation. |
|
956 | -f : force reset without asking for confirmation. | |
958 |
|
957 | |||
959 | -s : 'Soft' reset: Only clears your namespace, leaving history intact. |
|
958 | -s : 'Soft' reset: Only clears your namespace, leaving history intact. | |
960 | References to objects may be kept. By default (without this option), |
|
959 | References to objects may be kept. By default (without this option), | |
961 | we do a 'hard' reset, giving you a new session and removing all |
|
960 | we do a 'hard' reset, giving you a new session and removing all | |
962 | references to objects from the current session. |
|
961 | references to objects from the current session. | |
963 |
|
962 | |||
964 | Examples |
|
963 | Examples | |
965 | -------- |
|
964 | -------- | |
966 | In [6]: a = 1 |
|
965 | In [6]: a = 1 | |
967 |
|
966 | |||
968 | In [7]: a |
|
967 | In [7]: a | |
969 | Out[7]: 1 |
|
968 | Out[7]: 1 | |
970 |
|
969 | |||
971 | In [8]: 'a' in _ip.user_ns |
|
970 | In [8]: 'a' in _ip.user_ns | |
972 | Out[8]: True |
|
971 | Out[8]: True | |
973 |
|
972 | |||
974 | In [9]: %reset -f |
|
973 | In [9]: %reset -f | |
975 |
|
974 | |||
976 | In [1]: 'a' in _ip.user_ns |
|
975 | In [1]: 'a' in _ip.user_ns | |
977 | Out[1]: False |
|
976 | Out[1]: False | |
978 | """ |
|
977 | """ | |
979 | opts, args = self.parse_options(parameter_s,'sf') |
|
978 | opts, args = self.parse_options(parameter_s,'sf') | |
980 | if 'f' in opts: |
|
979 | if 'f' in opts: | |
981 | ans = True |
|
980 | ans = True | |
982 | else: |
|
981 | else: | |
983 | ans = self.shell.ask_yes_no( |
|
982 | ans = self.shell.ask_yes_no( | |
984 | "Once deleted, variables cannot be recovered. Proceed (y/[n])? ") |
|
983 | "Once deleted, variables cannot be recovered. Proceed (y/[n])? ") | |
985 | if not ans: |
|
984 | if not ans: | |
986 | print 'Nothing done.' |
|
985 | print 'Nothing done.' | |
987 | return |
|
986 | return | |
988 |
|
987 | |||
989 | if 's' in opts: # Soft reset |
|
988 | if 's' in opts: # Soft reset | |
990 | user_ns = self.shell.user_ns |
|
989 | user_ns = self.shell.user_ns | |
991 | for i in self.magic_who_ls(): |
|
990 | for i in self.magic_who_ls(): | |
992 | del(user_ns[i]) |
|
991 | del(user_ns[i]) | |
993 |
|
992 | |||
994 | else: # Hard reset |
|
993 | else: # Hard reset | |
995 | self.shell.reset(new_session = False) |
|
994 | self.shell.reset(new_session = False) | |
996 |
|
995 | |||
997 |
|
996 | |||
998 |
|
997 | |||
999 | def magic_reset_selective(self, parameter_s=''): |
|
998 | def magic_reset_selective(self, parameter_s=''): | |
1000 | """Resets the namespace by removing names defined by the user. |
|
999 | """Resets the namespace by removing names defined by the user. | |
1001 |
|
1000 | |||
1002 | Input/Output history are left around in case you need them. |
|
1001 | Input/Output history are left around in case you need them. | |
1003 |
|
1002 | |||
1004 | %reset_selective [-f] regex |
|
1003 | %reset_selective [-f] regex | |
1005 |
|
1004 | |||
1006 | No action is taken if regex is not included |
|
1005 | No action is taken if regex is not included | |
1007 |
|
1006 | |||
1008 | Options |
|
1007 | Options | |
1009 | -f : force reset without asking for confirmation. |
|
1008 | -f : force reset without asking for confirmation. | |
1010 |
|
1009 | |||
1011 | Examples |
|
1010 | Examples | |
1012 | -------- |
|
1011 | -------- | |
1013 |
|
1012 | |||
1014 | We first fully reset the namespace so your output looks identical to |
|
1013 | We first fully reset the namespace so your output looks identical to | |
1015 | this example for pedagogical reasons; in practice you do not need a |
|
1014 | this example for pedagogical reasons; in practice you do not need a | |
1016 | full reset. |
|
1015 | full reset. | |
1017 |
|
1016 | |||
1018 | In [1]: %reset -f |
|
1017 | In [1]: %reset -f | |
1019 |
|
1018 | |||
1020 | Now, with a clean namespace we can make a few variables and use |
|
1019 | Now, with a clean namespace we can make a few variables and use | |
1021 | %reset_selective to only delete names that match our regexp: |
|
1020 | %reset_selective to only delete names that match our regexp: | |
1022 |
|
1021 | |||
1023 | In [2]: a=1; b=2; c=3; b1m=4; b2m=5; b3m=6; b4m=7; b2s=8 |
|
1022 | In [2]: a=1; b=2; c=3; b1m=4; b2m=5; b3m=6; b4m=7; b2s=8 | |
1024 |
|
1023 | |||
1025 | In [3]: who_ls |
|
1024 | In [3]: who_ls | |
1026 | Out[3]: ['a', 'b', 'b1m', 'b2m', 'b2s', 'b3m', 'b4m', 'c'] |
|
1025 | Out[3]: ['a', 'b', 'b1m', 'b2m', 'b2s', 'b3m', 'b4m', 'c'] | |
1027 |
|
1026 | |||
1028 | In [4]: %reset_selective -f b[2-3]m |
|
1027 | In [4]: %reset_selective -f b[2-3]m | |
1029 |
|
1028 | |||
1030 | In [5]: who_ls |
|
1029 | In [5]: who_ls | |
1031 | Out[5]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c'] |
|
1030 | Out[5]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c'] | |
1032 |
|
1031 | |||
1033 | In [6]: %reset_selective -f d |
|
1032 | In [6]: %reset_selective -f d | |
1034 |
|
1033 | |||
1035 | In [7]: who_ls |
|
1034 | In [7]: who_ls | |
1036 | Out[7]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c'] |
|
1035 | Out[7]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c'] | |
1037 |
|
1036 | |||
1038 | In [8]: %reset_selective -f c |
|
1037 | In [8]: %reset_selective -f c | |
1039 |
|
1038 | |||
1040 | In [9]: who_ls |
|
1039 | In [9]: who_ls | |
1041 | Out[9]: ['a', 'b', 'b1m', 'b2s', 'b4m'] |
|
1040 | Out[9]: ['a', 'b', 'b1m', 'b2s', 'b4m'] | |
1042 |
|
1041 | |||
1043 | In [10]: %reset_selective -f b |
|
1042 | In [10]: %reset_selective -f b | |
1044 |
|
1043 | |||
1045 | In [11]: who_ls |
|
1044 | In [11]: who_ls | |
1046 | Out[11]: ['a'] |
|
1045 | Out[11]: ['a'] | |
1047 | """ |
|
1046 | """ | |
1048 |
|
1047 | |||
1049 | opts, regex = self.parse_options(parameter_s,'f') |
|
1048 | opts, regex = self.parse_options(parameter_s,'f') | |
1050 |
|
1049 | |||
1051 | if opts.has_key('f'): |
|
1050 | if opts.has_key('f'): | |
1052 | ans = True |
|
1051 | ans = True | |
1053 | else: |
|
1052 | else: | |
1054 | ans = self.shell.ask_yes_no( |
|
1053 | ans = self.shell.ask_yes_no( | |
1055 | "Once deleted, variables cannot be recovered. Proceed (y/[n])? ") |
|
1054 | "Once deleted, variables cannot be recovered. Proceed (y/[n])? ") | |
1056 | if not ans: |
|
1055 | if not ans: | |
1057 | print 'Nothing done.' |
|
1056 | print 'Nothing done.' | |
1058 | return |
|
1057 | return | |
1059 | user_ns = self.shell.user_ns |
|
1058 | user_ns = self.shell.user_ns | |
1060 | if not regex: |
|
1059 | if not regex: | |
1061 | print 'No regex pattern specified. Nothing done.' |
|
1060 | print 'No regex pattern specified. Nothing done.' | |
1062 | return |
|
1061 | return | |
1063 | else: |
|
1062 | else: | |
1064 | try: |
|
1063 | try: | |
1065 | m = re.compile(regex) |
|
1064 | m = re.compile(regex) | |
1066 | except TypeError: |
|
1065 | except TypeError: | |
1067 | raise TypeError('regex must be a string or compiled pattern') |
|
1066 | raise TypeError('regex must be a string or compiled pattern') | |
1068 | for i in self.magic_who_ls(): |
|
1067 | for i in self.magic_who_ls(): | |
1069 | if m.search(i): |
|
1068 | if m.search(i): | |
1070 | del(user_ns[i]) |
|
1069 | del(user_ns[i]) | |
1071 |
|
1070 | |||
1072 | def magic_xdel(self, parameter_s=''): |
|
1071 | def magic_xdel(self, parameter_s=''): | |
1073 | """Delete a variable, trying to clear it from anywhere that |
|
1072 | """Delete a variable, trying to clear it from anywhere that | |
1074 | IPython's machinery has references to it. By default, this uses |
|
1073 | IPython's machinery has references to it. By default, this uses | |
1075 | the identity of the named object in the user namespace to remove |
|
1074 | the identity of the named object in the user namespace to remove | |
1076 | references held under other names. The object is also removed |
|
1075 | references held under other names. The object is also removed | |
1077 | from the output history. |
|
1076 | from the output history. | |
1078 |
|
1077 | |||
1079 | Options |
|
1078 | Options | |
1080 | -n : Delete the specified name from all namespaces, without |
|
1079 | -n : Delete the specified name from all namespaces, without | |
1081 | checking their identity. |
|
1080 | checking their identity. | |
1082 | """ |
|
1081 | """ | |
1083 | opts, varname = self.parse_options(parameter_s,'n') |
|
1082 | opts, varname = self.parse_options(parameter_s,'n') | |
1084 | try: |
|
1083 | try: | |
1085 | self.shell.del_var(varname, ('n' in opts)) |
|
1084 | self.shell.del_var(varname, ('n' in opts)) | |
1086 | except (NameError, ValueError) as e: |
|
1085 | except (NameError, ValueError) as e: | |
1087 | print type(e).__name__ +": "+ str(e) |
|
1086 | print type(e).__name__ +": "+ str(e) | |
1088 |
|
1087 | |||
1089 | def magic_logstart(self,parameter_s=''): |
|
1088 | def magic_logstart(self,parameter_s=''): | |
1090 | """Start logging anywhere in a session. |
|
1089 | """Start logging anywhere in a session. | |
1091 |
|
1090 | |||
1092 | %logstart [-o|-r|-t] [log_name [log_mode]] |
|
1091 | %logstart [-o|-r|-t] [log_name [log_mode]] | |
1093 |
|
1092 | |||
1094 | If no name is given, it defaults to a file named 'ipython_log.py' in your |
|
1093 | If no name is given, it defaults to a file named 'ipython_log.py' in your | |
1095 | current directory, in 'rotate' mode (see below). |
|
1094 | current directory, in 'rotate' mode (see below). | |
1096 |
|
1095 | |||
1097 | '%logstart name' saves to file 'name' in 'backup' mode. It saves your |
|
1096 | '%logstart name' saves to file 'name' in 'backup' mode. It saves your | |
1098 | history up to that point and then continues logging. |
|
1097 | history up to that point and then continues logging. | |
1099 |
|
1098 | |||
1100 | %logstart takes a second optional parameter: logging mode. This can be one |
|
1099 | %logstart takes a second optional parameter: logging mode. This can be one | |
1101 | of (note that the modes are given unquoted):\\ |
|
1100 | of (note that the modes are given unquoted):\\ | |
1102 | append: well, that says it.\\ |
|
1101 | append: well, that says it.\\ | |
1103 | backup: rename (if exists) to name~ and start name.\\ |
|
1102 | backup: rename (if exists) to name~ and start name.\\ | |
1104 | global: single logfile in your home dir, appended to.\\ |
|
1103 | global: single logfile in your home dir, appended to.\\ | |
1105 | over : overwrite existing log.\\ |
|
1104 | over : overwrite existing log.\\ | |
1106 | rotate: create rotating logs name.1~, name.2~, etc. |
|
1105 | rotate: create rotating logs name.1~, name.2~, etc. | |
1107 |
|
1106 | |||
1108 | Options: |
|
1107 | Options: | |
1109 |
|
1108 | |||
1110 | -o: log also IPython's output. In this mode, all commands which |
|
1109 | -o: log also IPython's output. In this mode, all commands which | |
1111 | generate an Out[NN] prompt are recorded to the logfile, right after |
|
1110 | generate an Out[NN] prompt are recorded to the logfile, right after | |
1112 | their corresponding input line. The output lines are always |
|
1111 | their corresponding input line. The output lines are always | |
1113 | prepended with a '#[Out]# ' marker, so that the log remains valid |
|
1112 | prepended with a '#[Out]# ' marker, so that the log remains valid | |
1114 | Python code. |
|
1113 | Python code. | |
1115 |
|
1114 | |||
1116 | Since this marker is always the same, filtering only the output from |
|
1115 | Since this marker is always the same, filtering only the output from | |
1117 | a log is very easy, using for example a simple awk call: |
|
1116 | a log is very easy, using for example a simple awk call: | |
1118 |
|
1117 | |||
1119 | awk -F'#\\[Out\\]# ' '{if($2) {print $2}}' ipython_log.py |
|
1118 | awk -F'#\\[Out\\]# ' '{if($2) {print $2}}' ipython_log.py | |
1120 |
|
1119 | |||
1121 | -r: log 'raw' input. Normally, IPython's logs contain the processed |
|
1120 | -r: log 'raw' input. Normally, IPython's logs contain the processed | |
1122 | input, so that user lines are logged in their final form, converted |
|
1121 | input, so that user lines are logged in their final form, converted | |
1123 | into valid Python. For example, %Exit is logged as |
|
1122 | into valid Python. For example, %Exit is logged as | |
1124 | '_ip.magic("Exit"). If the -r flag is given, all input is logged |
|
1123 | '_ip.magic("Exit"). If the -r flag is given, all input is logged | |
1125 | exactly as typed, with no transformations applied. |
|
1124 | exactly as typed, with no transformations applied. | |
1126 |
|
1125 | |||
1127 | -t: put timestamps before each input line logged (these are put in |
|
1126 | -t: put timestamps before each input line logged (these are put in | |
1128 | comments).""" |
|
1127 | comments).""" | |
1129 |
|
1128 | |||
1130 | opts,par = self.parse_options(parameter_s,'ort') |
|
1129 | opts,par = self.parse_options(parameter_s,'ort') | |
1131 | log_output = 'o' in opts |
|
1130 | log_output = 'o' in opts | |
1132 | log_raw_input = 'r' in opts |
|
1131 | log_raw_input = 'r' in opts | |
1133 | timestamp = 't' in opts |
|
1132 | timestamp = 't' in opts | |
1134 |
|
1133 | |||
1135 | logger = self.shell.logger |
|
1134 | logger = self.shell.logger | |
1136 |
|
1135 | |||
1137 | # if no args are given, the defaults set in the logger constructor by |
|
1136 | # if no args are given, the defaults set in the logger constructor by | |
1138 | # ipytohn remain valid |
|
1137 | # ipytohn remain valid | |
1139 | if par: |
|
1138 | if par: | |
1140 | try: |
|
1139 | try: | |
1141 | logfname,logmode = par.split() |
|
1140 | logfname,logmode = par.split() | |
1142 | except: |
|
1141 | except: | |
1143 | logfname = par |
|
1142 | logfname = par | |
1144 | logmode = 'backup' |
|
1143 | logmode = 'backup' | |
1145 | else: |
|
1144 | else: | |
1146 | logfname = logger.logfname |
|
1145 | logfname = logger.logfname | |
1147 | logmode = logger.logmode |
|
1146 | logmode = logger.logmode | |
1148 | # put logfname into rc struct as if it had been called on the command |
|
1147 | # put logfname into rc struct as if it had been called on the command | |
1149 | # line, so it ends up saved in the log header Save it in case we need |
|
1148 | # line, so it ends up saved in the log header Save it in case we need | |
1150 | # to restore it... |
|
1149 | # to restore it... | |
1151 | old_logfile = self.shell.logfile |
|
1150 | old_logfile = self.shell.logfile | |
1152 | if logfname: |
|
1151 | if logfname: | |
1153 | logfname = os.path.expanduser(logfname) |
|
1152 | logfname = os.path.expanduser(logfname) | |
1154 | self.shell.logfile = logfname |
|
1153 | self.shell.logfile = logfname | |
1155 |
|
1154 | |||
1156 | loghead = '# IPython log file\n\n' |
|
1155 | loghead = '# IPython log file\n\n' | |
1157 | try: |
|
1156 | try: | |
1158 | started = logger.logstart(logfname,loghead,logmode, |
|
1157 | started = logger.logstart(logfname,loghead,logmode, | |
1159 | log_output,timestamp,log_raw_input) |
|
1158 | log_output,timestamp,log_raw_input) | |
1160 | except: |
|
1159 | except: | |
1161 | self.shell.logfile = old_logfile |
|
1160 | self.shell.logfile = old_logfile | |
1162 | warn("Couldn't start log: %s" % sys.exc_info()[1]) |
|
1161 | warn("Couldn't start log: %s" % sys.exc_info()[1]) | |
1163 | else: |
|
1162 | else: | |
1164 | # log input history up to this point, optionally interleaving |
|
1163 | # log input history up to this point, optionally interleaving | |
1165 | # output if requested |
|
1164 | # output if requested | |
1166 |
|
1165 | |||
1167 | if timestamp: |
|
1166 | if timestamp: | |
1168 | # disable timestamping for the previous history, since we've |
|
1167 | # disable timestamping for the previous history, since we've | |
1169 | # lost those already (no time machine here). |
|
1168 | # lost those already (no time machine here). | |
1170 | logger.timestamp = False |
|
1169 | logger.timestamp = False | |
1171 |
|
1170 | |||
1172 | if log_raw_input: |
|
1171 | if log_raw_input: | |
1173 | input_hist = self.shell.history_manager.input_hist_raw |
|
1172 | input_hist = self.shell.history_manager.input_hist_raw | |
1174 | else: |
|
1173 | else: | |
1175 | input_hist = self.shell.history_manager.input_hist_parsed |
|
1174 | input_hist = self.shell.history_manager.input_hist_parsed | |
1176 |
|
1175 | |||
1177 | if log_output: |
|
1176 | if log_output: | |
1178 | log_write = logger.log_write |
|
1177 | log_write = logger.log_write | |
1179 | output_hist = self.shell.history_manager.output_hist |
|
1178 | output_hist = self.shell.history_manager.output_hist | |
1180 | for n in range(1,len(input_hist)-1): |
|
1179 | for n in range(1,len(input_hist)-1): | |
1181 | log_write(input_hist[n].rstrip() + '\n') |
|
1180 | log_write(input_hist[n].rstrip() + '\n') | |
1182 | if n in output_hist: |
|
1181 | if n in output_hist: | |
1183 | log_write(repr(output_hist[n]),'output') |
|
1182 | log_write(repr(output_hist[n]),'output') | |
1184 | else: |
|
1183 | else: | |
1185 | logger.log_write('\n'.join(input_hist[1:])) |
|
1184 | logger.log_write('\n'.join(input_hist[1:])) | |
1186 | logger.log_write('\n') |
|
1185 | logger.log_write('\n') | |
1187 | if timestamp: |
|
1186 | if timestamp: | |
1188 | # re-enable timestamping |
|
1187 | # re-enable timestamping | |
1189 | logger.timestamp = True |
|
1188 | logger.timestamp = True | |
1190 |
|
1189 | |||
1191 | print ('Activating auto-logging. ' |
|
1190 | print ('Activating auto-logging. ' | |
1192 | 'Current session state plus future input saved.') |
|
1191 | 'Current session state plus future input saved.') | |
1193 | logger.logstate() |
|
1192 | logger.logstate() | |
1194 |
|
1193 | |||
1195 | def magic_logstop(self,parameter_s=''): |
|
1194 | def magic_logstop(self,parameter_s=''): | |
1196 | """Fully stop logging and close log file. |
|
1195 | """Fully stop logging and close log file. | |
1197 |
|
1196 | |||
1198 | In order to start logging again, a new %logstart call needs to be made, |
|
1197 | In order to start logging again, a new %logstart call needs to be made, | |
1199 | possibly (though not necessarily) with a new filename, mode and other |
|
1198 | possibly (though not necessarily) with a new filename, mode and other | |
1200 | options.""" |
|
1199 | options.""" | |
1201 | self.logger.logstop() |
|
1200 | self.logger.logstop() | |
1202 |
|
1201 | |||
1203 | def magic_logoff(self,parameter_s=''): |
|
1202 | def magic_logoff(self,parameter_s=''): | |
1204 | """Temporarily stop logging. |
|
1203 | """Temporarily stop logging. | |
1205 |
|
1204 | |||
1206 | You must have previously started logging.""" |
|
1205 | You must have previously started logging.""" | |
1207 | self.shell.logger.switch_log(0) |
|
1206 | self.shell.logger.switch_log(0) | |
1208 |
|
1207 | |||
1209 | def magic_logon(self,parameter_s=''): |
|
1208 | def magic_logon(self,parameter_s=''): | |
1210 | """Restart logging. |
|
1209 | """Restart logging. | |
1211 |
|
1210 | |||
1212 | This function is for restarting logging which you've temporarily |
|
1211 | This function is for restarting logging which you've temporarily | |
1213 | stopped with %logoff. For starting logging for the first time, you |
|
1212 | stopped with %logoff. For starting logging for the first time, you | |
1214 | must use the %logstart function, which allows you to specify an |
|
1213 | must use the %logstart function, which allows you to specify an | |
1215 | optional log filename.""" |
|
1214 | optional log filename.""" | |
1216 |
|
1215 | |||
1217 | self.shell.logger.switch_log(1) |
|
1216 | self.shell.logger.switch_log(1) | |
1218 |
|
1217 | |||
1219 | def magic_logstate(self,parameter_s=''): |
|
1218 | def magic_logstate(self,parameter_s=''): | |
1220 | """Print the status of the logging system.""" |
|
1219 | """Print the status of the logging system.""" | |
1221 |
|
1220 | |||
1222 | self.shell.logger.logstate() |
|
1221 | self.shell.logger.logstate() | |
1223 |
|
1222 | |||
1224 | def magic_pdb(self, parameter_s=''): |
|
1223 | def magic_pdb(self, parameter_s=''): | |
1225 | """Control the automatic calling of the pdb interactive debugger. |
|
1224 | """Control the automatic calling of the pdb interactive debugger. | |
1226 |
|
1225 | |||
1227 | Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without |
|
1226 | Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without | |
1228 | argument it works as a toggle. |
|
1227 | argument it works as a toggle. | |
1229 |
|
1228 | |||
1230 | When an exception is triggered, IPython can optionally call the |
|
1229 | When an exception is triggered, IPython can optionally call the | |
1231 | interactive pdb debugger after the traceback printout. %pdb toggles |
|
1230 | interactive pdb debugger after the traceback printout. %pdb toggles | |
1232 | this feature on and off. |
|
1231 | this feature on and off. | |
1233 |
|
1232 | |||
1234 | The initial state of this feature is set in your ipythonrc |
|
1233 | The initial state of this feature is set in your ipythonrc | |
1235 | configuration file (the variable is called 'pdb'). |
|
1234 | configuration file (the variable is called 'pdb'). | |
1236 |
|
1235 | |||
1237 | If you want to just activate the debugger AFTER an exception has fired, |
|
1236 | If you want to just activate the debugger AFTER an exception has fired, | |
1238 | without having to type '%pdb on' and rerunning your code, you can use |
|
1237 | without having to type '%pdb on' and rerunning your code, you can use | |
1239 | the %debug magic.""" |
|
1238 | the %debug magic.""" | |
1240 |
|
1239 | |||
1241 | par = parameter_s.strip().lower() |
|
1240 | par = parameter_s.strip().lower() | |
1242 |
|
1241 | |||
1243 | if par: |
|
1242 | if par: | |
1244 | try: |
|
1243 | try: | |
1245 | new_pdb = {'off':0,'0':0,'on':1,'1':1}[par] |
|
1244 | new_pdb = {'off':0,'0':0,'on':1,'1':1}[par] | |
1246 | except KeyError: |
|
1245 | except KeyError: | |
1247 | print ('Incorrect argument. Use on/1, off/0, ' |
|
1246 | print ('Incorrect argument. Use on/1, off/0, ' | |
1248 | 'or nothing for a toggle.') |
|
1247 | 'or nothing for a toggle.') | |
1249 | return |
|
1248 | return | |
1250 | else: |
|
1249 | else: | |
1251 | # toggle |
|
1250 | # toggle | |
1252 | new_pdb = not self.shell.call_pdb |
|
1251 | new_pdb = not self.shell.call_pdb | |
1253 |
|
1252 | |||
1254 | # set on the shell |
|
1253 | # set on the shell | |
1255 | self.shell.call_pdb = new_pdb |
|
1254 | self.shell.call_pdb = new_pdb | |
1256 | print 'Automatic pdb calling has been turned',on_off(new_pdb) |
|
1255 | print 'Automatic pdb calling has been turned',on_off(new_pdb) | |
1257 |
|
1256 | |||
1258 | def magic_debug(self, parameter_s=''): |
|
1257 | def magic_debug(self, parameter_s=''): | |
1259 | """Activate the interactive debugger in post-mortem mode. |
|
1258 | """Activate the interactive debugger in post-mortem mode. | |
1260 |
|
1259 | |||
1261 | If an exception has just occurred, this lets you inspect its stack |
|
1260 | If an exception has just occurred, this lets you inspect its stack | |
1262 | frames interactively. Note that this will always work only on the last |
|
1261 | frames interactively. Note that this will always work only on the last | |
1263 | traceback that occurred, so you must call this quickly after an |
|
1262 | traceback that occurred, so you must call this quickly after an | |
1264 | exception that you wish to inspect has fired, because if another one |
|
1263 | exception that you wish to inspect has fired, because if another one | |
1265 | occurs, it clobbers the previous one. |
|
1264 | occurs, it clobbers the previous one. | |
1266 |
|
1265 | |||
1267 | If you want IPython to automatically do this on every exception, see |
|
1266 | If you want IPython to automatically do this on every exception, see | |
1268 | the %pdb magic for more details. |
|
1267 | the %pdb magic for more details. | |
1269 | """ |
|
1268 | """ | |
1270 | self.shell.debugger(force=True) |
|
1269 | self.shell.debugger(force=True) | |
1271 |
|
1270 | |||
1272 | @skip_doctest |
|
1271 | @skip_doctest | |
1273 | def magic_prun(self, parameter_s ='',user_mode=1, |
|
1272 | def magic_prun(self, parameter_s ='',user_mode=1, | |
1274 | opts=None,arg_lst=None,prog_ns=None): |
|
1273 | opts=None,arg_lst=None,prog_ns=None): | |
1275 |
|
1274 | |||
1276 | """Run a statement through the python code profiler. |
|
1275 | """Run a statement through the python code profiler. | |
1277 |
|
1276 | |||
1278 | Usage: |
|
1277 | Usage: | |
1279 | %prun [options] statement |
|
1278 | %prun [options] statement | |
1280 |
|
1279 | |||
1281 | The given statement (which doesn't require quote marks) is run via the |
|
1280 | The given statement (which doesn't require quote marks) is run via the | |
1282 | python profiler in a manner similar to the profile.run() function. |
|
1281 | python profiler in a manner similar to the profile.run() function. | |
1283 | Namespaces are internally managed to work correctly; profile.run |
|
1282 | Namespaces are internally managed to work correctly; profile.run | |
1284 | cannot be used in IPython because it makes certain assumptions about |
|
1283 | cannot be used in IPython because it makes certain assumptions about | |
1285 | namespaces which do not hold under IPython. |
|
1284 | namespaces which do not hold under IPython. | |
1286 |
|
1285 | |||
1287 | Options: |
|
1286 | Options: | |
1288 |
|
1287 | |||
1289 | -l <limit>: you can place restrictions on what or how much of the |
|
1288 | -l <limit>: you can place restrictions on what or how much of the | |
1290 | profile gets printed. The limit value can be: |
|
1289 | profile gets printed. The limit value can be: | |
1291 |
|
1290 | |||
1292 | * A string: only information for function names containing this string |
|
1291 | * A string: only information for function names containing this string | |
1293 | is printed. |
|
1292 | is printed. | |
1294 |
|
1293 | |||
1295 | * An integer: only these many lines are printed. |
|
1294 | * An integer: only these many lines are printed. | |
1296 |
|
1295 | |||
1297 | * A float (between 0 and 1): this fraction of the report is printed |
|
1296 | * A float (between 0 and 1): this fraction of the report is printed | |
1298 | (for example, use a limit of 0.4 to see the topmost 40% only). |
|
1297 | (for example, use a limit of 0.4 to see the topmost 40% only). | |
1299 |
|
1298 | |||
1300 | You can combine several limits with repeated use of the option. For |
|
1299 | You can combine several limits with repeated use of the option. For | |
1301 | example, '-l __init__ -l 5' will print only the topmost 5 lines of |
|
1300 | example, '-l __init__ -l 5' will print only the topmost 5 lines of | |
1302 | information about class constructors. |
|
1301 | information about class constructors. | |
1303 |
|
1302 | |||
1304 | -r: return the pstats.Stats object generated by the profiling. This |
|
1303 | -r: return the pstats.Stats object generated by the profiling. This | |
1305 | object has all the information about the profile in it, and you can |
|
1304 | object has all the information about the profile in it, and you can | |
1306 | later use it for further analysis or in other functions. |
|
1305 | later use it for further analysis or in other functions. | |
1307 |
|
1306 | |||
1308 | -s <key>: sort profile by given key. You can provide more than one key |
|
1307 | -s <key>: sort profile by given key. You can provide more than one key | |
1309 | by using the option several times: '-s key1 -s key2 -s key3...'. The |
|
1308 | by using the option several times: '-s key1 -s key2 -s key3...'. The | |
1310 | default sorting key is 'time'. |
|
1309 | default sorting key is 'time'. | |
1311 |
|
1310 | |||
1312 | The following is copied verbatim from the profile documentation |
|
1311 | The following is copied verbatim from the profile documentation | |
1313 | referenced below: |
|
1312 | referenced below: | |
1314 |
|
1313 | |||
1315 | When more than one key is provided, additional keys are used as |
|
1314 | When more than one key is provided, additional keys are used as | |
1316 | secondary criteria when the there is equality in all keys selected |
|
1315 | secondary criteria when the there is equality in all keys selected | |
1317 | before them. |
|
1316 | before them. | |
1318 |
|
1317 | |||
1319 | Abbreviations can be used for any key names, as long as the |
|
1318 | Abbreviations can be used for any key names, as long as the | |
1320 | abbreviation is unambiguous. The following are the keys currently |
|
1319 | abbreviation is unambiguous. The following are the keys currently | |
1321 | defined: |
|
1320 | defined: | |
1322 |
|
1321 | |||
1323 | Valid Arg Meaning |
|
1322 | Valid Arg Meaning | |
1324 | "calls" call count |
|
1323 | "calls" call count | |
1325 | "cumulative" cumulative time |
|
1324 | "cumulative" cumulative time | |
1326 | "file" file name |
|
1325 | "file" file name | |
1327 | "module" file name |
|
1326 | "module" file name | |
1328 | "pcalls" primitive call count |
|
1327 | "pcalls" primitive call count | |
1329 | "line" line number |
|
1328 | "line" line number | |
1330 | "name" function name |
|
1329 | "name" function name | |
1331 | "nfl" name/file/line |
|
1330 | "nfl" name/file/line | |
1332 | "stdname" standard name |
|
1331 | "stdname" standard name | |
1333 | "time" internal time |
|
1332 | "time" internal time | |
1334 |
|
1333 | |||
1335 | Note that all sorts on statistics are in descending order (placing |
|
1334 | Note that all sorts on statistics are in descending order (placing | |
1336 | most time consuming items first), where as name, file, and line number |
|
1335 | most time consuming items first), where as name, file, and line number | |
1337 | searches are in ascending order (i.e., alphabetical). The subtle |
|
1336 | searches are in ascending order (i.e., alphabetical). The subtle | |
1338 | distinction between "nfl" and "stdname" is that the standard name is a |
|
1337 | distinction between "nfl" and "stdname" is that the standard name is a | |
1339 | sort of the name as printed, which means that the embedded line |
|
1338 | sort of the name as printed, which means that the embedded line | |
1340 | numbers get compared in an odd way. For example, lines 3, 20, and 40 |
|
1339 | numbers get compared in an odd way. For example, lines 3, 20, and 40 | |
1341 | would (if the file names were the same) appear in the string order |
|
1340 | would (if the file names were the same) appear in the string order | |
1342 | "20" "3" and "40". In contrast, "nfl" does a numeric compare of the |
|
1341 | "20" "3" and "40". In contrast, "nfl" does a numeric compare of the | |
1343 | line numbers. In fact, sort_stats("nfl") is the same as |
|
1342 | line numbers. In fact, sort_stats("nfl") is the same as | |
1344 | sort_stats("name", "file", "line"). |
|
1343 | sort_stats("name", "file", "line"). | |
1345 |
|
1344 | |||
1346 | -T <filename>: save profile results as shown on screen to a text |
|
1345 | -T <filename>: save profile results as shown on screen to a text | |
1347 | file. The profile is still shown on screen. |
|
1346 | file. The profile is still shown on screen. | |
1348 |
|
1347 | |||
1349 | -D <filename>: save (via dump_stats) profile statistics to given |
|
1348 | -D <filename>: save (via dump_stats) profile statistics to given | |
1350 | filename. This data is in a format understod by the pstats module, and |
|
1349 | filename. This data is in a format understod by the pstats module, and | |
1351 | is generated by a call to the dump_stats() method of profile |
|
1350 | is generated by a call to the dump_stats() method of profile | |
1352 | objects. The profile is still shown on screen. |
|
1351 | objects. The profile is still shown on screen. | |
1353 |
|
1352 | |||
1354 | If you want to run complete programs under the profiler's control, use |
|
1353 | If you want to run complete programs under the profiler's control, use | |
1355 | '%run -p [prof_opts] filename.py [args to program]' where prof_opts |
|
1354 | '%run -p [prof_opts] filename.py [args to program]' where prof_opts | |
1356 | contains profiler specific options as described here. |
|
1355 | contains profiler specific options as described here. | |
1357 |
|
1356 | |||
1358 | You can read the complete documentation for the profile module with:: |
|
1357 | You can read the complete documentation for the profile module with:: | |
1359 |
|
1358 | |||
1360 | In [1]: import profile; profile.help() |
|
1359 | In [1]: import profile; profile.help() | |
1361 | """ |
|
1360 | """ | |
1362 |
|
1361 | |||
1363 | opts_def = Struct(D=[''],l=[],s=['time'],T=['']) |
|
1362 | opts_def = Struct(D=[''],l=[],s=['time'],T=['']) | |
1364 | # protect user quote marks |
|
1363 | # protect user quote marks | |
1365 | parameter_s = parameter_s.replace('"',r'\"').replace("'",r"\'") |
|
1364 | parameter_s = parameter_s.replace('"',r'\"').replace("'",r"\'") | |
1366 |
|
1365 | |||
1367 | if user_mode: # regular user call |
|
1366 | if user_mode: # regular user call | |
1368 | opts,arg_str = self.parse_options(parameter_s,'D:l:rs:T:', |
|
1367 | opts,arg_str = self.parse_options(parameter_s,'D:l:rs:T:', | |
1369 | list_all=1) |
|
1368 | list_all=1) | |
1370 | namespace = self.shell.user_ns |
|
1369 | namespace = self.shell.user_ns | |
1371 | else: # called to run a program by %run -p |
|
1370 | else: # called to run a program by %run -p | |
1372 | try: |
|
1371 | try: | |
1373 | filename = get_py_filename(arg_lst[0]) |
|
1372 | filename = get_py_filename(arg_lst[0]) | |
1374 | except IOError,msg: |
|
1373 | except IOError,msg: | |
1375 | error(msg) |
|
1374 | error(msg) | |
1376 | return |
|
1375 | return | |
1377 |
|
1376 | |||
1378 | arg_str = 'execfile(filename,prog_ns)' |
|
1377 | arg_str = 'execfile(filename,prog_ns)' | |
1379 | namespace = locals() |
|
1378 | namespace = locals() | |
1380 |
|
1379 | |||
1381 | opts.merge(opts_def) |
|
1380 | opts.merge(opts_def) | |
1382 |
|
1381 | |||
1383 | prof = profile.Profile() |
|
1382 | prof = profile.Profile() | |
1384 | try: |
|
1383 | try: | |
1385 | prof = prof.runctx(arg_str,namespace,namespace) |
|
1384 | prof = prof.runctx(arg_str,namespace,namespace) | |
1386 | sys_exit = '' |
|
1385 | sys_exit = '' | |
1387 | except SystemExit: |
|
1386 | except SystemExit: | |
1388 | sys_exit = """*** SystemExit exception caught in code being profiled.""" |
|
1387 | sys_exit = """*** SystemExit exception caught in code being profiled.""" | |
1389 |
|
1388 | |||
1390 | stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s) |
|
1389 | stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s) | |
1391 |
|
1390 | |||
1392 | lims = opts.l |
|
1391 | lims = opts.l | |
1393 | if lims: |
|
1392 | if lims: | |
1394 | lims = [] # rebuild lims with ints/floats/strings |
|
1393 | lims = [] # rebuild lims with ints/floats/strings | |
1395 | for lim in opts.l: |
|
1394 | for lim in opts.l: | |
1396 | try: |
|
1395 | try: | |
1397 | lims.append(int(lim)) |
|
1396 | lims.append(int(lim)) | |
1398 | except ValueError: |
|
1397 | except ValueError: | |
1399 | try: |
|
1398 | try: | |
1400 | lims.append(float(lim)) |
|
1399 | lims.append(float(lim)) | |
1401 | except ValueError: |
|
1400 | except ValueError: | |
1402 | lims.append(lim) |
|
1401 | lims.append(lim) | |
1403 |
|
1402 | |||
1404 | # Trap output. |
|
1403 | # Trap output. | |
1405 | stdout_trap = StringIO() |
|
1404 | stdout_trap = StringIO() | |
1406 |
|
1405 | |||
1407 | if hasattr(stats,'stream'): |
|
1406 | if hasattr(stats,'stream'): | |
1408 | # In newer versions of python, the stats object has a 'stream' |
|
1407 | # In newer versions of python, the stats object has a 'stream' | |
1409 | # attribute to write into. |
|
1408 | # attribute to write into. | |
1410 | stats.stream = stdout_trap |
|
1409 | stats.stream = stdout_trap | |
1411 | stats.print_stats(*lims) |
|
1410 | stats.print_stats(*lims) | |
1412 | else: |
|
1411 | else: | |
1413 | # For older versions, we manually redirect stdout during printing |
|
1412 | # For older versions, we manually redirect stdout during printing | |
1414 | sys_stdout = sys.stdout |
|
1413 | sys_stdout = sys.stdout | |
1415 | try: |
|
1414 | try: | |
1416 | sys.stdout = stdout_trap |
|
1415 | sys.stdout = stdout_trap | |
1417 | stats.print_stats(*lims) |
|
1416 | stats.print_stats(*lims) | |
1418 | finally: |
|
1417 | finally: | |
1419 | sys.stdout = sys_stdout |
|
1418 | sys.stdout = sys_stdout | |
1420 |
|
1419 | |||
1421 | output = stdout_trap.getvalue() |
|
1420 | output = stdout_trap.getvalue() | |
1422 | output = output.rstrip() |
|
1421 | output = output.rstrip() | |
1423 |
|
1422 | |||
1424 | page.page(output) |
|
1423 | page.page(output) | |
1425 | print sys_exit, |
|
1424 | print sys_exit, | |
1426 |
|
1425 | |||
1427 | dump_file = opts.D[0] |
|
1426 | dump_file = opts.D[0] | |
1428 | text_file = opts.T[0] |
|
1427 | text_file = opts.T[0] | |
1429 | if dump_file: |
|
1428 | if dump_file: | |
1430 | prof.dump_stats(dump_file) |
|
1429 | prof.dump_stats(dump_file) | |
1431 | print '\n*** Profile stats marshalled to file',\ |
|
1430 | print '\n*** Profile stats marshalled to file',\ | |
1432 | `dump_file`+'.',sys_exit |
|
1431 | `dump_file`+'.',sys_exit | |
1433 | if text_file: |
|
1432 | if text_file: | |
1434 | pfile = file(text_file,'w') |
|
1433 | pfile = file(text_file,'w') | |
1435 | pfile.write(output) |
|
1434 | pfile.write(output) | |
1436 | pfile.close() |
|
1435 | pfile.close() | |
1437 | print '\n*** Profile printout saved to text file',\ |
|
1436 | print '\n*** Profile printout saved to text file',\ | |
1438 | `text_file`+'.',sys_exit |
|
1437 | `text_file`+'.',sys_exit | |
1439 |
|
1438 | |||
1440 | if opts.has_key('r'): |
|
1439 | if opts.has_key('r'): | |
1441 | return stats |
|
1440 | return stats | |
1442 | else: |
|
1441 | else: | |
1443 | return None |
|
1442 | return None | |
1444 |
|
1443 | |||
1445 | @skip_doctest |
|
1444 | @skip_doctest | |
1446 | def magic_run(self, parameter_s ='',runner=None, |
|
1445 | def magic_run(self, parameter_s ='',runner=None, | |
1447 | file_finder=get_py_filename): |
|
1446 | file_finder=get_py_filename): | |
1448 | """Run the named file inside IPython as a program. |
|
1447 | """Run the named file inside IPython as a program. | |
1449 |
|
1448 | |||
1450 | Usage:\\ |
|
1449 | Usage:\\ | |
1451 | %run [-n -i -t [-N<N>] -d [-b<N>] -p [profile options]] file [args] |
|
1450 | %run [-n -i -t [-N<N>] -d [-b<N>] -p [profile options]] file [args] | |
1452 |
|
1451 | |||
1453 | Parameters after the filename are passed as command-line arguments to |
|
1452 | Parameters after the filename are passed as command-line arguments to | |
1454 | the program (put in sys.argv). Then, control returns to IPython's |
|
1453 | the program (put in sys.argv). Then, control returns to IPython's | |
1455 | prompt. |
|
1454 | prompt. | |
1456 |
|
1455 | |||
1457 | This is similar to running at a system prompt:\\ |
|
1456 | This is similar to running at a system prompt:\\ | |
1458 | $ python file args\\ |
|
1457 | $ python file args\\ | |
1459 | but with the advantage of giving you IPython's tracebacks, and of |
|
1458 | but with the advantage of giving you IPython's tracebacks, and of | |
1460 | loading all variables into your interactive namespace for further use |
|
1459 | loading all variables into your interactive namespace for further use | |
1461 | (unless -p is used, see below). |
|
1460 | (unless -p is used, see below). | |
1462 |
|
1461 | |||
1463 | The file is executed in a namespace initially consisting only of |
|
1462 | The file is executed in a namespace initially consisting only of | |
1464 | __name__=='__main__' and sys.argv constructed as indicated. It thus |
|
1463 | __name__=='__main__' and sys.argv constructed as indicated. It thus | |
1465 | sees its environment as if it were being run as a stand-alone program |
|
1464 | sees its environment as if it were being run as a stand-alone program | |
1466 | (except for sharing global objects such as previously imported |
|
1465 | (except for sharing global objects such as previously imported | |
1467 | modules). But after execution, the IPython interactive namespace gets |
|
1466 | modules). But after execution, the IPython interactive namespace gets | |
1468 | updated with all variables defined in the program (except for __name__ |
|
1467 | updated with all variables defined in the program (except for __name__ | |
1469 | and sys.argv). This allows for very convenient loading of code for |
|
1468 | and sys.argv). This allows for very convenient loading of code for | |
1470 | interactive work, while giving each program a 'clean sheet' to run in. |
|
1469 | interactive work, while giving each program a 'clean sheet' to run in. | |
1471 |
|
1470 | |||
1472 | Options: |
|
1471 | Options: | |
1473 |
|
1472 | |||
1474 | -n: __name__ is NOT set to '__main__', but to the running file's name |
|
1473 | -n: __name__ is NOT set to '__main__', but to the running file's name | |
1475 | without extension (as python does under import). This allows running |
|
1474 | without extension (as python does under import). This allows running | |
1476 | scripts and reloading the definitions in them without calling code |
|
1475 | scripts and reloading the definitions in them without calling code | |
1477 | protected by an ' if __name__ == "__main__" ' clause. |
|
1476 | protected by an ' if __name__ == "__main__" ' clause. | |
1478 |
|
1477 | |||
1479 | -i: run the file in IPython's namespace instead of an empty one. This |
|
1478 | -i: run the file in IPython's namespace instead of an empty one. This | |
1480 | is useful if you are experimenting with code written in a text editor |
|
1479 | is useful if you are experimenting with code written in a text editor | |
1481 | which depends on variables defined interactively. |
|
1480 | which depends on variables defined interactively. | |
1482 |
|
1481 | |||
1483 | -e: ignore sys.exit() calls or SystemExit exceptions in the script |
|
1482 | -e: ignore sys.exit() calls or SystemExit exceptions in the script | |
1484 | being run. This is particularly useful if IPython is being used to |
|
1483 | being run. This is particularly useful if IPython is being used to | |
1485 | run unittests, which always exit with a sys.exit() call. In such |
|
1484 | run unittests, which always exit with a sys.exit() call. In such | |
1486 | cases you are interested in the output of the test results, not in |
|
1485 | cases you are interested in the output of the test results, not in | |
1487 | seeing a traceback of the unittest module. |
|
1486 | seeing a traceback of the unittest module. | |
1488 |
|
1487 | |||
1489 | -t: print timing information at the end of the run. IPython will give |
|
1488 | -t: print timing information at the end of the run. IPython will give | |
1490 | you an estimated CPU time consumption for your script, which under |
|
1489 | you an estimated CPU time consumption for your script, which under | |
1491 | Unix uses the resource module to avoid the wraparound problems of |
|
1490 | Unix uses the resource module to avoid the wraparound problems of | |
1492 | time.clock(). Under Unix, an estimate of time spent on system tasks |
|
1491 | time.clock(). Under Unix, an estimate of time spent on system tasks | |
1493 | is also given (for Windows platforms this is reported as 0.0). |
|
1492 | is also given (for Windows platforms this is reported as 0.0). | |
1494 |
|
1493 | |||
1495 | If -t is given, an additional -N<N> option can be given, where <N> |
|
1494 | If -t is given, an additional -N<N> option can be given, where <N> | |
1496 | must be an integer indicating how many times you want the script to |
|
1495 | must be an integer indicating how many times you want the script to | |
1497 | run. The final timing report will include total and per run results. |
|
1496 | run. The final timing report will include total and per run results. | |
1498 |
|
1497 | |||
1499 | For example (testing the script uniq_stable.py): |
|
1498 | For example (testing the script uniq_stable.py): | |
1500 |
|
1499 | |||
1501 | In [1]: run -t uniq_stable |
|
1500 | In [1]: run -t uniq_stable | |
1502 |
|
1501 | |||
1503 | IPython CPU timings (estimated):\\ |
|
1502 | IPython CPU timings (estimated):\\ | |
1504 | User : 0.19597 s.\\ |
|
1503 | User : 0.19597 s.\\ | |
1505 | System: 0.0 s.\\ |
|
1504 | System: 0.0 s.\\ | |
1506 |
|
1505 | |||
1507 | In [2]: run -t -N5 uniq_stable |
|
1506 | In [2]: run -t -N5 uniq_stable | |
1508 |
|
1507 | |||
1509 | IPython CPU timings (estimated):\\ |
|
1508 | IPython CPU timings (estimated):\\ | |
1510 | Total runs performed: 5\\ |
|
1509 | Total runs performed: 5\\ | |
1511 | Times : Total Per run\\ |
|
1510 | Times : Total Per run\\ | |
1512 | User : 0.910862 s, 0.1821724 s.\\ |
|
1511 | User : 0.910862 s, 0.1821724 s.\\ | |
1513 | System: 0.0 s, 0.0 s. |
|
1512 | System: 0.0 s, 0.0 s. | |
1514 |
|
1513 | |||
1515 | -d: run your program under the control of pdb, the Python debugger. |
|
1514 | -d: run your program under the control of pdb, the Python debugger. | |
1516 | This allows you to execute your program step by step, watch variables, |
|
1515 | This allows you to execute your program step by step, watch variables, | |
1517 | etc. Internally, what IPython does is similar to calling: |
|
1516 | etc. Internally, what IPython does is similar to calling: | |
1518 |
|
1517 | |||
1519 | pdb.run('execfile("YOURFILENAME")') |
|
1518 | pdb.run('execfile("YOURFILENAME")') | |
1520 |
|
1519 | |||
1521 | with a breakpoint set on line 1 of your file. You can change the line |
|
1520 | with a breakpoint set on line 1 of your file. You can change the line | |
1522 | number for this automatic breakpoint to be <N> by using the -bN option |
|
1521 | number for this automatic breakpoint to be <N> by using the -bN option | |
1523 | (where N must be an integer). For example: |
|
1522 | (where N must be an integer). For example: | |
1524 |
|
1523 | |||
1525 | %run -d -b40 myscript |
|
1524 | %run -d -b40 myscript | |
1526 |
|
1525 | |||
1527 | will set the first breakpoint at line 40 in myscript.py. Note that |
|
1526 | will set the first breakpoint at line 40 in myscript.py. Note that | |
1528 | the first breakpoint must be set on a line which actually does |
|
1527 | the first breakpoint must be set on a line which actually does | |
1529 | something (not a comment or docstring) for it to stop execution. |
|
1528 | something (not a comment or docstring) for it to stop execution. | |
1530 |
|
1529 | |||
1531 | When the pdb debugger starts, you will see a (Pdb) prompt. You must |
|
1530 | When the pdb debugger starts, you will see a (Pdb) prompt. You must | |
1532 | first enter 'c' (without qoutes) to start execution up to the first |
|
1531 | first enter 'c' (without qoutes) to start execution up to the first | |
1533 | breakpoint. |
|
1532 | breakpoint. | |
1534 |
|
1533 | |||
1535 | Entering 'help' gives information about the use of the debugger. You |
|
1534 | Entering 'help' gives information about the use of the debugger. You | |
1536 | can easily see pdb's full documentation with "import pdb;pdb.help()" |
|
1535 | can easily see pdb's full documentation with "import pdb;pdb.help()" | |
1537 | at a prompt. |
|
1536 | at a prompt. | |
1538 |
|
1537 | |||
1539 | -p: run program under the control of the Python profiler module (which |
|
1538 | -p: run program under the control of the Python profiler module (which | |
1540 | prints a detailed report of execution times, function calls, etc). |
|
1539 | prints a detailed report of execution times, function calls, etc). | |
1541 |
|
1540 | |||
1542 | You can pass other options after -p which affect the behavior of the |
|
1541 | You can pass other options after -p which affect the behavior of the | |
1543 | profiler itself. See the docs for %prun for details. |
|
1542 | profiler itself. See the docs for %prun for details. | |
1544 |
|
1543 | |||
1545 | In this mode, the program's variables do NOT propagate back to the |
|
1544 | In this mode, the program's variables do NOT propagate back to the | |
1546 | IPython interactive namespace (because they remain in the namespace |
|
1545 | IPython interactive namespace (because they remain in the namespace | |
1547 | where the profiler executes them). |
|
1546 | where the profiler executes them). | |
1548 |
|
1547 | |||
1549 | Internally this triggers a call to %prun, see its documentation for |
|
1548 | Internally this triggers a call to %prun, see its documentation for | |
1550 | details on the options available specifically for profiling. |
|
1549 | details on the options available specifically for profiling. | |
1551 |
|
1550 | |||
1552 | There is one special usage for which the text above doesn't apply: |
|
1551 | There is one special usage for which the text above doesn't apply: | |
1553 | if the filename ends with .ipy, the file is run as ipython script, |
|
1552 | if the filename ends with .ipy, the file is run as ipython script, | |
1554 | just as if the commands were written on IPython prompt. |
|
1553 | just as if the commands were written on IPython prompt. | |
1555 | """ |
|
1554 | """ | |
1556 |
|
1555 | |||
1557 | # get arguments and set sys.argv for program to be run. |
|
1556 | # get arguments and set sys.argv for program to be run. | |
1558 | opts,arg_lst = self.parse_options(parameter_s,'nidtN:b:pD:l:rs:T:e', |
|
1557 | opts,arg_lst = self.parse_options(parameter_s,'nidtN:b:pD:l:rs:T:e', | |
1559 | mode='list',list_all=1) |
|
1558 | mode='list',list_all=1) | |
1560 |
|
1559 | |||
1561 | try: |
|
1560 | try: | |
1562 | filename = file_finder(arg_lst[0]) |
|
1561 | filename = file_finder(arg_lst[0]) | |
1563 | except IndexError: |
|
1562 | except IndexError: | |
1564 | warn('you must provide at least a filename.') |
|
1563 | warn('you must provide at least a filename.') | |
1565 | print '\n%run:\n',oinspect.getdoc(self.magic_run) |
|
1564 | print '\n%run:\n',oinspect.getdoc(self.magic_run) | |
1566 | return |
|
1565 | return | |
1567 | except IOError,msg: |
|
1566 | except IOError,msg: | |
1568 | error(msg) |
|
1567 | error(msg) | |
1569 | return |
|
1568 | return | |
1570 |
|
1569 | |||
1571 | if filename.lower().endswith('.ipy'): |
|
1570 | if filename.lower().endswith('.ipy'): | |
1572 | self.shell.safe_execfile_ipy(filename) |
|
1571 | self.shell.safe_execfile_ipy(filename) | |
1573 | return |
|
1572 | return | |
1574 |
|
1573 | |||
1575 | # Control the response to exit() calls made by the script being run |
|
1574 | # Control the response to exit() calls made by the script being run | |
1576 | exit_ignore = opts.has_key('e') |
|
1575 | exit_ignore = opts.has_key('e') | |
1577 |
|
1576 | |||
1578 | # Make sure that the running script gets a proper sys.argv as if it |
|
1577 | # Make sure that the running script gets a proper sys.argv as if it | |
1579 | # were run from a system shell. |
|
1578 | # were run from a system shell. | |
1580 | save_argv = sys.argv # save it for later restoring |
|
1579 | save_argv = sys.argv # save it for later restoring | |
1581 |
|
1580 | |||
1582 | # simulate shell expansion on arguments, at least tilde expansion |
|
1581 | # simulate shell expansion on arguments, at least tilde expansion | |
1583 | args = [ os.path.expanduser(a) for a in arg_lst[1:] ] |
|
1582 | args = [ os.path.expanduser(a) for a in arg_lst[1:] ] | |
1584 |
|
1583 | |||
1585 | sys.argv = [filename]+ args # put in the proper filename |
|
1584 | sys.argv = [filename]+ args # put in the proper filename | |
1586 |
|
1585 | |||
1587 | if opts.has_key('i'): |
|
1586 | if opts.has_key('i'): | |
1588 | # Run in user's interactive namespace |
|
1587 | # Run in user's interactive namespace | |
1589 | prog_ns = self.shell.user_ns |
|
1588 | prog_ns = self.shell.user_ns | |
1590 | __name__save = self.shell.user_ns['__name__'] |
|
1589 | __name__save = self.shell.user_ns['__name__'] | |
1591 | prog_ns['__name__'] = '__main__' |
|
1590 | prog_ns['__name__'] = '__main__' | |
1592 | main_mod = self.shell.new_main_mod(prog_ns) |
|
1591 | main_mod = self.shell.new_main_mod(prog_ns) | |
1593 | else: |
|
1592 | else: | |
1594 | # Run in a fresh, empty namespace |
|
1593 | # Run in a fresh, empty namespace | |
1595 | if opts.has_key('n'): |
|
1594 | if opts.has_key('n'): | |
1596 | name = os.path.splitext(os.path.basename(filename))[0] |
|
1595 | name = os.path.splitext(os.path.basename(filename))[0] | |
1597 | else: |
|
1596 | else: | |
1598 | name = '__main__' |
|
1597 | name = '__main__' | |
1599 |
|
1598 | |||
1600 | main_mod = self.shell.new_main_mod() |
|
1599 | main_mod = self.shell.new_main_mod() | |
1601 | prog_ns = main_mod.__dict__ |
|
1600 | prog_ns = main_mod.__dict__ | |
1602 | prog_ns['__name__'] = name |
|
1601 | prog_ns['__name__'] = name | |
1603 |
|
1602 | |||
1604 | # Since '%run foo' emulates 'python foo.py' at the cmd line, we must |
|
1603 | # Since '%run foo' emulates 'python foo.py' at the cmd line, we must | |
1605 | # set the __file__ global in the script's namespace |
|
1604 | # set the __file__ global in the script's namespace | |
1606 | prog_ns['__file__'] = filename |
|
1605 | prog_ns['__file__'] = filename | |
1607 |
|
1606 | |||
1608 | # pickle fix. See interactiveshell for an explanation. But we need to make sure |
|
1607 | # pickle fix. See interactiveshell for an explanation. But we need to make sure | |
1609 | # that, if we overwrite __main__, we replace it at the end |
|
1608 | # that, if we overwrite __main__, we replace it at the end | |
1610 | main_mod_name = prog_ns['__name__'] |
|
1609 | main_mod_name = prog_ns['__name__'] | |
1611 |
|
1610 | |||
1612 | if main_mod_name == '__main__': |
|
1611 | if main_mod_name == '__main__': | |
1613 | restore_main = sys.modules['__main__'] |
|
1612 | restore_main = sys.modules['__main__'] | |
1614 | else: |
|
1613 | else: | |
1615 | restore_main = False |
|
1614 | restore_main = False | |
1616 |
|
1615 | |||
1617 | # This needs to be undone at the end to prevent holding references to |
|
1616 | # This needs to be undone at the end to prevent holding references to | |
1618 | # every single object ever created. |
|
1617 | # every single object ever created. | |
1619 | sys.modules[main_mod_name] = main_mod |
|
1618 | sys.modules[main_mod_name] = main_mod | |
1620 |
|
1619 | |||
1621 | try: |
|
1620 | try: | |
1622 | stats = None |
|
1621 | stats = None | |
1623 | with self.readline_no_record: |
|
1622 | with self.readline_no_record: | |
1624 | if opts.has_key('p'): |
|
1623 | if opts.has_key('p'): | |
1625 | stats = self.magic_prun('',0,opts,arg_lst,prog_ns) |
|
1624 | stats = self.magic_prun('',0,opts,arg_lst,prog_ns) | |
1626 | else: |
|
1625 | else: | |
1627 | if opts.has_key('d'): |
|
1626 | if opts.has_key('d'): | |
1628 | deb = debugger.Pdb(self.shell.colors) |
|
1627 | deb = debugger.Pdb(self.shell.colors) | |
1629 | # reset Breakpoint state, which is moronically kept |
|
1628 | # reset Breakpoint state, which is moronically kept | |
1630 | # in a class |
|
1629 | # in a class | |
1631 | bdb.Breakpoint.next = 1 |
|
1630 | bdb.Breakpoint.next = 1 | |
1632 | bdb.Breakpoint.bplist = {} |
|
1631 | bdb.Breakpoint.bplist = {} | |
1633 | bdb.Breakpoint.bpbynumber = [None] |
|
1632 | bdb.Breakpoint.bpbynumber = [None] | |
1634 | # Set an initial breakpoint to stop execution |
|
1633 | # Set an initial breakpoint to stop execution | |
1635 | maxtries = 10 |
|
1634 | maxtries = 10 | |
1636 | bp = int(opts.get('b',[1])[0]) |
|
1635 | bp = int(opts.get('b',[1])[0]) | |
1637 | checkline = deb.checkline(filename,bp) |
|
1636 | checkline = deb.checkline(filename,bp) | |
1638 | if not checkline: |
|
1637 | if not checkline: | |
1639 | for bp in range(bp+1,bp+maxtries+1): |
|
1638 | for bp in range(bp+1,bp+maxtries+1): | |
1640 | if deb.checkline(filename,bp): |
|
1639 | if deb.checkline(filename,bp): | |
1641 | break |
|
1640 | break | |
1642 | else: |
|
1641 | else: | |
1643 | msg = ("\nI failed to find a valid line to set " |
|
1642 | msg = ("\nI failed to find a valid line to set " | |
1644 | "a breakpoint\n" |
|
1643 | "a breakpoint\n" | |
1645 | "after trying up to line: %s.\n" |
|
1644 | "after trying up to line: %s.\n" | |
1646 | "Please set a valid breakpoint manually " |
|
1645 | "Please set a valid breakpoint manually " | |
1647 | "with the -b option." % bp) |
|
1646 | "with the -b option." % bp) | |
1648 | error(msg) |
|
1647 | error(msg) | |
1649 | return |
|
1648 | return | |
1650 | # if we find a good linenumber, set the breakpoint |
|
1649 | # if we find a good linenumber, set the breakpoint | |
1651 | deb.do_break('%s:%s' % (filename,bp)) |
|
1650 | deb.do_break('%s:%s' % (filename,bp)) | |
1652 | # Start file run |
|
1651 | # Start file run | |
1653 | print "NOTE: Enter 'c' at the", |
|
1652 | print "NOTE: Enter 'c' at the", | |
1654 | print "%s prompt to start your script." % deb.prompt |
|
1653 | print "%s prompt to start your script." % deb.prompt | |
1655 | try: |
|
1654 | try: | |
1656 | deb.run('execfile("%s")' % filename,prog_ns) |
|
1655 | deb.run('execfile("%s")' % filename,prog_ns) | |
1657 |
|
1656 | |||
1658 | except: |
|
1657 | except: | |
1659 | etype, value, tb = sys.exc_info() |
|
1658 | etype, value, tb = sys.exc_info() | |
1660 | # Skip three frames in the traceback: the %run one, |
|
1659 | # Skip three frames in the traceback: the %run one, | |
1661 | # one inside bdb.py, and the command-line typed by the |
|
1660 | # one inside bdb.py, and the command-line typed by the | |
1662 | # user (run by exec in pdb itself). |
|
1661 | # user (run by exec in pdb itself). | |
1663 | self.shell.InteractiveTB(etype,value,tb,tb_offset=3) |
|
1662 | self.shell.InteractiveTB(etype,value,tb,tb_offset=3) | |
1664 | else: |
|
1663 | else: | |
1665 | if runner is None: |
|
1664 | if runner is None: | |
1666 | runner = self.shell.safe_execfile |
|
1665 | runner = self.shell.safe_execfile | |
1667 | if opts.has_key('t'): |
|
1666 | if opts.has_key('t'): | |
1668 | # timed execution |
|
1667 | # timed execution | |
1669 | try: |
|
1668 | try: | |
1670 | nruns = int(opts['N'][0]) |
|
1669 | nruns = int(opts['N'][0]) | |
1671 | if nruns < 1: |
|
1670 | if nruns < 1: | |
1672 | error('Number of runs must be >=1') |
|
1671 | error('Number of runs must be >=1') | |
1673 | return |
|
1672 | return | |
1674 | except (KeyError): |
|
1673 | except (KeyError): | |
1675 | nruns = 1 |
|
1674 | nruns = 1 | |
1676 | twall0 = time.time() |
|
1675 | twall0 = time.time() | |
1677 | if nruns == 1: |
|
1676 | if nruns == 1: | |
1678 | t0 = clock2() |
|
1677 | t0 = clock2() | |
1679 | runner(filename,prog_ns,prog_ns, |
|
1678 | runner(filename,prog_ns,prog_ns, | |
1680 | exit_ignore=exit_ignore) |
|
1679 | exit_ignore=exit_ignore) | |
1681 | t1 = clock2() |
|
1680 | t1 = clock2() | |
1682 | t_usr = t1[0]-t0[0] |
|
1681 | t_usr = t1[0]-t0[0] | |
1683 | t_sys = t1[1]-t0[1] |
|
1682 | t_sys = t1[1]-t0[1] | |
1684 | print "\nIPython CPU timings (estimated):" |
|
1683 | print "\nIPython CPU timings (estimated):" | |
1685 | print " User : %10.2f s." % t_usr |
|
1684 | print " User : %10.2f s." % t_usr | |
1686 | print " System : %10.2f s." % t_sys |
|
1685 | print " System : %10.2f s." % t_sys | |
1687 | else: |
|
1686 | else: | |
1688 | runs = range(nruns) |
|
1687 | runs = range(nruns) | |
1689 | t0 = clock2() |
|
1688 | t0 = clock2() | |
1690 | for nr in runs: |
|
1689 | for nr in runs: | |
1691 | runner(filename,prog_ns,prog_ns, |
|
1690 | runner(filename,prog_ns,prog_ns, | |
1692 | exit_ignore=exit_ignore) |
|
1691 | exit_ignore=exit_ignore) | |
1693 | t1 = clock2() |
|
1692 | t1 = clock2() | |
1694 | t_usr = t1[0]-t0[0] |
|
1693 | t_usr = t1[0]-t0[0] | |
1695 | t_sys = t1[1]-t0[1] |
|
1694 | t_sys = t1[1]-t0[1] | |
1696 | print "\nIPython CPU timings (estimated):" |
|
1695 | print "\nIPython CPU timings (estimated):" | |
1697 | print "Total runs performed:",nruns |
|
1696 | print "Total runs performed:",nruns | |
1698 | print " Times : %10.2f %10.2f" % ('Total','Per run') |
|
1697 | print " Times : %10.2f %10.2f" % ('Total','Per run') | |
1699 | print " User : %10.2f s, %10.2f s." % (t_usr,t_usr/nruns) |
|
1698 | print " User : %10.2f s, %10.2f s." % (t_usr,t_usr/nruns) | |
1700 | print " System : %10.2f s, %10.2f s." % (t_sys,t_sys/nruns) |
|
1699 | print " System : %10.2f s, %10.2f s." % (t_sys,t_sys/nruns) | |
1701 | twall1 = time.time() |
|
1700 | twall1 = time.time() | |
1702 | print "Wall time: %10.2f s." % (twall1-twall0) |
|
1701 | print "Wall time: %10.2f s." % (twall1-twall0) | |
1703 |
|
1702 | |||
1704 | else: |
|
1703 | else: | |
1705 | # regular execution |
|
1704 | # regular execution | |
1706 | runner(filename,prog_ns,prog_ns,exit_ignore=exit_ignore) |
|
1705 | runner(filename,prog_ns,prog_ns,exit_ignore=exit_ignore) | |
1707 |
|
1706 | |||
1708 | if opts.has_key('i'): |
|
1707 | if opts.has_key('i'): | |
1709 | self.shell.user_ns['__name__'] = __name__save |
|
1708 | self.shell.user_ns['__name__'] = __name__save | |
1710 | else: |
|
1709 | else: | |
1711 | # The shell MUST hold a reference to prog_ns so after %run |
|
1710 | # The shell MUST hold a reference to prog_ns so after %run | |
1712 | # exits, the python deletion mechanism doesn't zero it out |
|
1711 | # exits, the python deletion mechanism doesn't zero it out | |
1713 | # (leaving dangling references). |
|
1712 | # (leaving dangling references). | |
1714 | self.shell.cache_main_mod(prog_ns,filename) |
|
1713 | self.shell.cache_main_mod(prog_ns,filename) | |
1715 | # update IPython interactive namespace |
|
1714 | # update IPython interactive namespace | |
1716 |
|
1715 | |||
1717 | # Some forms of read errors on the file may mean the |
|
1716 | # Some forms of read errors on the file may mean the | |
1718 | # __name__ key was never set; using pop we don't have to |
|
1717 | # __name__ key was never set; using pop we don't have to | |
1719 | # worry about a possible KeyError. |
|
1718 | # worry about a possible KeyError. | |
1720 | prog_ns.pop('__name__', None) |
|
1719 | prog_ns.pop('__name__', None) | |
1721 |
|
1720 | |||
1722 | self.shell.user_ns.update(prog_ns) |
|
1721 | self.shell.user_ns.update(prog_ns) | |
1723 | finally: |
|
1722 | finally: | |
1724 | # It's a bit of a mystery why, but __builtins__ can change from |
|
1723 | # It's a bit of a mystery why, but __builtins__ can change from | |
1725 | # being a module to becoming a dict missing some key data after |
|
1724 | # being a module to becoming a dict missing some key data after | |
1726 | # %run. As best I can see, this is NOT something IPython is doing |
|
1725 | # %run. As best I can see, this is NOT something IPython is doing | |
1727 | # at all, and similar problems have been reported before: |
|
1726 | # at all, and similar problems have been reported before: | |
1728 | # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html |
|
1727 | # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html | |
1729 | # Since this seems to be done by the interpreter itself, the best |
|
1728 | # Since this seems to be done by the interpreter itself, the best | |
1730 | # we can do is to at least restore __builtins__ for the user on |
|
1729 | # we can do is to at least restore __builtins__ for the user on | |
1731 | # exit. |
|
1730 | # exit. | |
1732 | self.shell.user_ns['__builtins__'] = __builtin__ |
|
1731 | self.shell.user_ns['__builtins__'] = __builtin__ | |
1733 |
|
1732 | |||
1734 | # Ensure key global structures are restored |
|
1733 | # Ensure key global structures are restored | |
1735 | sys.argv = save_argv |
|
1734 | sys.argv = save_argv | |
1736 | if restore_main: |
|
1735 | if restore_main: | |
1737 | sys.modules['__main__'] = restore_main |
|
1736 | sys.modules['__main__'] = restore_main | |
1738 | else: |
|
1737 | else: | |
1739 | # Remove from sys.modules the reference to main_mod we'd |
|
1738 | # Remove from sys.modules the reference to main_mod we'd | |
1740 | # added. Otherwise it will trap references to objects |
|
1739 | # added. Otherwise it will trap references to objects | |
1741 | # contained therein. |
|
1740 | # contained therein. | |
1742 | del sys.modules[main_mod_name] |
|
1741 | del sys.modules[main_mod_name] | |
1743 |
|
1742 | |||
1744 | return stats |
|
1743 | return stats | |
1745 |
|
1744 | |||
1746 | @skip_doctest |
|
1745 | @skip_doctest | |
1747 | def magic_timeit(self, parameter_s =''): |
|
1746 | def magic_timeit(self, parameter_s =''): | |
1748 | """Time execution of a Python statement or expression |
|
1747 | """Time execution of a Python statement or expression | |
1749 |
|
1748 | |||
1750 | Usage:\\ |
|
1749 | Usage:\\ | |
1751 | %timeit [-n<N> -r<R> [-t|-c]] statement |
|
1750 | %timeit [-n<N> -r<R> [-t|-c]] statement | |
1752 |
|
1751 | |||
1753 | Time execution of a Python statement or expression using the timeit |
|
1752 | Time execution of a Python statement or expression using the timeit | |
1754 | module. |
|
1753 | module. | |
1755 |
|
1754 | |||
1756 | Options: |
|
1755 | Options: | |
1757 | -n<N>: execute the given statement <N> times in a loop. If this value |
|
1756 | -n<N>: execute the given statement <N> times in a loop. If this value | |
1758 | is not given, a fitting value is chosen. |
|
1757 | is not given, a fitting value is chosen. | |
1759 |
|
1758 | |||
1760 | -r<R>: repeat the loop iteration <R> times and take the best result. |
|
1759 | -r<R>: repeat the loop iteration <R> times and take the best result. | |
1761 | Default: 3 |
|
1760 | Default: 3 | |
1762 |
|
1761 | |||
1763 | -t: use time.time to measure the time, which is the default on Unix. |
|
1762 | -t: use time.time to measure the time, which is the default on Unix. | |
1764 | This function measures wall time. |
|
1763 | This function measures wall time. | |
1765 |
|
1764 | |||
1766 | -c: use time.clock to measure the time, which is the default on |
|
1765 | -c: use time.clock to measure the time, which is the default on | |
1767 | Windows and measures wall time. On Unix, resource.getrusage is used |
|
1766 | Windows and measures wall time. On Unix, resource.getrusage is used | |
1768 | instead and returns the CPU user time. |
|
1767 | instead and returns the CPU user time. | |
1769 |
|
1768 | |||
1770 | -p<P>: use a precision of <P> digits to display the timing result. |
|
1769 | -p<P>: use a precision of <P> digits to display the timing result. | |
1771 | Default: 3 |
|
1770 | Default: 3 | |
1772 |
|
1771 | |||
1773 |
|
1772 | |||
1774 | Examples: |
|
1773 | Examples: | |
1775 |
|
1774 | |||
1776 | In [1]: %timeit pass |
|
1775 | In [1]: %timeit pass | |
1777 | 10000000 loops, best of 3: 53.3 ns per loop |
|
1776 | 10000000 loops, best of 3: 53.3 ns per loop | |
1778 |
|
1777 | |||
1779 | In [2]: u = None |
|
1778 | In [2]: u = None | |
1780 |
|
1779 | |||
1781 | In [3]: %timeit u is None |
|
1780 | In [3]: %timeit u is None | |
1782 | 10000000 loops, best of 3: 184 ns per loop |
|
1781 | 10000000 loops, best of 3: 184 ns per loop | |
1783 |
|
1782 | |||
1784 | In [4]: %timeit -r 4 u == None |
|
1783 | In [4]: %timeit -r 4 u == None | |
1785 | 1000000 loops, best of 4: 242 ns per loop |
|
1784 | 1000000 loops, best of 4: 242 ns per loop | |
1786 |
|
1785 | |||
1787 | In [5]: import time |
|
1786 | In [5]: import time | |
1788 |
|
1787 | |||
1789 | In [6]: %timeit -n1 time.sleep(2) |
|
1788 | In [6]: %timeit -n1 time.sleep(2) | |
1790 | 1 loops, best of 3: 2 s per loop |
|
1789 | 1 loops, best of 3: 2 s per loop | |
1791 |
|
1790 | |||
1792 |
|
1791 | |||
1793 | The times reported by %timeit will be slightly higher than those |
|
1792 | The times reported by %timeit will be slightly higher than those | |
1794 | reported by the timeit.py script when variables are accessed. This is |
|
1793 | reported by the timeit.py script when variables are accessed. This is | |
1795 | due to the fact that %timeit executes the statement in the namespace |
|
1794 | due to the fact that %timeit executes the statement in the namespace | |
1796 | of the shell, compared with timeit.py, which uses a single setup |
|
1795 | of the shell, compared with timeit.py, which uses a single setup | |
1797 | statement to import function or create variables. Generally, the bias |
|
1796 | statement to import function or create variables. Generally, the bias | |
1798 | does not matter as long as results from timeit.py are not mixed with |
|
1797 | does not matter as long as results from timeit.py are not mixed with | |
1799 | those from %timeit.""" |
|
1798 | those from %timeit.""" | |
1800 |
|
1799 | |||
1801 | import timeit |
|
1800 | import timeit | |
1802 | import math |
|
1801 | import math | |
1803 |
|
1802 | |||
1804 | # XXX: Unfortunately the unicode 'micro' symbol can cause problems in |
|
1803 | # XXX: Unfortunately the unicode 'micro' symbol can cause problems in | |
1805 | # certain terminals. Until we figure out a robust way of |
|
1804 | # certain terminals. Until we figure out a robust way of | |
1806 | # auto-detecting if the terminal can deal with it, use plain 'us' for |
|
1805 | # auto-detecting if the terminal can deal with it, use plain 'us' for | |
1807 | # microseconds. I am really NOT happy about disabling the proper |
|
1806 | # microseconds. I am really NOT happy about disabling the proper | |
1808 | # 'micro' prefix, but crashing is worse... If anyone knows what the |
|
1807 | # 'micro' prefix, but crashing is worse... If anyone knows what the | |
1809 | # right solution for this is, I'm all ears... |
|
1808 | # right solution for this is, I'm all ears... | |
1810 | # |
|
1809 | # | |
1811 | # Note: using |
|
1810 | # Note: using | |
1812 | # |
|
1811 | # | |
1813 | # s = u'\xb5' |
|
1812 | # s = u'\xb5' | |
1814 | # s.encode(sys.getdefaultencoding()) |
|
1813 | # s.encode(sys.getdefaultencoding()) | |
1815 | # |
|
1814 | # | |
1816 | # is not sufficient, as I've seen terminals where that fails but |
|
1815 | # is not sufficient, as I've seen terminals where that fails but | |
1817 | # print s |
|
1816 | # print s | |
1818 | # |
|
1817 | # | |
1819 | # succeeds |
|
1818 | # succeeds | |
1820 | # |
|
1819 | # | |
1821 | # See bug: https://bugs.launchpad.net/ipython/+bug/348466 |
|
1820 | # See bug: https://bugs.launchpad.net/ipython/+bug/348466 | |
1822 |
|
1821 | |||
1823 | #units = [u"s", u"ms",u'\xb5',"ns"] |
|
1822 | #units = [u"s", u"ms",u'\xb5',"ns"] | |
1824 | units = [u"s", u"ms",u'us',"ns"] |
|
1823 | units = [u"s", u"ms",u'us',"ns"] | |
1825 |
|
1824 | |||
1826 | scaling = [1, 1e3, 1e6, 1e9] |
|
1825 | scaling = [1, 1e3, 1e6, 1e9] | |
1827 |
|
1826 | |||
1828 | opts, stmt = self.parse_options(parameter_s,'n:r:tcp:', |
|
1827 | opts, stmt = self.parse_options(parameter_s,'n:r:tcp:', | |
1829 | posix=False) |
|
1828 | posix=False) | |
1830 | if stmt == "": |
|
1829 | if stmt == "": | |
1831 | return |
|
1830 | return | |
1832 | timefunc = timeit.default_timer |
|
1831 | timefunc = timeit.default_timer | |
1833 | number = int(getattr(opts, "n", 0)) |
|
1832 | number = int(getattr(opts, "n", 0)) | |
1834 | repeat = int(getattr(opts, "r", timeit.default_repeat)) |
|
1833 | repeat = int(getattr(opts, "r", timeit.default_repeat)) | |
1835 | precision = int(getattr(opts, "p", 3)) |
|
1834 | precision = int(getattr(opts, "p", 3)) | |
1836 | if hasattr(opts, "t"): |
|
1835 | if hasattr(opts, "t"): | |
1837 | timefunc = time.time |
|
1836 | timefunc = time.time | |
1838 | if hasattr(opts, "c"): |
|
1837 | if hasattr(opts, "c"): | |
1839 | timefunc = clock |
|
1838 | timefunc = clock | |
1840 |
|
1839 | |||
1841 | timer = timeit.Timer(timer=timefunc) |
|
1840 | timer = timeit.Timer(timer=timefunc) | |
1842 | # this code has tight coupling to the inner workings of timeit.Timer, |
|
1841 | # this code has tight coupling to the inner workings of timeit.Timer, | |
1843 | # but is there a better way to achieve that the code stmt has access |
|
1842 | # but is there a better way to achieve that the code stmt has access | |
1844 | # to the shell namespace? |
|
1843 | # to the shell namespace? | |
1845 |
|
1844 | |||
1846 | src = timeit.template % {'stmt': timeit.reindent(stmt, 8), |
|
1845 | src = timeit.template % {'stmt': timeit.reindent(stmt, 8), | |
1847 | 'setup': "pass"} |
|
1846 | 'setup': "pass"} | |
1848 | # Track compilation time so it can be reported if too long |
|
1847 | # Track compilation time so it can be reported if too long | |
1849 | # Minimum time above which compilation time will be reported |
|
1848 | # Minimum time above which compilation time will be reported | |
1850 | tc_min = 0.1 |
|
1849 | tc_min = 0.1 | |
1851 |
|
1850 | |||
1852 | t0 = clock() |
|
1851 | t0 = clock() | |
1853 | code = compile(src, "<magic-timeit>", "exec") |
|
1852 | code = compile(src, "<magic-timeit>", "exec") | |
1854 | tc = clock()-t0 |
|
1853 | tc = clock()-t0 | |
1855 |
|
1854 | |||
1856 | ns = {} |
|
1855 | ns = {} | |
1857 | exec code in self.shell.user_ns, ns |
|
1856 | exec code in self.shell.user_ns, ns | |
1858 | timer.inner = ns["inner"] |
|
1857 | timer.inner = ns["inner"] | |
1859 |
|
1858 | |||
1860 | if number == 0: |
|
1859 | if number == 0: | |
1861 | # determine number so that 0.2 <= total time < 2.0 |
|
1860 | # determine number so that 0.2 <= total time < 2.0 | |
1862 | number = 1 |
|
1861 | number = 1 | |
1863 | for i in range(1, 10): |
|
1862 | for i in range(1, 10): | |
1864 | if timer.timeit(number) >= 0.2: |
|
1863 | if timer.timeit(number) >= 0.2: | |
1865 | break |
|
1864 | break | |
1866 | number *= 10 |
|
1865 | number *= 10 | |
1867 |
|
1866 | |||
1868 | best = min(timer.repeat(repeat, number)) / number |
|
1867 | best = min(timer.repeat(repeat, number)) / number | |
1869 |
|
1868 | |||
1870 | if best > 0.0 and best < 1000.0: |
|
1869 | if best > 0.0 and best < 1000.0: | |
1871 | order = min(-int(math.floor(math.log10(best)) // 3), 3) |
|
1870 | order = min(-int(math.floor(math.log10(best)) // 3), 3) | |
1872 | elif best >= 1000.0: |
|
1871 | elif best >= 1000.0: | |
1873 | order = 0 |
|
1872 | order = 0 | |
1874 | else: |
|
1873 | else: | |
1875 | order = 3 |
|
1874 | order = 3 | |
1876 | print u"%d loops, best of %d: %.*g %s per loop" % (number, repeat, |
|
1875 | print u"%d loops, best of %d: %.*g %s per loop" % (number, repeat, | |
1877 | precision, |
|
1876 | precision, | |
1878 | best * scaling[order], |
|
1877 | best * scaling[order], | |
1879 | units[order]) |
|
1878 | units[order]) | |
1880 | if tc > tc_min: |
|
1879 | if tc > tc_min: | |
1881 | print "Compiler time: %.2f s" % tc |
|
1880 | print "Compiler time: %.2f s" % tc | |
1882 |
|
1881 | |||
1883 | @skip_doctest |
|
1882 | @skip_doctest | |
1884 | @needs_local_scope |
|
1883 | @needs_local_scope | |
1885 | def magic_time(self,parameter_s = ''): |
|
1884 | def magic_time(self,parameter_s = ''): | |
1886 | """Time execution of a Python statement or expression. |
|
1885 | """Time execution of a Python statement or expression. | |
1887 |
|
1886 | |||
1888 | The CPU and wall clock times are printed, and the value of the |
|
1887 | The CPU and wall clock times are printed, and the value of the | |
1889 | expression (if any) is returned. Note that under Win32, system time |
|
1888 | expression (if any) is returned. Note that under Win32, system time | |
1890 | is always reported as 0, since it can not be measured. |
|
1889 | is always reported as 0, since it can not be measured. | |
1891 |
|
1890 | |||
1892 | This function provides very basic timing functionality. In Python |
|
1891 | This function provides very basic timing functionality. In Python | |
1893 | 2.3, the timeit module offers more control and sophistication, so this |
|
1892 | 2.3, the timeit module offers more control and sophistication, so this | |
1894 | could be rewritten to use it (patches welcome). |
|
1893 | could be rewritten to use it (patches welcome). | |
1895 |
|
1894 | |||
1896 | Some examples: |
|
1895 | Some examples: | |
1897 |
|
1896 | |||
1898 | In [1]: time 2**128 |
|
1897 | In [1]: time 2**128 | |
1899 | CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s |
|
1898 | CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s | |
1900 | Wall time: 0.00 |
|
1899 | Wall time: 0.00 | |
1901 | Out[1]: 340282366920938463463374607431768211456L |
|
1900 | Out[1]: 340282366920938463463374607431768211456L | |
1902 |
|
1901 | |||
1903 | In [2]: n = 1000000 |
|
1902 | In [2]: n = 1000000 | |
1904 |
|
1903 | |||
1905 | In [3]: time sum(range(n)) |
|
1904 | In [3]: time sum(range(n)) | |
1906 | CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s |
|
1905 | CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s | |
1907 | Wall time: 1.37 |
|
1906 | Wall time: 1.37 | |
1908 | Out[3]: 499999500000L |
|
1907 | Out[3]: 499999500000L | |
1909 |
|
1908 | |||
1910 | In [4]: time print 'hello world' |
|
1909 | In [4]: time print 'hello world' | |
1911 | hello world |
|
1910 | hello world | |
1912 | CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s |
|
1911 | CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s | |
1913 | Wall time: 0.00 |
|
1912 | Wall time: 0.00 | |
1914 |
|
1913 | |||
1915 | Note that the time needed by Python to compile the given expression |
|
1914 | Note that the time needed by Python to compile the given expression | |
1916 | will be reported if it is more than 0.1s. In this example, the |
|
1915 | will be reported if it is more than 0.1s. In this example, the | |
1917 | actual exponentiation is done by Python at compilation time, so while |
|
1916 | actual exponentiation is done by Python at compilation time, so while | |
1918 | the expression can take a noticeable amount of time to compute, that |
|
1917 | the expression can take a noticeable amount of time to compute, that | |
1919 | time is purely due to the compilation: |
|
1918 | time is purely due to the compilation: | |
1920 |
|
1919 | |||
1921 | In [5]: time 3**9999; |
|
1920 | In [5]: time 3**9999; | |
1922 | CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s |
|
1921 | CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s | |
1923 | Wall time: 0.00 s |
|
1922 | Wall time: 0.00 s | |
1924 |
|
1923 | |||
1925 | In [6]: time 3**999999; |
|
1924 | In [6]: time 3**999999; | |
1926 | CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s |
|
1925 | CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s | |
1927 | Wall time: 0.00 s |
|
1926 | Wall time: 0.00 s | |
1928 | Compiler : 0.78 s |
|
1927 | Compiler : 0.78 s | |
1929 | """ |
|
1928 | """ | |
1930 |
|
1929 | |||
1931 | # fail immediately if the given expression can't be compiled |
|
1930 | # fail immediately if the given expression can't be compiled | |
1932 |
|
1931 | |||
1933 | expr = self.shell.prefilter(parameter_s,False) |
|
1932 | expr = self.shell.prefilter(parameter_s,False) | |
1934 |
|
1933 | |||
1935 | # Minimum time above which compilation time will be reported |
|
1934 | # Minimum time above which compilation time will be reported | |
1936 | tc_min = 0.1 |
|
1935 | tc_min = 0.1 | |
1937 |
|
1936 | |||
1938 | try: |
|
1937 | try: | |
1939 | mode = 'eval' |
|
1938 | mode = 'eval' | |
1940 | t0 = clock() |
|
1939 | t0 = clock() | |
1941 | code = compile(expr,'<timed eval>',mode) |
|
1940 | code = compile(expr,'<timed eval>',mode) | |
1942 | tc = clock()-t0 |
|
1941 | tc = clock()-t0 | |
1943 | except SyntaxError: |
|
1942 | except SyntaxError: | |
1944 | mode = 'exec' |
|
1943 | mode = 'exec' | |
1945 | t0 = clock() |
|
1944 | t0 = clock() | |
1946 | code = compile(expr,'<timed exec>',mode) |
|
1945 | code = compile(expr,'<timed exec>',mode) | |
1947 | tc = clock()-t0 |
|
1946 | tc = clock()-t0 | |
1948 | # skew measurement as little as possible |
|
1947 | # skew measurement as little as possible | |
1949 | glob = self.shell.user_ns |
|
1948 | glob = self.shell.user_ns | |
1950 | locs = self._magic_locals |
|
1949 | locs = self._magic_locals | |
1951 | clk = clock2 |
|
1950 | clk = clock2 | |
1952 | wtime = time.time |
|
1951 | wtime = time.time | |
1953 | # time execution |
|
1952 | # time execution | |
1954 | wall_st = wtime() |
|
1953 | wall_st = wtime() | |
1955 | if mode=='eval': |
|
1954 | if mode=='eval': | |
1956 | st = clk() |
|
1955 | st = clk() | |
1957 | out = eval(code, glob, locs) |
|
1956 | out = eval(code, glob, locs) | |
1958 | end = clk() |
|
1957 | end = clk() | |
1959 | else: |
|
1958 | else: | |
1960 | st = clk() |
|
1959 | st = clk() | |
1961 | exec code in glob, locs |
|
1960 | exec code in glob, locs | |
1962 | end = clk() |
|
1961 | end = clk() | |
1963 | out = None |
|
1962 | out = None | |
1964 | wall_end = wtime() |
|
1963 | wall_end = wtime() | |
1965 | # Compute actual times and report |
|
1964 | # Compute actual times and report | |
1966 | wall_time = wall_end-wall_st |
|
1965 | wall_time = wall_end-wall_st | |
1967 | cpu_user = end[0]-st[0] |
|
1966 | cpu_user = end[0]-st[0] | |
1968 | cpu_sys = end[1]-st[1] |
|
1967 | cpu_sys = end[1]-st[1] | |
1969 | cpu_tot = cpu_user+cpu_sys |
|
1968 | cpu_tot = cpu_user+cpu_sys | |
1970 | print "CPU times: user %.2f s, sys: %.2f s, total: %.2f s" % \ |
|
1969 | print "CPU times: user %.2f s, sys: %.2f s, total: %.2f s" % \ | |
1971 | (cpu_user,cpu_sys,cpu_tot) |
|
1970 | (cpu_user,cpu_sys,cpu_tot) | |
1972 | print "Wall time: %.2f s" % wall_time |
|
1971 | print "Wall time: %.2f s" % wall_time | |
1973 | if tc > tc_min: |
|
1972 | if tc > tc_min: | |
1974 | print "Compiler : %.2f s" % tc |
|
1973 | print "Compiler : %.2f s" % tc | |
1975 | return out |
|
1974 | return out | |
1976 |
|
1975 | |||
1977 | @skip_doctest |
|
1976 | @skip_doctest | |
1978 | def magic_macro(self,parameter_s = ''): |
|
1977 | def magic_macro(self,parameter_s = ''): | |
1979 | """Define a macro for future re-execution. It accepts ranges of history, |
|
1978 | """Define a macro for future re-execution. It accepts ranges of history, | |
1980 | filenames or string objects. |
|
1979 | filenames or string objects. | |
1981 |
|
1980 | |||
1982 | Usage:\\ |
|
1981 | Usage:\\ | |
1983 | %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ... |
|
1982 | %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ... | |
1984 |
|
1983 | |||
1985 | Options: |
|
1984 | Options: | |
1986 |
|
1985 | |||
1987 | -r: use 'raw' input. By default, the 'processed' history is used, |
|
1986 | -r: use 'raw' input. By default, the 'processed' history is used, | |
1988 | so that magics are loaded in their transformed version to valid |
|
1987 | so that magics are loaded in their transformed version to valid | |
1989 | Python. If this option is given, the raw input as typed as the |
|
1988 | Python. If this option is given, the raw input as typed as the | |
1990 | command line is used instead. |
|
1989 | command line is used instead. | |
1991 |
|
1990 | |||
1992 | This will define a global variable called `name` which is a string |
|
1991 | This will define a global variable called `name` which is a string | |
1993 | made of joining the slices and lines you specify (n1,n2,... numbers |
|
1992 | made of joining the slices and lines you specify (n1,n2,... numbers | |
1994 | above) from your input history into a single string. This variable |
|
1993 | above) from your input history into a single string. This variable | |
1995 | acts like an automatic function which re-executes those lines as if |
|
1994 | acts like an automatic function which re-executes those lines as if | |
1996 | you had typed them. You just type 'name' at the prompt and the code |
|
1995 | you had typed them. You just type 'name' at the prompt and the code | |
1997 | executes. |
|
1996 | executes. | |
1998 |
|
1997 | |||
1999 | The syntax for indicating input ranges is described in %history. |
|
1998 | The syntax for indicating input ranges is described in %history. | |
2000 |
|
1999 | |||
2001 | Note: as a 'hidden' feature, you can also use traditional python slice |
|
2000 | Note: as a 'hidden' feature, you can also use traditional python slice | |
2002 | notation, where N:M means numbers N through M-1. |
|
2001 | notation, where N:M means numbers N through M-1. | |
2003 |
|
2002 | |||
2004 | For example, if your history contains (%hist prints it): |
|
2003 | For example, if your history contains (%hist prints it): | |
2005 |
|
2004 | |||
2006 | 44: x=1 |
|
2005 | 44: x=1 | |
2007 | 45: y=3 |
|
2006 | 45: y=3 | |
2008 | 46: z=x+y |
|
2007 | 46: z=x+y | |
2009 | 47: print x |
|
2008 | 47: print x | |
2010 | 48: a=5 |
|
2009 | 48: a=5 | |
2011 | 49: print 'x',x,'y',y |
|
2010 | 49: print 'x',x,'y',y | |
2012 |
|
2011 | |||
2013 | you can create a macro with lines 44 through 47 (included) and line 49 |
|
2012 | you can create a macro with lines 44 through 47 (included) and line 49 | |
2014 | called my_macro with: |
|
2013 | called my_macro with: | |
2015 |
|
2014 | |||
2016 | In [55]: %macro my_macro 44-47 49 |
|
2015 | In [55]: %macro my_macro 44-47 49 | |
2017 |
|
2016 | |||
2018 | Now, typing `my_macro` (without quotes) will re-execute all this code |
|
2017 | Now, typing `my_macro` (without quotes) will re-execute all this code | |
2019 | in one pass. |
|
2018 | in one pass. | |
2020 |
|
2019 | |||
2021 | You don't need to give the line-numbers in order, and any given line |
|
2020 | You don't need to give the line-numbers in order, and any given line | |
2022 | number can appear multiple times. You can assemble macros with any |
|
2021 | number can appear multiple times. You can assemble macros with any | |
2023 | lines from your input history in any order. |
|
2022 | lines from your input history in any order. | |
2024 |
|
2023 | |||
2025 | The macro is a simple object which holds its value in an attribute, |
|
2024 | The macro is a simple object which holds its value in an attribute, | |
2026 | but IPython's display system checks for macros and executes them as |
|
2025 | but IPython's display system checks for macros and executes them as | |
2027 | code instead of printing them when you type their name. |
|
2026 | code instead of printing them when you type their name. | |
2028 |
|
2027 | |||
2029 | You can view a macro's contents by explicitly printing it with: |
|
2028 | You can view a macro's contents by explicitly printing it with: | |
2030 |
|
2029 | |||
2031 | 'print macro_name'. |
|
2030 | 'print macro_name'. | |
2032 |
|
2031 | |||
2033 | """ |
|
2032 | """ | |
2034 | opts,args = self.parse_options(parameter_s,'r',mode='list') |
|
2033 | opts,args = self.parse_options(parameter_s,'r',mode='list') | |
2035 | if not args: # List existing macros |
|
2034 | if not args: # List existing macros | |
2036 | return sorted(k for k,v in self.shell.user_ns.iteritems() if\ |
|
2035 | return sorted(k for k,v in self.shell.user_ns.iteritems() if\ | |
2037 | isinstance(v, Macro)) |
|
2036 | isinstance(v, Macro)) | |
2038 | if len(args) == 1: |
|
2037 | if len(args) == 1: | |
2039 | raise UsageError( |
|
2038 | raise UsageError( | |
2040 | "%macro insufficient args; usage '%macro name n1-n2 n3-4...") |
|
2039 | "%macro insufficient args; usage '%macro name n1-n2 n3-4...") | |
2041 | name, codefrom = args[0], " ".join(args[1:]) |
|
2040 | name, codefrom = args[0], " ".join(args[1:]) | |
2042 |
|
2041 | |||
2043 | #print 'rng',ranges # dbg |
|
2042 | #print 'rng',ranges # dbg | |
2044 | try: |
|
2043 | try: | |
2045 | lines = self.shell.find_user_code(codefrom, 'r' in opts) |
|
2044 | lines = self.shell.find_user_code(codefrom, 'r' in opts) | |
2046 | except (ValueError, TypeError) as e: |
|
2045 | except (ValueError, TypeError) as e: | |
2047 | print e.args[0] |
|
2046 | print e.args[0] | |
2048 | return |
|
2047 | return | |
2049 | macro = Macro(lines) |
|
2048 | macro = Macro(lines) | |
2050 | self.shell.define_macro(name, macro) |
|
2049 | self.shell.define_macro(name, macro) | |
2051 | print 'Macro `%s` created. To execute, type its name (without quotes).' % name |
|
2050 | print 'Macro `%s` created. To execute, type its name (without quotes).' % name | |
2052 | print '=== Macro contents: ===' |
|
2051 | print '=== Macro contents: ===' | |
2053 | print macro, |
|
2052 | print macro, | |
2054 |
|
2053 | |||
2055 | def magic_save(self,parameter_s = ''): |
|
2054 | def magic_save(self,parameter_s = ''): | |
2056 | """Save a set of lines or a macro to a given filename. |
|
2055 | """Save a set of lines or a macro to a given filename. | |
2057 |
|
2056 | |||
2058 | Usage:\\ |
|
2057 | Usage:\\ | |
2059 | %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ... |
|
2058 | %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ... | |
2060 |
|
2059 | |||
2061 | Options: |
|
2060 | Options: | |
2062 |
|
2061 | |||
2063 | -r: use 'raw' input. By default, the 'processed' history is used, |
|
2062 | -r: use 'raw' input. By default, the 'processed' history is used, | |
2064 | so that magics are loaded in their transformed version to valid |
|
2063 | so that magics are loaded in their transformed version to valid | |
2065 | Python. If this option is given, the raw input as typed as the |
|
2064 | Python. If this option is given, the raw input as typed as the | |
2066 | command line is used instead. |
|
2065 | command line is used instead. | |
2067 |
|
2066 | |||
2068 | This function uses the same syntax as %history for input ranges, |
|
2067 | This function uses the same syntax as %history for input ranges, | |
2069 | then saves the lines to the filename you specify. |
|
2068 | then saves the lines to the filename you specify. | |
2070 |
|
2069 | |||
2071 | It adds a '.py' extension to the file if you don't do so yourself, and |
|
2070 | It adds a '.py' extension to the file if you don't do so yourself, and | |
2072 | it asks for confirmation before overwriting existing files.""" |
|
2071 | it asks for confirmation before overwriting existing files.""" | |
2073 |
|
2072 | |||
2074 | opts,args = self.parse_options(parameter_s,'r',mode='list') |
|
2073 | opts,args = self.parse_options(parameter_s,'r',mode='list') | |
2075 | fname, codefrom = args[0], " ".join(args[1:]) |
|
2074 | fname, codefrom = args[0], " ".join(args[1:]) | |
2076 | if not fname.endswith('.py'): |
|
2075 | if not fname.endswith('.py'): | |
2077 | fname += '.py' |
|
2076 | fname += '.py' | |
2078 | if os.path.isfile(fname): |
|
2077 | if os.path.isfile(fname): | |
2079 | ans = raw_input('File `%s` exists. Overwrite (y/[N])? ' % fname) |
|
2078 | ans = raw_input('File `%s` exists. Overwrite (y/[N])? ' % fname) | |
2080 | if ans.lower() not in ['y','yes']: |
|
2079 | if ans.lower() not in ['y','yes']: | |
2081 | print 'Operation cancelled.' |
|
2080 | print 'Operation cancelled.' | |
2082 | return |
|
2081 | return | |
2083 | try: |
|
2082 | try: | |
2084 | cmds = self.shell.find_user_code(codefrom, 'r' in opts) |
|
2083 | cmds = self.shell.find_user_code(codefrom, 'r' in opts) | |
2085 | except (TypeError, ValueError) as e: |
|
2084 | except (TypeError, ValueError) as e: | |
2086 | print e.args[0] |
|
2085 | print e.args[0] | |
2087 | return |
|
2086 | return | |
2088 | if isinstance(cmds, unicode): |
|
2087 | if isinstance(cmds, unicode): | |
2089 | cmds = cmds.encode("utf-8") |
|
2088 | cmds = cmds.encode("utf-8") | |
2090 | with open(fname,'w') as f: |
|
2089 | with open(fname,'w') as f: | |
2091 | f.write("# coding: utf-8\n") |
|
2090 | f.write("# coding: utf-8\n") | |
2092 | f.write(cmds) |
|
2091 | f.write(cmds) | |
2093 | print 'The following commands were written to file `%s`:' % fname |
|
2092 | print 'The following commands were written to file `%s`:' % fname | |
2094 | print cmds |
|
2093 | print cmds | |
2095 |
|
2094 | |||
2096 | def magic_pastebin(self, parameter_s = ''): |
|
2095 | def magic_pastebin(self, parameter_s = ''): | |
2097 | """Upload code to the 'Lodge it' paste bin, returning the URL.""" |
|
2096 | """Upload code to the 'Lodge it' paste bin, returning the URL.""" | |
2098 | try: |
|
2097 | try: | |
2099 | code = self.shell.find_user_code(parameter_s) |
|
2098 | code = self.shell.find_user_code(parameter_s) | |
2100 | except (ValueError, TypeError) as e: |
|
2099 | except (ValueError, TypeError) as e: | |
2101 | print e.args[0] |
|
2100 | print e.args[0] | |
2102 | return |
|
2101 | return | |
2103 | pbserver = ServerProxy('http://paste.pocoo.org/xmlrpc/') |
|
2102 | pbserver = ServerProxy('http://paste.pocoo.org/xmlrpc/') | |
2104 | id = pbserver.pastes.newPaste("python", code) |
|
2103 | id = pbserver.pastes.newPaste("python", code) | |
2105 | return "http://paste.pocoo.org/show/" + id |
|
2104 | return "http://paste.pocoo.org/show/" + id | |
2106 |
|
2105 | |||
2107 | def magic_loadpy(self, arg_s): |
|
2106 | def magic_loadpy(self, arg_s): | |
2108 | """Load a .py python script into the GUI console. |
|
2107 | """Load a .py python script into the GUI console. | |
2109 |
|
2108 | |||
2110 | This magic command can either take a local filename or a url:: |
|
2109 | This magic command can either take a local filename or a url:: | |
2111 |
|
2110 | |||
2112 | %loadpy myscript.py |
|
2111 | %loadpy myscript.py | |
2113 | %loadpy http://www.example.com/myscript.py |
|
2112 | %loadpy http://www.example.com/myscript.py | |
2114 | """ |
|
2113 | """ | |
2115 | if not arg_s.endswith('.py'): |
|
2114 | if not arg_s.endswith('.py'): | |
2116 | raise ValueError('%%load only works with .py files: %s' % arg_s) |
|
2115 | raise ValueError('%%load only works with .py files: %s' % arg_s) | |
2117 | if arg_s.startswith('http'): |
|
2116 | if arg_s.startswith('http'): | |
2118 | import urllib2 |
|
2117 | import urllib2 | |
2119 | response = urllib2.urlopen(arg_s) |
|
2118 | response = urllib2.urlopen(arg_s) | |
2120 | content = response.read() |
|
2119 | content = response.read() | |
2121 | else: |
|
2120 | else: | |
2122 | with open(arg_s) as f: |
|
2121 | with open(arg_s) as f: | |
2123 | content = f.read() |
|
2122 | content = f.read() | |
2124 | self.set_next_input(content) |
|
2123 | self.set_next_input(content) | |
2125 |
|
2124 | |||
2126 | def _find_edit_target(self, args, opts, last_call): |
|
2125 | def _find_edit_target(self, args, opts, last_call): | |
2127 | """Utility method used by magic_edit to find what to edit.""" |
|
2126 | """Utility method used by magic_edit to find what to edit.""" | |
2128 |
|
2127 | |||
2129 | def make_filename(arg): |
|
2128 | def make_filename(arg): | |
2130 | "Make a filename from the given args" |
|
2129 | "Make a filename from the given args" | |
2131 | try: |
|
2130 | try: | |
2132 | filename = get_py_filename(arg) |
|
2131 | filename = get_py_filename(arg) | |
2133 | except IOError: |
|
2132 | except IOError: | |
2134 | # If it ends with .py but doesn't already exist, assume we want |
|
2133 | # If it ends with .py but doesn't already exist, assume we want | |
2135 | # a new file. |
|
2134 | # a new file. | |
2136 | if args.endswith('.py'): |
|
2135 | if args.endswith('.py'): | |
2137 | filename = arg |
|
2136 | filename = arg | |
2138 | else: |
|
2137 | else: | |
2139 | filename = None |
|
2138 | filename = None | |
2140 | return filename |
|
2139 | return filename | |
2141 |
|
2140 | |||
2142 | # Set a few locals from the options for convenience: |
|
2141 | # Set a few locals from the options for convenience: | |
2143 | opts_prev = 'p' in opts |
|
2142 | opts_prev = 'p' in opts | |
2144 | opts_raw = 'r' in opts |
|
2143 | opts_raw = 'r' in opts | |
2145 |
|
2144 | |||
2146 | # custom exceptions |
|
2145 | # custom exceptions | |
2147 | class DataIsObject(Exception): pass |
|
2146 | class DataIsObject(Exception): pass | |
2148 |
|
2147 | |||
2149 | # Default line number value |
|
2148 | # Default line number value | |
2150 | lineno = opts.get('n',None) |
|
2149 | lineno = opts.get('n',None) | |
2151 |
|
2150 | |||
2152 | if opts_prev: |
|
2151 | if opts_prev: | |
2153 | args = '_%s' % last_call[0] |
|
2152 | args = '_%s' % last_call[0] | |
2154 | if not self.shell.user_ns.has_key(args): |
|
2153 | if not self.shell.user_ns.has_key(args): | |
2155 | args = last_call[1] |
|
2154 | args = last_call[1] | |
2156 |
|
2155 | |||
2157 | # use last_call to remember the state of the previous call, but don't |
|
2156 | # use last_call to remember the state of the previous call, but don't | |
2158 | # let it be clobbered by successive '-p' calls. |
|
2157 | # let it be clobbered by successive '-p' calls. | |
2159 | try: |
|
2158 | try: | |
2160 | last_call[0] = self.shell.displayhook.prompt_count |
|
2159 | last_call[0] = self.shell.displayhook.prompt_count | |
2161 | if not opts_prev: |
|
2160 | if not opts_prev: | |
2162 | last_call[1] = parameter_s |
|
2161 | last_call[1] = parameter_s | |
2163 | except: |
|
2162 | except: | |
2164 | pass |
|
2163 | pass | |
2165 |
|
2164 | |||
2166 | # by default this is done with temp files, except when the given |
|
2165 | # by default this is done with temp files, except when the given | |
2167 | # arg is a filename |
|
2166 | # arg is a filename | |
2168 | use_temp = True |
|
2167 | use_temp = True | |
2169 |
|
2168 | |||
2170 | data = '' |
|
2169 | data = '' | |
2171 |
|
2170 | |||
2172 | # First, see if the arguments should be a filename. |
|
2171 | # First, see if the arguments should be a filename. | |
2173 | filename = make_filename(args) |
|
2172 | filename = make_filename(args) | |
2174 | if filename: |
|
2173 | if filename: | |
2175 | use_temp = False |
|
2174 | use_temp = False | |
2176 | elif args: |
|
2175 | elif args: | |
2177 | # Mode where user specifies ranges of lines, like in %macro. |
|
2176 | # Mode where user specifies ranges of lines, like in %macro. | |
2178 | data = self.extract_input_lines(args, opts_raw) |
|
2177 | data = self.extract_input_lines(args, opts_raw) | |
2179 | if not data: |
|
2178 | if not data: | |
2180 | try: |
|
2179 | try: | |
2181 | # Load the parameter given as a variable. If not a string, |
|
2180 | # Load the parameter given as a variable. If not a string, | |
2182 | # process it as an object instead (below) |
|
2181 | # process it as an object instead (below) | |
2183 |
|
2182 | |||
2184 | #print '*** args',args,'type',type(args) # dbg |
|
2183 | #print '*** args',args,'type',type(args) # dbg | |
2185 | data = eval(args, self.shell.user_ns) |
|
2184 | data = eval(args, self.shell.user_ns) | |
2186 | if not isinstance(data, basestring): |
|
2185 | if not isinstance(data, basestring): | |
2187 | raise DataIsObject |
|
2186 | raise DataIsObject | |
2188 |
|
2187 | |||
2189 | except (NameError,SyntaxError): |
|
2188 | except (NameError,SyntaxError): | |
2190 | # given argument is not a variable, try as a filename |
|
2189 | # given argument is not a variable, try as a filename | |
2191 | filename = make_filename(args) |
|
2190 | filename = make_filename(args) | |
2192 | if filename is None: |
|
2191 | if filename is None: | |
2193 | warn("Argument given (%s) can't be found as a variable " |
|
2192 | warn("Argument given (%s) can't be found as a variable " | |
2194 | "or as a filename." % args) |
|
2193 | "or as a filename." % args) | |
2195 | return |
|
2194 | return | |
2196 | use_temp = False |
|
2195 | use_temp = False | |
2197 |
|
2196 | |||
2198 | except DataIsObject: |
|
2197 | except DataIsObject: | |
2199 | # macros have a special edit function |
|
2198 | # macros have a special edit function | |
2200 | if isinstance(data, Macro): |
|
2199 | if isinstance(data, Macro): | |
2201 | raise MacroToEdit(data) |
|
2200 | raise MacroToEdit(data) | |
2202 |
|
2201 | |||
2203 | # For objects, try to edit the file where they are defined |
|
2202 | # For objects, try to edit the file where they are defined | |
2204 | try: |
|
2203 | try: | |
2205 | filename = inspect.getabsfile(data) |
|
2204 | filename = inspect.getabsfile(data) | |
2206 | if 'fakemodule' in filename.lower() and inspect.isclass(data): |
|
2205 | if 'fakemodule' in filename.lower() and inspect.isclass(data): | |
2207 | # class created by %edit? Try to find source |
|
2206 | # class created by %edit? Try to find source | |
2208 | # by looking for method definitions instead, the |
|
2207 | # by looking for method definitions instead, the | |
2209 | # __module__ in those classes is FakeModule. |
|
2208 | # __module__ in those classes is FakeModule. | |
2210 | attrs = [getattr(data, aname) for aname in dir(data)] |
|
2209 | attrs = [getattr(data, aname) for aname in dir(data)] | |
2211 | for attr in attrs: |
|
2210 | for attr in attrs: | |
2212 | if not inspect.ismethod(attr): |
|
2211 | if not inspect.ismethod(attr): | |
2213 | continue |
|
2212 | continue | |
2214 | filename = inspect.getabsfile(attr) |
|
2213 | filename = inspect.getabsfile(attr) | |
2215 | if filename and 'fakemodule' not in filename.lower(): |
|
2214 | if filename and 'fakemodule' not in filename.lower(): | |
2216 | # change the attribute to be the edit target instead |
|
2215 | # change the attribute to be the edit target instead | |
2217 | data = attr |
|
2216 | data = attr | |
2218 | break |
|
2217 | break | |
2219 |
|
2218 | |||
2220 | datafile = 1 |
|
2219 | datafile = 1 | |
2221 | except TypeError: |
|
2220 | except TypeError: | |
2222 | filename = make_filename(args) |
|
2221 | filename = make_filename(args) | |
2223 | datafile = 1 |
|
2222 | datafile = 1 | |
2224 | warn('Could not find file where `%s` is defined.\n' |
|
2223 | warn('Could not find file where `%s` is defined.\n' | |
2225 | 'Opening a file named `%s`' % (args,filename)) |
|
2224 | 'Opening a file named `%s`' % (args,filename)) | |
2226 | # Now, make sure we can actually read the source (if it was in |
|
2225 | # Now, make sure we can actually read the source (if it was in | |
2227 | # a temp file it's gone by now). |
|
2226 | # a temp file it's gone by now). | |
2228 | if datafile: |
|
2227 | if datafile: | |
2229 | try: |
|
2228 | try: | |
2230 | if lineno is None: |
|
2229 | if lineno is None: | |
2231 | lineno = inspect.getsourcelines(data)[1] |
|
2230 | lineno = inspect.getsourcelines(data)[1] | |
2232 | except IOError: |
|
2231 | except IOError: | |
2233 | filename = make_filename(args) |
|
2232 | filename = make_filename(args) | |
2234 | if filename is None: |
|
2233 | if filename is None: | |
2235 | warn('The file `%s` where `%s` was defined cannot ' |
|
2234 | warn('The file `%s` where `%s` was defined cannot ' | |
2236 | 'be read.' % (filename,data)) |
|
2235 | 'be read.' % (filename,data)) | |
2237 | return |
|
2236 | return | |
2238 | use_temp = False |
|
2237 | use_temp = False | |
2239 |
|
2238 | |||
2240 | if use_temp: |
|
2239 | if use_temp: | |
2241 | filename = self.shell.mktempfile(data) |
|
2240 | filename = self.shell.mktempfile(data) | |
2242 | print 'IPython will make a temporary file named:',filename |
|
2241 | print 'IPython will make a temporary file named:',filename | |
2243 |
|
2242 | |||
2244 | return filename, lineno, use_temp |
|
2243 | return filename, lineno, use_temp | |
2245 |
|
2244 | |||
2246 | def _edit_macro(self,mname,macro): |
|
2245 | def _edit_macro(self,mname,macro): | |
2247 | """open an editor with the macro data in a file""" |
|
2246 | """open an editor with the macro data in a file""" | |
2248 | filename = self.shell.mktempfile(macro.value) |
|
2247 | filename = self.shell.mktempfile(macro.value) | |
2249 | self.shell.hooks.editor(filename) |
|
2248 | self.shell.hooks.editor(filename) | |
2250 |
|
2249 | |||
2251 | # and make a new macro object, to replace the old one |
|
2250 | # and make a new macro object, to replace the old one | |
2252 | mfile = open(filename) |
|
2251 | mfile = open(filename) | |
2253 | mvalue = mfile.read() |
|
2252 | mvalue = mfile.read() | |
2254 | mfile.close() |
|
2253 | mfile.close() | |
2255 | self.shell.user_ns[mname] = Macro(mvalue) |
|
2254 | self.shell.user_ns[mname] = Macro(mvalue) | |
2256 |
|
2255 | |||
2257 | def magic_ed(self,parameter_s=''): |
|
2256 | def magic_ed(self,parameter_s=''): | |
2258 | """Alias to %edit.""" |
|
2257 | """Alias to %edit.""" | |
2259 | return self.magic_edit(parameter_s) |
|
2258 | return self.magic_edit(parameter_s) | |
2260 |
|
2259 | |||
2261 | @skip_doctest |
|
2260 | @skip_doctest | |
2262 | def magic_edit(self,parameter_s='',last_call=['','']): |
|
2261 | def magic_edit(self,parameter_s='',last_call=['','']): | |
2263 | """Bring up an editor and execute the resulting code. |
|
2262 | """Bring up an editor and execute the resulting code. | |
2264 |
|
2263 | |||
2265 | Usage: |
|
2264 | Usage: | |
2266 | %edit [options] [args] |
|
2265 | %edit [options] [args] | |
2267 |
|
2266 | |||
2268 | %edit runs IPython's editor hook. The default version of this hook is |
|
2267 | %edit runs IPython's editor hook. The default version of this hook is | |
2269 | set to call the __IPYTHON__.rc.editor command. This is read from your |
|
2268 | set to call the __IPYTHON__.rc.editor command. This is read from your | |
2270 | environment variable $EDITOR. If this isn't found, it will default to |
|
2269 | environment variable $EDITOR. If this isn't found, it will default to | |
2271 | vi under Linux/Unix and to notepad under Windows. See the end of this |
|
2270 | vi under Linux/Unix and to notepad under Windows. See the end of this | |
2272 | docstring for how to change the editor hook. |
|
2271 | docstring for how to change the editor hook. | |
2273 |
|
2272 | |||
2274 | You can also set the value of this editor via the command line option |
|
2273 | You can also set the value of this editor via the command line option | |
2275 | '-editor' or in your ipythonrc file. This is useful if you wish to use |
|
2274 | '-editor' or in your ipythonrc file. This is useful if you wish to use | |
2276 | specifically for IPython an editor different from your typical default |
|
2275 | specifically for IPython an editor different from your typical default | |
2277 | (and for Windows users who typically don't set environment variables). |
|
2276 | (and for Windows users who typically don't set environment variables). | |
2278 |
|
2277 | |||
2279 | This command allows you to conveniently edit multi-line code right in |
|
2278 | This command allows you to conveniently edit multi-line code right in | |
2280 | your IPython session. |
|
2279 | your IPython session. | |
2281 |
|
2280 | |||
2282 | If called without arguments, %edit opens up an empty editor with a |
|
2281 | If called without arguments, %edit opens up an empty editor with a | |
2283 | temporary file and will execute the contents of this file when you |
|
2282 | temporary file and will execute the contents of this file when you | |
2284 | close it (don't forget to save it!). |
|
2283 | close it (don't forget to save it!). | |
2285 |
|
2284 | |||
2286 |
|
2285 | |||
2287 | Options: |
|
2286 | Options: | |
2288 |
|
2287 | |||
2289 | -n <number>: open the editor at a specified line number. By default, |
|
2288 | -n <number>: open the editor at a specified line number. By default, | |
2290 | the IPython editor hook uses the unix syntax 'editor +N filename', but |
|
2289 | the IPython editor hook uses the unix syntax 'editor +N filename', but | |
2291 | you can configure this by providing your own modified hook if your |
|
2290 | you can configure this by providing your own modified hook if your | |
2292 | favorite editor supports line-number specifications with a different |
|
2291 | favorite editor supports line-number specifications with a different | |
2293 | syntax. |
|
2292 | syntax. | |
2294 |
|
2293 | |||
2295 | -p: this will call the editor with the same data as the previous time |
|
2294 | -p: this will call the editor with the same data as the previous time | |
2296 | it was used, regardless of how long ago (in your current session) it |
|
2295 | it was used, regardless of how long ago (in your current session) it | |
2297 | was. |
|
2296 | was. | |
2298 |
|
2297 | |||
2299 | -r: use 'raw' input. This option only applies to input taken from the |
|
2298 | -r: use 'raw' input. This option only applies to input taken from the | |
2300 | user's history. By default, the 'processed' history is used, so that |
|
2299 | user's history. By default, the 'processed' history is used, so that | |
2301 | magics are loaded in their transformed version to valid Python. If |
|
2300 | magics are loaded in their transformed version to valid Python. If | |
2302 | this option is given, the raw input as typed as the command line is |
|
2301 | this option is given, the raw input as typed as the command line is | |
2303 | used instead. When you exit the editor, it will be executed by |
|
2302 | used instead. When you exit the editor, it will be executed by | |
2304 | IPython's own processor. |
|
2303 | IPython's own processor. | |
2305 |
|
2304 | |||
2306 | -x: do not execute the edited code immediately upon exit. This is |
|
2305 | -x: do not execute the edited code immediately upon exit. This is | |
2307 | mainly useful if you are editing programs which need to be called with |
|
2306 | mainly useful if you are editing programs which need to be called with | |
2308 | command line arguments, which you can then do using %run. |
|
2307 | command line arguments, which you can then do using %run. | |
2309 |
|
2308 | |||
2310 |
|
2309 | |||
2311 | Arguments: |
|
2310 | Arguments: | |
2312 |
|
2311 | |||
2313 | If arguments are given, the following possibilites exist: |
|
2312 | If arguments are given, the following possibilites exist: | |
2314 |
|
2313 | |||
2315 | - If the argument is a filename, IPython will load that into the |
|
2314 | - If the argument is a filename, IPython will load that into the | |
2316 | editor. It will execute its contents with execfile() when you exit, |
|
2315 | editor. It will execute its contents with execfile() when you exit, | |
2317 | loading any code in the file into your interactive namespace. |
|
2316 | loading any code in the file into your interactive namespace. | |
2318 |
|
2317 | |||
2319 | - The arguments are ranges of input history, e.g. "7 ~1/4-6". |
|
2318 | - The arguments are ranges of input history, e.g. "7 ~1/4-6". | |
2320 | The syntax is the same as in the %history magic. |
|
2319 | The syntax is the same as in the %history magic. | |
2321 |
|
2320 | |||
2322 | - If the argument is a string variable, its contents are loaded |
|
2321 | - If the argument is a string variable, its contents are loaded | |
2323 | into the editor. You can thus edit any string which contains |
|
2322 | into the editor. You can thus edit any string which contains | |
2324 | python code (including the result of previous edits). |
|
2323 | python code (including the result of previous edits). | |
2325 |
|
2324 | |||
2326 | - If the argument is the name of an object (other than a string), |
|
2325 | - If the argument is the name of an object (other than a string), | |
2327 | IPython will try to locate the file where it was defined and open the |
|
2326 | IPython will try to locate the file where it was defined and open the | |
2328 | editor at the point where it is defined. You can use `%edit function` |
|
2327 | editor at the point where it is defined. You can use `%edit function` | |
2329 | to load an editor exactly at the point where 'function' is defined, |
|
2328 | to load an editor exactly at the point where 'function' is defined, | |
2330 | edit it and have the file be executed automatically. |
|
2329 | edit it and have the file be executed automatically. | |
2331 |
|
2330 | |||
2332 | If the object is a macro (see %macro for details), this opens up your |
|
2331 | If the object is a macro (see %macro for details), this opens up your | |
2333 | specified editor with a temporary file containing the macro's data. |
|
2332 | specified editor with a temporary file containing the macro's data. | |
2334 | Upon exit, the macro is reloaded with the contents of the file. |
|
2333 | Upon exit, the macro is reloaded with the contents of the file. | |
2335 |
|
2334 | |||
2336 | Note: opening at an exact line is only supported under Unix, and some |
|
2335 | Note: opening at an exact line is only supported under Unix, and some | |
2337 | editors (like kedit and gedit up to Gnome 2.8) do not understand the |
|
2336 | editors (like kedit and gedit up to Gnome 2.8) do not understand the | |
2338 | '+NUMBER' parameter necessary for this feature. Good editors like |
|
2337 | '+NUMBER' parameter necessary for this feature. Good editors like | |
2339 | (X)Emacs, vi, jed, pico and joe all do. |
|
2338 | (X)Emacs, vi, jed, pico and joe all do. | |
2340 |
|
2339 | |||
2341 | After executing your code, %edit will return as output the code you |
|
2340 | After executing your code, %edit will return as output the code you | |
2342 | typed in the editor (except when it was an existing file). This way |
|
2341 | typed in the editor (except when it was an existing file). This way | |
2343 | you can reload the code in further invocations of %edit as a variable, |
|
2342 | you can reload the code in further invocations of %edit as a variable, | |
2344 | via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of |
|
2343 | via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of | |
2345 | the output. |
|
2344 | the output. | |
2346 |
|
2345 | |||
2347 | Note that %edit is also available through the alias %ed. |
|
2346 | Note that %edit is also available through the alias %ed. | |
2348 |
|
2347 | |||
2349 | This is an example of creating a simple function inside the editor and |
|
2348 | This is an example of creating a simple function inside the editor and | |
2350 | then modifying it. First, start up the editor: |
|
2349 | then modifying it. First, start up the editor: | |
2351 |
|
2350 | |||
2352 | In [1]: ed |
|
2351 | In [1]: ed | |
2353 | Editing... done. Executing edited code... |
|
2352 | Editing... done. Executing edited code... | |
2354 | Out[1]: 'def foo():n print "foo() was defined in an editing session"n' |
|
2353 | Out[1]: 'def foo():n print "foo() was defined in an editing session"n' | |
2355 |
|
2354 | |||
2356 | We can then call the function foo(): |
|
2355 | We can then call the function foo(): | |
2357 |
|
2356 | |||
2358 | In [2]: foo() |
|
2357 | In [2]: foo() | |
2359 | foo() was defined in an editing session |
|
2358 | foo() was defined in an editing session | |
2360 |
|
2359 | |||
2361 | Now we edit foo. IPython automatically loads the editor with the |
|
2360 | Now we edit foo. IPython automatically loads the editor with the | |
2362 | (temporary) file where foo() was previously defined: |
|
2361 | (temporary) file where foo() was previously defined: | |
2363 |
|
2362 | |||
2364 | In [3]: ed foo |
|
2363 | In [3]: ed foo | |
2365 | Editing... done. Executing edited code... |
|
2364 | Editing... done. Executing edited code... | |
2366 |
|
2365 | |||
2367 | And if we call foo() again we get the modified version: |
|
2366 | And if we call foo() again we get the modified version: | |
2368 |
|
2367 | |||
2369 | In [4]: foo() |
|
2368 | In [4]: foo() | |
2370 | foo() has now been changed! |
|
2369 | foo() has now been changed! | |
2371 |
|
2370 | |||
2372 | Here is an example of how to edit a code snippet successive |
|
2371 | Here is an example of how to edit a code snippet successive | |
2373 | times. First we call the editor: |
|
2372 | times. First we call the editor: | |
2374 |
|
2373 | |||
2375 | In [5]: ed |
|
2374 | In [5]: ed | |
2376 | Editing... done. Executing edited code... |
|
2375 | Editing... done. Executing edited code... | |
2377 | hello |
|
2376 | hello | |
2378 | Out[5]: "print 'hello'n" |
|
2377 | Out[5]: "print 'hello'n" | |
2379 |
|
2378 | |||
2380 | Now we call it again with the previous output (stored in _): |
|
2379 | Now we call it again with the previous output (stored in _): | |
2381 |
|
2380 | |||
2382 | In [6]: ed _ |
|
2381 | In [6]: ed _ | |
2383 | Editing... done. Executing edited code... |
|
2382 | Editing... done. Executing edited code... | |
2384 | hello world |
|
2383 | hello world | |
2385 | Out[6]: "print 'hello world'n" |
|
2384 | Out[6]: "print 'hello world'n" | |
2386 |
|
2385 | |||
2387 | Now we call it with the output #8 (stored in _8, also as Out[8]): |
|
2386 | Now we call it with the output #8 (stored in _8, also as Out[8]): | |
2388 |
|
2387 | |||
2389 | In [7]: ed _8 |
|
2388 | In [7]: ed _8 | |
2390 | Editing... done. Executing edited code... |
|
2389 | Editing... done. Executing edited code... | |
2391 | hello again |
|
2390 | hello again | |
2392 | Out[7]: "print 'hello again'n" |
|
2391 | Out[7]: "print 'hello again'n" | |
2393 |
|
2392 | |||
2394 |
|
2393 | |||
2395 | Changing the default editor hook: |
|
2394 | Changing the default editor hook: | |
2396 |
|
2395 | |||
2397 | If you wish to write your own editor hook, you can put it in a |
|
2396 | If you wish to write your own editor hook, you can put it in a | |
2398 | configuration file which you load at startup time. The default hook |
|
2397 | configuration file which you load at startup time. The default hook | |
2399 | is defined in the IPython.core.hooks module, and you can use that as a |
|
2398 | is defined in the IPython.core.hooks module, and you can use that as a | |
2400 | starting example for further modifications. That file also has |
|
2399 | starting example for further modifications. That file also has | |
2401 | general instructions on how to set a new hook for use once you've |
|
2400 | general instructions on how to set a new hook for use once you've | |
2402 | defined it.""" |
|
2401 | defined it.""" | |
2403 | opts,args = self.parse_options(parameter_s,'prxn:') |
|
2402 | opts,args = self.parse_options(parameter_s,'prxn:') | |
2404 |
|
2403 | |||
2405 | try: |
|
2404 | try: | |
2406 | filename, lineno, is_temp = self._find_edit_target(args, opts, last_call) |
|
2405 | filename, lineno, is_temp = self._find_edit_target(args, opts, last_call) | |
2407 | except MacroToEdit as e: |
|
2406 | except MacroToEdit as e: | |
2408 | self._edit_macro(args, e.args[0]) |
|
2407 | self._edit_macro(args, e.args[0]) | |
2409 | return |
|
2408 | return | |
2410 |
|
2409 | |||
2411 | # do actual editing here |
|
2410 | # do actual editing here | |
2412 | print 'Editing...', |
|
2411 | print 'Editing...', | |
2413 | sys.stdout.flush() |
|
2412 | sys.stdout.flush() | |
2414 | try: |
|
2413 | try: | |
2415 | # Quote filenames that may have spaces in them |
|
2414 | # Quote filenames that may have spaces in them | |
2416 | if ' ' in filename: |
|
2415 | if ' ' in filename: | |
2417 | filename = "'%s'" % filename |
|
2416 | filename = "'%s'" % filename | |
2418 | self.shell.hooks.editor(filename,lineno) |
|
2417 | self.shell.hooks.editor(filename,lineno) | |
2419 | except TryNext: |
|
2418 | except TryNext: | |
2420 | warn('Could not open editor') |
|
2419 | warn('Could not open editor') | |
2421 | return |
|
2420 | return | |
2422 |
|
2421 | |||
2423 | # XXX TODO: should this be generalized for all string vars? |
|
2422 | # XXX TODO: should this be generalized for all string vars? | |
2424 | # For now, this is special-cased to blocks created by cpaste |
|
2423 | # For now, this is special-cased to blocks created by cpaste | |
2425 | if args.strip() == 'pasted_block': |
|
2424 | if args.strip() == 'pasted_block': | |
2426 | self.shell.user_ns['pasted_block'] = file_read(filename) |
|
2425 | self.shell.user_ns['pasted_block'] = file_read(filename) | |
2427 |
|
2426 | |||
2428 | if 'x' in opts: # -x prevents actual execution |
|
2427 | if 'x' in opts: # -x prevents actual execution | |
2429 |
|
2428 | |||
2430 | else: |
|
2429 | else: | |
2431 | print 'done. Executing edited code...' |
|
2430 | print 'done. Executing edited code...' | |
2432 | if 'r' in opts: # Untranslated IPython code |
|
2431 | if 'r' in opts: # Untranslated IPython code | |
2433 | self.shell.run_cell(file_read(filename), |
|
2432 | self.shell.run_cell(file_read(filename), | |
2434 | store_history=False) |
|
2433 | store_history=False) | |
2435 | else: |
|
2434 | else: | |
2436 | self.shell.safe_execfile(filename,self.shell.user_ns, |
|
2435 | self.shell.safe_execfile(filename,self.shell.user_ns, | |
2437 | self.shell.user_ns) |
|
2436 | self.shell.user_ns) | |
2438 |
|
2437 | |||
2439 | if is_temp: |
|
2438 | if is_temp: | |
2440 | try: |
|
2439 | try: | |
2441 | return open(filename).read() |
|
2440 | return open(filename).read() | |
2442 | except IOError,msg: |
|
2441 | except IOError,msg: | |
2443 | if msg.filename == filename: |
|
2442 | if msg.filename == filename: | |
2444 | warn('File not found. Did you forget to save?') |
|
2443 | warn('File not found. Did you forget to save?') | |
2445 | return |
|
2444 | return | |
2446 | else: |
|
2445 | else: | |
2447 | self.shell.showtraceback() |
|
2446 | self.shell.showtraceback() | |
2448 |
|
2447 | |||
2449 | def magic_xmode(self,parameter_s = ''): |
|
2448 | def magic_xmode(self,parameter_s = ''): | |
2450 | """Switch modes for the exception handlers. |
|
2449 | """Switch modes for the exception handlers. | |
2451 |
|
2450 | |||
2452 | Valid modes: Plain, Context and Verbose. |
|
2451 | Valid modes: Plain, Context and Verbose. | |
2453 |
|
2452 | |||
2454 | If called without arguments, acts as a toggle.""" |
|
2453 | If called without arguments, acts as a toggle.""" | |
2455 |
|
2454 | |||
2456 | def xmode_switch_err(name): |
|
2455 | def xmode_switch_err(name): | |
2457 | warn('Error changing %s exception modes.\n%s' % |
|
2456 | warn('Error changing %s exception modes.\n%s' % | |
2458 | (name,sys.exc_info()[1])) |
|
2457 | (name,sys.exc_info()[1])) | |
2459 |
|
2458 | |||
2460 | shell = self.shell |
|
2459 | shell = self.shell | |
2461 | new_mode = parameter_s.strip().capitalize() |
|
2460 | new_mode = parameter_s.strip().capitalize() | |
2462 | try: |
|
2461 | try: | |
2463 | shell.InteractiveTB.set_mode(mode=new_mode) |
|
2462 | shell.InteractiveTB.set_mode(mode=new_mode) | |
2464 | print 'Exception reporting mode:',shell.InteractiveTB.mode |
|
2463 | print 'Exception reporting mode:',shell.InteractiveTB.mode | |
2465 | except: |
|
2464 | except: | |
2466 | xmode_switch_err('user') |
|
2465 | xmode_switch_err('user') | |
2467 |
|
2466 | |||
2468 | def magic_colors(self,parameter_s = ''): |
|
2467 | def magic_colors(self,parameter_s = ''): | |
2469 | """Switch color scheme for prompts, info system and exception handlers. |
|
2468 | """Switch color scheme for prompts, info system and exception handlers. | |
2470 |
|
2469 | |||
2471 | Currently implemented schemes: NoColor, Linux, LightBG. |
|
2470 | Currently implemented schemes: NoColor, Linux, LightBG. | |
2472 |
|
2471 | |||
2473 | Color scheme names are not case-sensitive. |
|
2472 | Color scheme names are not case-sensitive. | |
2474 |
|
2473 | |||
2475 | Examples |
|
2474 | Examples | |
2476 | -------- |
|
2475 | -------- | |
2477 | To get a plain black and white terminal:: |
|
2476 | To get a plain black and white terminal:: | |
2478 |
|
2477 | |||
2479 | %colors nocolor |
|
2478 | %colors nocolor | |
2480 | """ |
|
2479 | """ | |
2481 |
|
2480 | |||
2482 | def color_switch_err(name): |
|
2481 | def color_switch_err(name): | |
2483 | warn('Error changing %s color schemes.\n%s' % |
|
2482 | warn('Error changing %s color schemes.\n%s' % | |
2484 | (name,sys.exc_info()[1])) |
|
2483 | (name,sys.exc_info()[1])) | |
2485 |
|
2484 | |||
2486 |
|
2485 | |||
2487 | new_scheme = parameter_s.strip() |
|
2486 | new_scheme = parameter_s.strip() | |
2488 | if not new_scheme: |
|
2487 | if not new_scheme: | |
2489 | raise UsageError( |
|
2488 | raise UsageError( | |
2490 | "%colors: you must specify a color scheme. See '%colors?'") |
|
2489 | "%colors: you must specify a color scheme. See '%colors?'") | |
2491 | return |
|
2490 | return | |
2492 | # local shortcut |
|
2491 | # local shortcut | |
2493 | shell = self.shell |
|
2492 | shell = self.shell | |
2494 |
|
2493 | |||
2495 | import IPython.utils.rlineimpl as readline |
|
2494 | import IPython.utils.rlineimpl as readline | |
2496 |
|
2495 | |||
2497 | if not readline.have_readline and sys.platform == "win32": |
|
2496 | if not readline.have_readline and sys.platform == "win32": | |
2498 | msg = """\ |
|
2497 | msg = """\ | |
2499 | Proper color support under MS Windows requires the pyreadline library. |
|
2498 | Proper color support under MS Windows requires the pyreadline library. | |
2500 | You can find it at: |
|
2499 | You can find it at: | |
2501 | http://ipython.scipy.org/moin/PyReadline/Intro |
|
2500 | http://ipython.scipy.org/moin/PyReadline/Intro | |
2502 | Gary's readline needs the ctypes module, from: |
|
2501 | Gary's readline needs the ctypes module, from: | |
2503 | http://starship.python.net/crew/theller/ctypes |
|
2502 | http://starship.python.net/crew/theller/ctypes | |
2504 | (Note that ctypes is already part of Python versions 2.5 and newer). |
|
2503 | (Note that ctypes is already part of Python versions 2.5 and newer). | |
2505 |
|
2504 | |||
2506 | Defaulting color scheme to 'NoColor'""" |
|
2505 | Defaulting color scheme to 'NoColor'""" | |
2507 | new_scheme = 'NoColor' |
|
2506 | new_scheme = 'NoColor' | |
2508 | warn(msg) |
|
2507 | warn(msg) | |
2509 |
|
2508 | |||
2510 | # readline option is 0 |
|
2509 | # readline option is 0 | |
2511 | if not shell.has_readline: |
|
2510 | if not shell.has_readline: | |
2512 | new_scheme = 'NoColor' |
|
2511 | new_scheme = 'NoColor' | |
2513 |
|
2512 | |||
2514 | # Set prompt colors |
|
2513 | # Set prompt colors | |
2515 | try: |
|
2514 | try: | |
2516 | shell.displayhook.set_colors(new_scheme) |
|
2515 | shell.displayhook.set_colors(new_scheme) | |
2517 | except: |
|
2516 | except: | |
2518 | color_switch_err('prompt') |
|
2517 | color_switch_err('prompt') | |
2519 | else: |
|
2518 | else: | |
2520 | shell.colors = \ |
|
2519 | shell.colors = \ | |
2521 | shell.displayhook.color_table.active_scheme_name |
|
2520 | shell.displayhook.color_table.active_scheme_name | |
2522 | # Set exception colors |
|
2521 | # Set exception colors | |
2523 | try: |
|
2522 | try: | |
2524 | shell.InteractiveTB.set_colors(scheme = new_scheme) |
|
2523 | shell.InteractiveTB.set_colors(scheme = new_scheme) | |
2525 | shell.SyntaxTB.set_colors(scheme = new_scheme) |
|
2524 | shell.SyntaxTB.set_colors(scheme = new_scheme) | |
2526 | except: |
|
2525 | except: | |
2527 | color_switch_err('exception') |
|
2526 | color_switch_err('exception') | |
2528 |
|
2527 | |||
2529 | # Set info (for 'object?') colors |
|
2528 | # Set info (for 'object?') colors | |
2530 | if shell.color_info: |
|
2529 | if shell.color_info: | |
2531 | try: |
|
2530 | try: | |
2532 | shell.inspector.set_active_scheme(new_scheme) |
|
2531 | shell.inspector.set_active_scheme(new_scheme) | |
2533 | except: |
|
2532 | except: | |
2534 | color_switch_err('object inspector') |
|
2533 | color_switch_err('object inspector') | |
2535 | else: |
|
2534 | else: | |
2536 | shell.inspector.set_active_scheme('NoColor') |
|
2535 | shell.inspector.set_active_scheme('NoColor') | |
2537 |
|
2536 | |||
2538 | def magic_pprint(self, parameter_s=''): |
|
2537 | def magic_pprint(self, parameter_s=''): | |
2539 | """Toggle pretty printing on/off.""" |
|
2538 | """Toggle pretty printing on/off.""" | |
2540 | ptformatter = self.shell.display_formatter.formatters['text/plain'] |
|
2539 | ptformatter = self.shell.display_formatter.formatters['text/plain'] | |
2541 | ptformatter.pprint = bool(1 - ptformatter.pprint) |
|
2540 | ptformatter.pprint = bool(1 - ptformatter.pprint) | |
2542 | print 'Pretty printing has been turned', \ |
|
2541 | print 'Pretty printing has been turned', \ | |
2543 | ['OFF','ON'][ptformatter.pprint] |
|
2542 | ['OFF','ON'][ptformatter.pprint] | |
2544 |
|
2543 | |||
2545 | #...................................................................... |
|
2544 | #...................................................................... | |
2546 | # Functions to implement unix shell-type things |
|
2545 | # Functions to implement unix shell-type things | |
2547 |
|
2546 | |||
2548 | @skip_doctest |
|
2547 | @skip_doctest | |
2549 | def magic_alias(self, parameter_s = ''): |
|
2548 | def magic_alias(self, parameter_s = ''): | |
2550 | """Define an alias for a system command. |
|
2549 | """Define an alias for a system command. | |
2551 |
|
2550 | |||
2552 | '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd' |
|
2551 | '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd' | |
2553 |
|
2552 | |||
2554 | Then, typing 'alias_name params' will execute the system command 'cmd |
|
2553 | Then, typing 'alias_name params' will execute the system command 'cmd | |
2555 | params' (from your underlying operating system). |
|
2554 | params' (from your underlying operating system). | |
2556 |
|
2555 | |||
2557 | Aliases have lower precedence than magic functions and Python normal |
|
2556 | Aliases have lower precedence than magic functions and Python normal | |
2558 | variables, so if 'foo' is both a Python variable and an alias, the |
|
2557 | variables, so if 'foo' is both a Python variable and an alias, the | |
2559 | alias can not be executed until 'del foo' removes the Python variable. |
|
2558 | alias can not be executed until 'del foo' removes the Python variable. | |
2560 |
|
2559 | |||
2561 | You can use the %l specifier in an alias definition to represent the |
|
2560 | You can use the %l specifier in an alias definition to represent the | |
2562 | whole line when the alias is called. For example: |
|
2561 | whole line when the alias is called. For example: | |
2563 |
|
2562 | |||
2564 | In [2]: alias bracket echo "Input in brackets: <%l>" |
|
2563 | In [2]: alias bracket echo "Input in brackets: <%l>" | |
2565 | In [3]: bracket hello world |
|
2564 | In [3]: bracket hello world | |
2566 | Input in brackets: <hello world> |
|
2565 | Input in brackets: <hello world> | |
2567 |
|
2566 | |||
2568 | You can also define aliases with parameters using %s specifiers (one |
|
2567 | You can also define aliases with parameters using %s specifiers (one | |
2569 | per parameter): |
|
2568 | per parameter): | |
2570 |
|
2569 | |||
2571 | In [1]: alias parts echo first %s second %s |
|
2570 | In [1]: alias parts echo first %s second %s | |
2572 | In [2]: %parts A B |
|
2571 | In [2]: %parts A B | |
2573 | first A second B |
|
2572 | first A second B | |
2574 | In [3]: %parts A |
|
2573 | In [3]: %parts A | |
2575 | Incorrect number of arguments: 2 expected. |
|
2574 | Incorrect number of arguments: 2 expected. | |
2576 | parts is an alias to: 'echo first %s second %s' |
|
2575 | parts is an alias to: 'echo first %s second %s' | |
2577 |
|
2576 | |||
2578 | Note that %l and %s are mutually exclusive. You can only use one or |
|
2577 | Note that %l and %s are mutually exclusive. You can only use one or | |
2579 | the other in your aliases. |
|
2578 | the other in your aliases. | |
2580 |
|
2579 | |||
2581 | Aliases expand Python variables just like system calls using ! or !! |
|
2580 | Aliases expand Python variables just like system calls using ! or !! | |
2582 | do: all expressions prefixed with '$' get expanded. For details of |
|
2581 | do: all expressions prefixed with '$' get expanded. For details of | |
2583 | the semantic rules, see PEP-215: |
|
2582 | the semantic rules, see PEP-215: | |
2584 | http://www.python.org/peps/pep-0215.html. This is the library used by |
|
2583 | http://www.python.org/peps/pep-0215.html. This is the library used by | |
2585 | IPython for variable expansion. If you want to access a true shell |
|
2584 | IPython for variable expansion. If you want to access a true shell | |
2586 | variable, an extra $ is necessary to prevent its expansion by IPython: |
|
2585 | variable, an extra $ is necessary to prevent its expansion by IPython: | |
2587 |
|
2586 | |||
2588 | In [6]: alias show echo |
|
2587 | In [6]: alias show echo | |
2589 | In [7]: PATH='A Python string' |
|
2588 | In [7]: PATH='A Python string' | |
2590 | In [8]: show $PATH |
|
2589 | In [8]: show $PATH | |
2591 | A Python string |
|
2590 | A Python string | |
2592 | In [9]: show $$PATH |
|
2591 | In [9]: show $$PATH | |
2593 | /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:... |
|
2592 | /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:... | |
2594 |
|
2593 | |||
2595 | You can use the alias facility to acess all of $PATH. See the %rehash |
|
2594 | You can use the alias facility to acess all of $PATH. See the %rehash | |
2596 | and %rehashx functions, which automatically create aliases for the |
|
2595 | and %rehashx functions, which automatically create aliases for the | |
2597 | contents of your $PATH. |
|
2596 | contents of your $PATH. | |
2598 |
|
2597 | |||
2599 | If called with no parameters, %alias prints the current alias table.""" |
|
2598 | If called with no parameters, %alias prints the current alias table.""" | |
2600 |
|
2599 | |||
2601 | par = parameter_s.strip() |
|
2600 | par = parameter_s.strip() | |
2602 | if not par: |
|
2601 | if not par: | |
2603 | stored = self.db.get('stored_aliases', {} ) |
|
2602 | stored = self.db.get('stored_aliases', {} ) | |
2604 | aliases = sorted(self.shell.alias_manager.aliases) |
|
2603 | aliases = sorted(self.shell.alias_manager.aliases) | |
2605 | # for k, v in stored: |
|
2604 | # for k, v in stored: | |
2606 | # atab.append(k, v[0]) |
|
2605 | # atab.append(k, v[0]) | |
2607 |
|
2606 | |||
2608 | print "Total number of aliases:", len(aliases) |
|
2607 | print "Total number of aliases:", len(aliases) | |
2609 | sys.stdout.flush() |
|
2608 | sys.stdout.flush() | |
2610 | return aliases |
|
2609 | return aliases | |
2611 |
|
2610 | |||
2612 | # Now try to define a new one |
|
2611 | # Now try to define a new one | |
2613 | try: |
|
2612 | try: | |
2614 | alias,cmd = par.split(None, 1) |
|
2613 | alias,cmd = par.split(None, 1) | |
2615 | except: |
|
2614 | except: | |
2616 | print oinspect.getdoc(self.magic_alias) |
|
2615 | print oinspect.getdoc(self.magic_alias) | |
2617 | else: |
|
2616 | else: | |
2618 | self.shell.alias_manager.soft_define_alias(alias, cmd) |
|
2617 | self.shell.alias_manager.soft_define_alias(alias, cmd) | |
2619 | # end magic_alias |
|
2618 | # end magic_alias | |
2620 |
|
2619 | |||
2621 | def magic_unalias(self, parameter_s = ''): |
|
2620 | def magic_unalias(self, parameter_s = ''): | |
2622 | """Remove an alias""" |
|
2621 | """Remove an alias""" | |
2623 |
|
2622 | |||
2624 | aname = parameter_s.strip() |
|
2623 | aname = parameter_s.strip() | |
2625 | self.shell.alias_manager.undefine_alias(aname) |
|
2624 | self.shell.alias_manager.undefine_alias(aname) | |
2626 | stored = self.db.get('stored_aliases', {} ) |
|
2625 | stored = self.db.get('stored_aliases', {} ) | |
2627 | if aname in stored: |
|
2626 | if aname in stored: | |
2628 | print "Removing %stored alias",aname |
|
2627 | print "Removing %stored alias",aname | |
2629 | del stored[aname] |
|
2628 | del stored[aname] | |
2630 | self.db['stored_aliases'] = stored |
|
2629 | self.db['stored_aliases'] = stored | |
2631 |
|
2630 | |||
2632 | def magic_rehashx(self, parameter_s = ''): |
|
2631 | def magic_rehashx(self, parameter_s = ''): | |
2633 | """Update the alias table with all executable files in $PATH. |
|
2632 | """Update the alias table with all executable files in $PATH. | |
2634 |
|
2633 | |||
2635 | This version explicitly checks that every entry in $PATH is a file |
|
2634 | This version explicitly checks that every entry in $PATH is a file | |
2636 | with execute access (os.X_OK), so it is much slower than %rehash. |
|
2635 | with execute access (os.X_OK), so it is much slower than %rehash. | |
2637 |
|
2636 | |||
2638 | Under Windows, it checks executability as a match agains a |
|
2637 | Under Windows, it checks executability as a match agains a | |
2639 | '|'-separated string of extensions, stored in the IPython config |
|
2638 | '|'-separated string of extensions, stored in the IPython config | |
2640 | variable win_exec_ext. This defaults to 'exe|com|bat'. |
|
2639 | variable win_exec_ext. This defaults to 'exe|com|bat'. | |
2641 |
|
2640 | |||
2642 | This function also resets the root module cache of module completer, |
|
2641 | This function also resets the root module cache of module completer, | |
2643 | used on slow filesystems. |
|
2642 | used on slow filesystems. | |
2644 | """ |
|
2643 | """ | |
2645 | from IPython.core.alias import InvalidAliasError |
|
2644 | from IPython.core.alias import InvalidAliasError | |
2646 |
|
2645 | |||
2647 | # for the benefit of module completer in ipy_completers.py |
|
2646 | # for the benefit of module completer in ipy_completers.py | |
2648 | del self.db['rootmodules'] |
|
2647 | del self.db['rootmodules'] | |
2649 |
|
2648 | |||
2650 | path = [os.path.abspath(os.path.expanduser(p)) for p in |
|
2649 | path = [os.path.abspath(os.path.expanduser(p)) for p in | |
2651 | os.environ.get('PATH','').split(os.pathsep)] |
|
2650 | os.environ.get('PATH','').split(os.pathsep)] | |
2652 | path = filter(os.path.isdir,path) |
|
2651 | path = filter(os.path.isdir,path) | |
2653 |
|
2652 | |||
2654 | syscmdlist = [] |
|
2653 | syscmdlist = [] | |
2655 | # Now define isexec in a cross platform manner. |
|
2654 | # Now define isexec in a cross platform manner. | |
2656 | if os.name == 'posix': |
|
2655 | if os.name == 'posix': | |
2657 | isexec = lambda fname:os.path.isfile(fname) and \ |
|
2656 | isexec = lambda fname:os.path.isfile(fname) and \ | |
2658 | os.access(fname,os.X_OK) |
|
2657 | os.access(fname,os.X_OK) | |
2659 | else: |
|
2658 | else: | |
2660 | try: |
|
2659 | try: | |
2661 | winext = os.environ['pathext'].replace(';','|').replace('.','') |
|
2660 | winext = os.environ['pathext'].replace(';','|').replace('.','') | |
2662 | except KeyError: |
|
2661 | except KeyError: | |
2663 | winext = 'exe|com|bat|py' |
|
2662 | winext = 'exe|com|bat|py' | |
2664 | if 'py' not in winext: |
|
2663 | if 'py' not in winext: | |
2665 | winext += '|py' |
|
2664 | winext += '|py' | |
2666 | execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE) |
|
2665 | execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE) | |
2667 | isexec = lambda fname:os.path.isfile(fname) and execre.match(fname) |
|
2666 | isexec = lambda fname:os.path.isfile(fname) and execre.match(fname) | |
2668 | savedir = os.getcwdu() |
|
2667 | savedir = os.getcwdu() | |
2669 |
|
2668 | |||
2670 | # Now walk the paths looking for executables to alias. |
|
2669 | # Now walk the paths looking for executables to alias. | |
2671 | try: |
|
2670 | try: | |
2672 | # write the whole loop for posix/Windows so we don't have an if in |
|
2671 | # write the whole loop for posix/Windows so we don't have an if in | |
2673 | # the innermost part |
|
2672 | # the innermost part | |
2674 | if os.name == 'posix': |
|
2673 | if os.name == 'posix': | |
2675 | for pdir in path: |
|
2674 | for pdir in path: | |
2676 | os.chdir(pdir) |
|
2675 | os.chdir(pdir) | |
2677 | for ff in os.listdir(pdir): |
|
2676 | for ff in os.listdir(pdir): | |
2678 | if isexec(ff): |
|
2677 | if isexec(ff): | |
2679 | try: |
|
2678 | try: | |
2680 | # Removes dots from the name since ipython |
|
2679 | # Removes dots from the name since ipython | |
2681 | # will assume names with dots to be python. |
|
2680 | # will assume names with dots to be python. | |
2682 | self.shell.alias_manager.define_alias( |
|
2681 | self.shell.alias_manager.define_alias( | |
2683 | ff.replace('.',''), ff) |
|
2682 | ff.replace('.',''), ff) | |
2684 | except InvalidAliasError: |
|
2683 | except InvalidAliasError: | |
2685 | pass |
|
2684 | pass | |
2686 | else: |
|
2685 | else: | |
2687 | syscmdlist.append(ff) |
|
2686 | syscmdlist.append(ff) | |
2688 | else: |
|
2687 | else: | |
2689 | no_alias = self.shell.alias_manager.no_alias |
|
2688 | no_alias = self.shell.alias_manager.no_alias | |
2690 | for pdir in path: |
|
2689 | for pdir in path: | |
2691 | os.chdir(pdir) |
|
2690 | os.chdir(pdir) | |
2692 | for ff in os.listdir(pdir): |
|
2691 | for ff in os.listdir(pdir): | |
2693 | base, ext = os.path.splitext(ff) |
|
2692 | base, ext = os.path.splitext(ff) | |
2694 | if isexec(ff) and base.lower() not in no_alias: |
|
2693 | if isexec(ff) and base.lower() not in no_alias: | |
2695 | if ext.lower() == '.exe': |
|
2694 | if ext.lower() == '.exe': | |
2696 | ff = base |
|
2695 | ff = base | |
2697 | try: |
|
2696 | try: | |
2698 | # Removes dots from the name since ipython |
|
2697 | # Removes dots from the name since ipython | |
2699 | # will assume names with dots to be python. |
|
2698 | # will assume names with dots to be python. | |
2700 | self.shell.alias_manager.define_alias( |
|
2699 | self.shell.alias_manager.define_alias( | |
2701 | base.lower().replace('.',''), ff) |
|
2700 | base.lower().replace('.',''), ff) | |
2702 | except InvalidAliasError: |
|
2701 | except InvalidAliasError: | |
2703 | pass |
|
2702 | pass | |
2704 | syscmdlist.append(ff) |
|
2703 | syscmdlist.append(ff) | |
2705 | db = self.db |
|
2704 | db = self.db | |
2706 | db['syscmdlist'] = syscmdlist |
|
2705 | db['syscmdlist'] = syscmdlist | |
2707 | finally: |
|
2706 | finally: | |
2708 | os.chdir(savedir) |
|
2707 | os.chdir(savedir) | |
2709 |
|
2708 | |||
2710 | @skip_doctest |
|
2709 | @skip_doctest | |
2711 | def magic_pwd(self, parameter_s = ''): |
|
2710 | def magic_pwd(self, parameter_s = ''): | |
2712 | """Return the current working directory path. |
|
2711 | """Return the current working directory path. | |
2713 |
|
2712 | |||
2714 | Examples |
|
2713 | Examples | |
2715 | -------- |
|
2714 | -------- | |
2716 | :: |
|
2715 | :: | |
2717 |
|
2716 | |||
2718 | In [9]: pwd |
|
2717 | In [9]: pwd | |
2719 | Out[9]: '/home/tsuser/sprint/ipython' |
|
2718 | Out[9]: '/home/tsuser/sprint/ipython' | |
2720 | """ |
|
2719 | """ | |
2721 | return os.getcwdu() |
|
2720 | return os.getcwdu() | |
2722 |
|
2721 | |||
2723 | @skip_doctest |
|
2722 | @skip_doctest | |
2724 | def magic_cd(self, parameter_s=''): |
|
2723 | def magic_cd(self, parameter_s=''): | |
2725 | """Change the current working directory. |
|
2724 | """Change the current working directory. | |
2726 |
|
2725 | |||
2727 | This command automatically maintains an internal list of directories |
|
2726 | This command automatically maintains an internal list of directories | |
2728 | you visit during your IPython session, in the variable _dh. The |
|
2727 | you visit during your IPython session, in the variable _dh. The | |
2729 | command %dhist shows this history nicely formatted. You can also |
|
2728 | command %dhist shows this history nicely formatted. You can also | |
2730 | do 'cd -<tab>' to see directory history conveniently. |
|
2729 | do 'cd -<tab>' to see directory history conveniently. | |
2731 |
|
2730 | |||
2732 | Usage: |
|
2731 | Usage: | |
2733 |
|
2732 | |||
2734 | cd 'dir': changes to directory 'dir'. |
|
2733 | cd 'dir': changes to directory 'dir'. | |
2735 |
|
2734 | |||
2736 | cd -: changes to the last visited directory. |
|
2735 | cd -: changes to the last visited directory. | |
2737 |
|
2736 | |||
2738 | cd -<n>: changes to the n-th directory in the directory history. |
|
2737 | cd -<n>: changes to the n-th directory in the directory history. | |
2739 |
|
2738 | |||
2740 | cd --foo: change to directory that matches 'foo' in history |
|
2739 | cd --foo: change to directory that matches 'foo' in history | |
2741 |
|
2740 | |||
2742 | cd -b <bookmark_name>: jump to a bookmark set by %bookmark |
|
2741 | cd -b <bookmark_name>: jump to a bookmark set by %bookmark | |
2743 | (note: cd <bookmark_name> is enough if there is no |
|
2742 | (note: cd <bookmark_name> is enough if there is no | |
2744 | directory <bookmark_name>, but a bookmark with the name exists.) |
|
2743 | directory <bookmark_name>, but a bookmark with the name exists.) | |
2745 | 'cd -b <tab>' allows you to tab-complete bookmark names. |
|
2744 | 'cd -b <tab>' allows you to tab-complete bookmark names. | |
2746 |
|
2745 | |||
2747 | Options: |
|
2746 | Options: | |
2748 |
|
2747 | |||
2749 | -q: quiet. Do not print the working directory after the cd command is |
|
2748 | -q: quiet. Do not print the working directory after the cd command is | |
2750 | executed. By default IPython's cd command does print this directory, |
|
2749 | executed. By default IPython's cd command does print this directory, | |
2751 | since the default prompts do not display path information. |
|
2750 | since the default prompts do not display path information. | |
2752 |
|
2751 | |||
2753 | Note that !cd doesn't work for this purpose because the shell where |
|
2752 | Note that !cd doesn't work for this purpose because the shell where | |
2754 | !command runs is immediately discarded after executing 'command'. |
|
2753 | !command runs is immediately discarded after executing 'command'. | |
2755 |
|
2754 | |||
2756 | Examples |
|
2755 | Examples | |
2757 | -------- |
|
2756 | -------- | |
2758 | :: |
|
2757 | :: | |
2759 |
|
2758 | |||
2760 | In [10]: cd parent/child |
|
2759 | In [10]: cd parent/child | |
2761 | /home/tsuser/parent/child |
|
2760 | /home/tsuser/parent/child | |
2762 | """ |
|
2761 | """ | |
2763 |
|
2762 | |||
2764 | parameter_s = parameter_s.strip() |
|
2763 | parameter_s = parameter_s.strip() | |
2765 | #bkms = self.shell.persist.get("bookmarks",{}) |
|
2764 | #bkms = self.shell.persist.get("bookmarks",{}) | |
2766 |
|
2765 | |||
2767 | oldcwd = os.getcwdu() |
|
2766 | oldcwd = os.getcwdu() | |
2768 | numcd = re.match(r'(-)(\d+)$',parameter_s) |
|
2767 | numcd = re.match(r'(-)(\d+)$',parameter_s) | |
2769 | # jump in directory history by number |
|
2768 | # jump in directory history by number | |
2770 | if numcd: |
|
2769 | if numcd: | |
2771 | nn = int(numcd.group(2)) |
|
2770 | nn = int(numcd.group(2)) | |
2772 | try: |
|
2771 | try: | |
2773 | ps = self.shell.user_ns['_dh'][nn] |
|
2772 | ps = self.shell.user_ns['_dh'][nn] | |
2774 | except IndexError: |
|
2773 | except IndexError: | |
2775 | print 'The requested directory does not exist in history.' |
|
2774 | print 'The requested directory does not exist in history.' | |
2776 | return |
|
2775 | return | |
2777 | else: |
|
2776 | else: | |
2778 | opts = {} |
|
2777 | opts = {} | |
2779 | elif parameter_s.startswith('--'): |
|
2778 | elif parameter_s.startswith('--'): | |
2780 | ps = None |
|
2779 | ps = None | |
2781 | fallback = None |
|
2780 | fallback = None | |
2782 | pat = parameter_s[2:] |
|
2781 | pat = parameter_s[2:] | |
2783 | dh = self.shell.user_ns['_dh'] |
|
2782 | dh = self.shell.user_ns['_dh'] | |
2784 | # first search only by basename (last component) |
|
2783 | # first search only by basename (last component) | |
2785 | for ent in reversed(dh): |
|
2784 | for ent in reversed(dh): | |
2786 | if pat in os.path.basename(ent) and os.path.isdir(ent): |
|
2785 | if pat in os.path.basename(ent) and os.path.isdir(ent): | |
2787 | ps = ent |
|
2786 | ps = ent | |
2788 | break |
|
2787 | break | |
2789 |
|
2788 | |||
2790 | if fallback is None and pat in ent and os.path.isdir(ent): |
|
2789 | if fallback is None and pat in ent and os.path.isdir(ent): | |
2791 | fallback = ent |
|
2790 | fallback = ent | |
2792 |
|
2791 | |||
2793 | # if we have no last part match, pick the first full path match |
|
2792 | # if we have no last part match, pick the first full path match | |
2794 | if ps is None: |
|
2793 | if ps is None: | |
2795 | ps = fallback |
|
2794 | ps = fallback | |
2796 |
|
2795 | |||
2797 | if ps is None: |
|
2796 | if ps is None: | |
2798 | print "No matching entry in directory history" |
|
2797 | print "No matching entry in directory history" | |
2799 | return |
|
2798 | return | |
2800 | else: |
|
2799 | else: | |
2801 | opts = {} |
|
2800 | opts = {} | |
2802 |
|
2801 | |||
2803 |
|
2802 | |||
2804 | else: |
|
2803 | else: | |
2805 | #turn all non-space-escaping backslashes to slashes, |
|
2804 | #turn all non-space-escaping backslashes to slashes, | |
2806 | # for c:\windows\directory\names\ |
|
2805 | # for c:\windows\directory\names\ | |
2807 | parameter_s = re.sub(r'\\(?! )','/', parameter_s) |
|
2806 | parameter_s = re.sub(r'\\(?! )','/', parameter_s) | |
2808 | opts,ps = self.parse_options(parameter_s,'qb',mode='string') |
|
2807 | opts,ps = self.parse_options(parameter_s,'qb',mode='string') | |
2809 | # jump to previous |
|
2808 | # jump to previous | |
2810 | if ps == '-': |
|
2809 | if ps == '-': | |
2811 | try: |
|
2810 | try: | |
2812 | ps = self.shell.user_ns['_dh'][-2] |
|
2811 | ps = self.shell.user_ns['_dh'][-2] | |
2813 | except IndexError: |
|
2812 | except IndexError: | |
2814 | raise UsageError('%cd -: No previous directory to change to.') |
|
2813 | raise UsageError('%cd -: No previous directory to change to.') | |
2815 | # jump to bookmark if needed |
|
2814 | # jump to bookmark if needed | |
2816 | else: |
|
2815 | else: | |
2817 | if not os.path.isdir(ps) or opts.has_key('b'): |
|
2816 | if not os.path.isdir(ps) or opts.has_key('b'): | |
2818 | bkms = self.db.get('bookmarks', {}) |
|
2817 | bkms = self.db.get('bookmarks', {}) | |
2819 |
|
2818 | |||
2820 | if bkms.has_key(ps): |
|
2819 | if bkms.has_key(ps): | |
2821 | target = bkms[ps] |
|
2820 | target = bkms[ps] | |
2822 | print '(bookmark:%s) -> %s' % (ps,target) |
|
2821 | print '(bookmark:%s) -> %s' % (ps,target) | |
2823 | ps = target |
|
2822 | ps = target | |
2824 | else: |
|
2823 | else: | |
2825 | if opts.has_key('b'): |
|
2824 | if opts.has_key('b'): | |
2826 | raise UsageError("Bookmark '%s' not found. " |
|
2825 | raise UsageError("Bookmark '%s' not found. " | |
2827 | "Use '%%bookmark -l' to see your bookmarks." % ps) |
|
2826 | "Use '%%bookmark -l' to see your bookmarks." % ps) | |
2828 |
|
2827 | |||
2829 | # strip extra quotes on Windows, because os.chdir doesn't like them |
|
2828 | # strip extra quotes on Windows, because os.chdir doesn't like them | |
2830 | if sys.platform == 'win32': |
|
2829 | if sys.platform == 'win32': | |
2831 | ps = ps.strip('\'"') |
|
2830 | ps = ps.strip('\'"') | |
2832 | # at this point ps should point to the target dir |
|
2831 | # at this point ps should point to the target dir | |
2833 | if ps: |
|
2832 | if ps: | |
2834 | try: |
|
2833 | try: | |
2835 | os.chdir(os.path.expanduser(ps)) |
|
2834 | os.chdir(os.path.expanduser(ps)) | |
2836 | if hasattr(self.shell, 'term_title') and self.shell.term_title: |
|
2835 | if hasattr(self.shell, 'term_title') and self.shell.term_title: | |
2837 | set_term_title('IPython: ' + abbrev_cwd()) |
|
2836 | set_term_title('IPython: ' + abbrev_cwd()) | |
2838 | except OSError: |
|
2837 | except OSError: | |
2839 | print sys.exc_info()[1] |
|
2838 | print sys.exc_info()[1] | |
2840 | else: |
|
2839 | else: | |
2841 | cwd = os.getcwdu() |
|
2840 | cwd = os.getcwdu() | |
2842 | dhist = self.shell.user_ns['_dh'] |
|
2841 | dhist = self.shell.user_ns['_dh'] | |
2843 | if oldcwd != cwd: |
|
2842 | if oldcwd != cwd: | |
2844 | dhist.append(cwd) |
|
2843 | dhist.append(cwd) | |
2845 | self.db['dhist'] = compress_dhist(dhist)[-100:] |
|
2844 | self.db['dhist'] = compress_dhist(dhist)[-100:] | |
2846 |
|
2845 | |||
2847 | else: |
|
2846 | else: | |
2848 | os.chdir(self.shell.home_dir) |
|
2847 | os.chdir(self.shell.home_dir) | |
2849 | if hasattr(self.shell, 'term_title') and self.shell.term_title: |
|
2848 | if hasattr(self.shell, 'term_title') and self.shell.term_title: | |
2850 | set_term_title('IPython: ' + '~') |
|
2849 | set_term_title('IPython: ' + '~') | |
2851 | cwd = os.getcwdu() |
|
2850 | cwd = os.getcwdu() | |
2852 | dhist = self.shell.user_ns['_dh'] |
|
2851 | dhist = self.shell.user_ns['_dh'] | |
2853 |
|
2852 | |||
2854 | if oldcwd != cwd: |
|
2853 | if oldcwd != cwd: | |
2855 | dhist.append(cwd) |
|
2854 | dhist.append(cwd) | |
2856 | self.db['dhist'] = compress_dhist(dhist)[-100:] |
|
2855 | self.db['dhist'] = compress_dhist(dhist)[-100:] | |
2857 | if not 'q' in opts and self.shell.user_ns['_dh']: |
|
2856 | if not 'q' in opts and self.shell.user_ns['_dh']: | |
2858 | print self.shell.user_ns['_dh'][-1] |
|
2857 | print self.shell.user_ns['_dh'][-1] | |
2859 |
|
2858 | |||
2860 |
|
2859 | |||
2861 | def magic_env(self, parameter_s=''): |
|
2860 | def magic_env(self, parameter_s=''): | |
2862 | """List environment variables.""" |
|
2861 | """List environment variables.""" | |
2863 |
|
2862 | |||
2864 | return os.environ.data |
|
2863 | return os.environ.data | |
2865 |
|
2864 | |||
2866 | def magic_pushd(self, parameter_s=''): |
|
2865 | def magic_pushd(self, parameter_s=''): | |
2867 | """Place the current dir on stack and change directory. |
|
2866 | """Place the current dir on stack and change directory. | |
2868 |
|
2867 | |||
2869 | Usage:\\ |
|
2868 | Usage:\\ | |
2870 | %pushd ['dirname'] |
|
2869 | %pushd ['dirname'] | |
2871 | """ |
|
2870 | """ | |
2872 |
|
2871 | |||
2873 | dir_s = self.shell.dir_stack |
|
2872 | dir_s = self.shell.dir_stack | |
2874 | tgt = os.path.expanduser(parameter_s) |
|
2873 | tgt = os.path.expanduser(parameter_s) | |
2875 | cwd = os.getcwdu().replace(self.home_dir,'~') |
|
2874 | cwd = os.getcwdu().replace(self.home_dir,'~') | |
2876 | if tgt: |
|
2875 | if tgt: | |
2877 | self.magic_cd(parameter_s) |
|
2876 | self.magic_cd(parameter_s) | |
2878 | dir_s.insert(0,cwd) |
|
2877 | dir_s.insert(0,cwd) | |
2879 | return self.magic_dirs() |
|
2878 | return self.magic_dirs() | |
2880 |
|
2879 | |||
2881 | def magic_popd(self, parameter_s=''): |
|
2880 | def magic_popd(self, parameter_s=''): | |
2882 | """Change to directory popped off the top of the stack. |
|
2881 | """Change to directory popped off the top of the stack. | |
2883 | """ |
|
2882 | """ | |
2884 | if not self.shell.dir_stack: |
|
2883 | if not self.shell.dir_stack: | |
2885 | raise UsageError("%popd on empty stack") |
|
2884 | raise UsageError("%popd on empty stack") | |
2886 | top = self.shell.dir_stack.pop(0) |
|
2885 | top = self.shell.dir_stack.pop(0) | |
2887 | self.magic_cd(top) |
|
2886 | self.magic_cd(top) | |
2888 | print "popd ->",top |
|
2887 | print "popd ->",top | |
2889 |
|
2888 | |||
2890 | def magic_dirs(self, parameter_s=''): |
|
2889 | def magic_dirs(self, parameter_s=''): | |
2891 | """Return the current directory stack.""" |
|
2890 | """Return the current directory stack.""" | |
2892 |
|
2891 | |||
2893 | return self.shell.dir_stack |
|
2892 | return self.shell.dir_stack | |
2894 |
|
2893 | |||
2895 | def magic_dhist(self, parameter_s=''): |
|
2894 | def magic_dhist(self, parameter_s=''): | |
2896 | """Print your history of visited directories. |
|
2895 | """Print your history of visited directories. | |
2897 |
|
2896 | |||
2898 | %dhist -> print full history\\ |
|
2897 | %dhist -> print full history\\ | |
2899 | %dhist n -> print last n entries only\\ |
|
2898 | %dhist n -> print last n entries only\\ | |
2900 | %dhist n1 n2 -> print entries between n1 and n2 (n1 not included)\\ |
|
2899 | %dhist n1 n2 -> print entries between n1 and n2 (n1 not included)\\ | |
2901 |
|
2900 | |||
2902 | This history is automatically maintained by the %cd command, and |
|
2901 | This history is automatically maintained by the %cd command, and | |
2903 | always available as the global list variable _dh. You can use %cd -<n> |
|
2902 | always available as the global list variable _dh. You can use %cd -<n> | |
2904 | to go to directory number <n>. |
|
2903 | to go to directory number <n>. | |
2905 |
|
2904 | |||
2906 | Note that most of time, you should view directory history by entering |
|
2905 | Note that most of time, you should view directory history by entering | |
2907 | cd -<TAB>. |
|
2906 | cd -<TAB>. | |
2908 |
|
2907 | |||
2909 | """ |
|
2908 | """ | |
2910 |
|
2909 | |||
2911 | dh = self.shell.user_ns['_dh'] |
|
2910 | dh = self.shell.user_ns['_dh'] | |
2912 | if parameter_s: |
|
2911 | if parameter_s: | |
2913 | try: |
|
2912 | try: | |
2914 | args = map(int,parameter_s.split()) |
|
2913 | args = map(int,parameter_s.split()) | |
2915 | except: |
|
2914 | except: | |
2916 | self.arg_err(Magic.magic_dhist) |
|
2915 | self.arg_err(Magic.magic_dhist) | |
2917 | return |
|
2916 | return | |
2918 | if len(args) == 1: |
|
2917 | if len(args) == 1: | |
2919 | ini,fin = max(len(dh)-(args[0]),0),len(dh) |
|
2918 | ini,fin = max(len(dh)-(args[0]),0),len(dh) | |
2920 | elif len(args) == 2: |
|
2919 | elif len(args) == 2: | |
2921 | ini,fin = args |
|
2920 | ini,fin = args | |
2922 | else: |
|
2921 | else: | |
2923 | self.arg_err(Magic.magic_dhist) |
|
2922 | self.arg_err(Magic.magic_dhist) | |
2924 | return |
|
2923 | return | |
2925 | else: |
|
2924 | else: | |
2926 | ini,fin = 0,len(dh) |
|
2925 | ini,fin = 0,len(dh) | |
2927 | nlprint(dh, |
|
2926 | nlprint(dh, | |
2928 | header = 'Directory history (kept in _dh)', |
|
2927 | header = 'Directory history (kept in _dh)', | |
2929 | start=ini,stop=fin) |
|
2928 | start=ini,stop=fin) | |
2930 |
|
2929 | |||
2931 | @skip_doctest |
|
2930 | @skip_doctest | |
2932 | def magic_sc(self, parameter_s=''): |
|
2931 | def magic_sc(self, parameter_s=''): | |
2933 | """Shell capture - execute a shell command and capture its output. |
|
2932 | """Shell capture - execute a shell command and capture its output. | |
2934 |
|
2933 | |||
2935 | DEPRECATED. Suboptimal, retained for backwards compatibility. |
|
2934 | DEPRECATED. Suboptimal, retained for backwards compatibility. | |
2936 |
|
2935 | |||
2937 | You should use the form 'var = !command' instead. Example: |
|
2936 | You should use the form 'var = !command' instead. Example: | |
2938 |
|
2937 | |||
2939 | "%sc -l myfiles = ls ~" should now be written as |
|
2938 | "%sc -l myfiles = ls ~" should now be written as | |
2940 |
|
2939 | |||
2941 | "myfiles = !ls ~" |
|
2940 | "myfiles = !ls ~" | |
2942 |
|
2941 | |||
2943 | myfiles.s, myfiles.l and myfiles.n still apply as documented |
|
2942 | myfiles.s, myfiles.l and myfiles.n still apply as documented | |
2944 | below. |
|
2943 | below. | |
2945 |
|
2944 | |||
2946 | -- |
|
2945 | -- | |
2947 | %sc [options] varname=command |
|
2946 | %sc [options] varname=command | |
2948 |
|
2947 | |||
2949 | IPython will run the given command using commands.getoutput(), and |
|
2948 | IPython will run the given command using commands.getoutput(), and | |
2950 | will then update the user's interactive namespace with a variable |
|
2949 | will then update the user's interactive namespace with a variable | |
2951 | called varname, containing the value of the call. Your command can |
|
2950 | called varname, containing the value of the call. Your command can | |
2952 | contain shell wildcards, pipes, etc. |
|
2951 | contain shell wildcards, pipes, etc. | |
2953 |
|
2952 | |||
2954 | The '=' sign in the syntax is mandatory, and the variable name you |
|
2953 | The '=' sign in the syntax is mandatory, and the variable name you | |
2955 | supply must follow Python's standard conventions for valid names. |
|
2954 | supply must follow Python's standard conventions for valid names. | |
2956 |
|
2955 | |||
2957 | (A special format without variable name exists for internal use) |
|
2956 | (A special format without variable name exists for internal use) | |
2958 |
|
2957 | |||
2959 | Options: |
|
2958 | Options: | |
2960 |
|
2959 | |||
2961 | -l: list output. Split the output on newlines into a list before |
|
2960 | -l: list output. Split the output on newlines into a list before | |
2962 | assigning it to the given variable. By default the output is stored |
|
2961 | assigning it to the given variable. By default the output is stored | |
2963 | as a single string. |
|
2962 | as a single string. | |
2964 |
|
2963 | |||
2965 | -v: verbose. Print the contents of the variable. |
|
2964 | -v: verbose. Print the contents of the variable. | |
2966 |
|
2965 | |||
2967 | In most cases you should not need to split as a list, because the |
|
2966 | In most cases you should not need to split as a list, because the | |
2968 | returned value is a special type of string which can automatically |
|
2967 | returned value is a special type of string which can automatically | |
2969 | provide its contents either as a list (split on newlines) or as a |
|
2968 | provide its contents either as a list (split on newlines) or as a | |
2970 | space-separated string. These are convenient, respectively, either |
|
2969 | space-separated string. These are convenient, respectively, either | |
2971 | for sequential processing or to be passed to a shell command. |
|
2970 | for sequential processing or to be passed to a shell command. | |
2972 |
|
2971 | |||
2973 | For example: |
|
2972 | For example: | |
2974 |
|
2973 | |||
2975 | # all-random |
|
2974 | # all-random | |
2976 |
|
2975 | |||
2977 | # Capture into variable a |
|
2976 | # Capture into variable a | |
2978 | In [1]: sc a=ls *py |
|
2977 | In [1]: sc a=ls *py | |
2979 |
|
2978 | |||
2980 | # a is a string with embedded newlines |
|
2979 | # a is a string with embedded newlines | |
2981 | In [2]: a |
|
2980 | In [2]: a | |
2982 | Out[2]: 'setup.py\\nwin32_manual_post_install.py' |
|
2981 | Out[2]: 'setup.py\\nwin32_manual_post_install.py' | |
2983 |
|
2982 | |||
2984 | # which can be seen as a list: |
|
2983 | # which can be seen as a list: | |
2985 | In [3]: a.l |
|
2984 | In [3]: a.l | |
2986 | Out[3]: ['setup.py', 'win32_manual_post_install.py'] |
|
2985 | Out[3]: ['setup.py', 'win32_manual_post_install.py'] | |
2987 |
|
2986 | |||
2988 | # or as a whitespace-separated string: |
|
2987 | # or as a whitespace-separated string: | |
2989 | In [4]: a.s |
|
2988 | In [4]: a.s | |
2990 | Out[4]: 'setup.py win32_manual_post_install.py' |
|
2989 | Out[4]: 'setup.py win32_manual_post_install.py' | |
2991 |
|
2990 | |||
2992 | # a.s is useful to pass as a single command line: |
|
2991 | # a.s is useful to pass as a single command line: | |
2993 | In [5]: !wc -l $a.s |
|
2992 | In [5]: !wc -l $a.s | |
2994 | 146 setup.py |
|
2993 | 146 setup.py | |
2995 | 130 win32_manual_post_install.py |
|
2994 | 130 win32_manual_post_install.py | |
2996 | 276 total |
|
2995 | 276 total | |
2997 |
|
2996 | |||
2998 | # while the list form is useful to loop over: |
|
2997 | # while the list form is useful to loop over: | |
2999 | In [6]: for f in a.l: |
|
2998 | In [6]: for f in a.l: | |
3000 | ...: !wc -l $f |
|
2999 | ...: !wc -l $f | |
3001 | ...: |
|
3000 | ...: | |
3002 | 146 setup.py |
|
3001 | 146 setup.py | |
3003 | 130 win32_manual_post_install.py |
|
3002 | 130 win32_manual_post_install.py | |
3004 |
|
3003 | |||
3005 | Similiarly, the lists returned by the -l option are also special, in |
|
3004 | Similiarly, the lists returned by the -l option are also special, in | |
3006 | the sense that you can equally invoke the .s attribute on them to |
|
3005 | the sense that you can equally invoke the .s attribute on them to | |
3007 | automatically get a whitespace-separated string from their contents: |
|
3006 | automatically get a whitespace-separated string from their contents: | |
3008 |
|
3007 | |||
3009 | In [7]: sc -l b=ls *py |
|
3008 | In [7]: sc -l b=ls *py | |
3010 |
|
3009 | |||
3011 | In [8]: b |
|
3010 | In [8]: b | |
3012 | Out[8]: ['setup.py', 'win32_manual_post_install.py'] |
|
3011 | Out[8]: ['setup.py', 'win32_manual_post_install.py'] | |
3013 |
|
3012 | |||
3014 | In [9]: b.s |
|
3013 | In [9]: b.s | |
3015 | Out[9]: 'setup.py win32_manual_post_install.py' |
|
3014 | Out[9]: 'setup.py win32_manual_post_install.py' | |
3016 |
|
3015 | |||
3017 | In summary, both the lists and strings used for ouptut capture have |
|
3016 | In summary, both the lists and strings used for ouptut capture have | |
3018 | the following special attributes: |
|
3017 | the following special attributes: | |
3019 |
|
3018 | |||
3020 | .l (or .list) : value as list. |
|
3019 | .l (or .list) : value as list. | |
3021 | .n (or .nlstr): value as newline-separated string. |
|
3020 | .n (or .nlstr): value as newline-separated string. | |
3022 | .s (or .spstr): value as space-separated string. |
|
3021 | .s (or .spstr): value as space-separated string. | |
3023 | """ |
|
3022 | """ | |
3024 |
|
3023 | |||
3025 | opts,args = self.parse_options(parameter_s,'lv') |
|
3024 | opts,args = self.parse_options(parameter_s,'lv') | |
3026 | # Try to get a variable name and command to run |
|
3025 | # Try to get a variable name and command to run | |
3027 | try: |
|
3026 | try: | |
3028 | # the variable name must be obtained from the parse_options |
|
3027 | # the variable name must be obtained from the parse_options | |
3029 | # output, which uses shlex.split to strip options out. |
|
3028 | # output, which uses shlex.split to strip options out. | |
3030 | var,_ = args.split('=',1) |
|
3029 | var,_ = args.split('=',1) | |
3031 | var = var.strip() |
|
3030 | var = var.strip() | |
3032 | # But the the command has to be extracted from the original input |
|
3031 | # But the the command has to be extracted from the original input | |
3033 | # parameter_s, not on what parse_options returns, to avoid the |
|
3032 | # parameter_s, not on what parse_options returns, to avoid the | |
3034 | # quote stripping which shlex.split performs on it. |
|
3033 | # quote stripping which shlex.split performs on it. | |
3035 | _,cmd = parameter_s.split('=',1) |
|
3034 | _,cmd = parameter_s.split('=',1) | |
3036 | except ValueError: |
|
3035 | except ValueError: | |
3037 | var,cmd = '','' |
|
3036 | var,cmd = '','' | |
3038 | # If all looks ok, proceed |
|
3037 | # If all looks ok, proceed | |
3039 | split = 'l' in opts |
|
3038 | split = 'l' in opts | |
3040 | out = self.shell.getoutput(cmd, split=split) |
|
3039 | out = self.shell.getoutput(cmd, split=split) | |
3041 | if opts.has_key('v'): |
|
3040 | if opts.has_key('v'): | |
3042 | print '%s ==\n%s' % (var,pformat(out)) |
|
3041 | print '%s ==\n%s' % (var,pformat(out)) | |
3043 | if var: |
|
3042 | if var: | |
3044 | self.shell.user_ns.update({var:out}) |
|
3043 | self.shell.user_ns.update({var:out}) | |
3045 | else: |
|
3044 | else: | |
3046 | return out |
|
3045 | return out | |
3047 |
|
3046 | |||
3048 | def magic_sx(self, parameter_s=''): |
|
3047 | def magic_sx(self, parameter_s=''): | |
3049 | """Shell execute - run a shell command and capture its output. |
|
3048 | """Shell execute - run a shell command and capture its output. | |
3050 |
|
3049 | |||
3051 | %sx command |
|
3050 | %sx command | |
3052 |
|
3051 | |||
3053 | IPython will run the given command using commands.getoutput(), and |
|
3052 | IPython will run the given command using commands.getoutput(), and | |
3054 | return the result formatted as a list (split on '\\n'). Since the |
|
3053 | return the result formatted as a list (split on '\\n'). Since the | |
3055 | output is _returned_, it will be stored in ipython's regular output |
|
3054 | output is _returned_, it will be stored in ipython's regular output | |
3056 | cache Out[N] and in the '_N' automatic variables. |
|
3055 | cache Out[N] and in the '_N' automatic variables. | |
3057 |
|
3056 | |||
3058 | Notes: |
|
3057 | Notes: | |
3059 |
|
3058 | |||
3060 | 1) If an input line begins with '!!', then %sx is automatically |
|
3059 | 1) If an input line begins with '!!', then %sx is automatically | |
3061 | invoked. That is, while: |
|
3060 | invoked. That is, while: | |
3062 | !ls |
|
3061 | !ls | |
3063 | causes ipython to simply issue system('ls'), typing |
|
3062 | causes ipython to simply issue system('ls'), typing | |
3064 | !!ls |
|
3063 | !!ls | |
3065 | is a shorthand equivalent to: |
|
3064 | is a shorthand equivalent to: | |
3066 | %sx ls |
|
3065 | %sx ls | |
3067 |
|
3066 | |||
3068 | 2) %sx differs from %sc in that %sx automatically splits into a list, |
|
3067 | 2) %sx differs from %sc in that %sx automatically splits into a list, | |
3069 | like '%sc -l'. The reason for this is to make it as easy as possible |
|
3068 | like '%sc -l'. The reason for this is to make it as easy as possible | |
3070 | to process line-oriented shell output via further python commands. |
|
3069 | to process line-oriented shell output via further python commands. | |
3071 | %sc is meant to provide much finer control, but requires more |
|
3070 | %sc is meant to provide much finer control, but requires more | |
3072 | typing. |
|
3071 | typing. | |
3073 |
|
3072 | |||
3074 | 3) Just like %sc -l, this is a list with special attributes: |
|
3073 | 3) Just like %sc -l, this is a list with special attributes: | |
3075 |
|
3074 | |||
3076 | .l (or .list) : value as list. |
|
3075 | .l (or .list) : value as list. | |
3077 | .n (or .nlstr): value as newline-separated string. |
|
3076 | .n (or .nlstr): value as newline-separated string. | |
3078 | .s (or .spstr): value as whitespace-separated string. |
|
3077 | .s (or .spstr): value as whitespace-separated string. | |
3079 |
|
3078 | |||
3080 | This is very useful when trying to use such lists as arguments to |
|
3079 | This is very useful when trying to use such lists as arguments to | |
3081 | system commands.""" |
|
3080 | system commands.""" | |
3082 |
|
3081 | |||
3083 | if parameter_s: |
|
3082 | if parameter_s: | |
3084 | return self.shell.getoutput(parameter_s) |
|
3083 | return self.shell.getoutput(parameter_s) | |
3085 |
|
3084 | |||
3086 |
|
3085 | |||
3087 | def magic_bookmark(self, parameter_s=''): |
|
3086 | def magic_bookmark(self, parameter_s=''): | |
3088 | """Manage IPython's bookmark system. |
|
3087 | """Manage IPython's bookmark system. | |
3089 |
|
3088 | |||
3090 | %bookmark <name> - set bookmark to current dir |
|
3089 | %bookmark <name> - set bookmark to current dir | |
3091 | %bookmark <name> <dir> - set bookmark to <dir> |
|
3090 | %bookmark <name> <dir> - set bookmark to <dir> | |
3092 | %bookmark -l - list all bookmarks |
|
3091 | %bookmark -l - list all bookmarks | |
3093 | %bookmark -d <name> - remove bookmark |
|
3092 | %bookmark -d <name> - remove bookmark | |
3094 | %bookmark -r - remove all bookmarks |
|
3093 | %bookmark -r - remove all bookmarks | |
3095 |
|
3094 | |||
3096 | You can later on access a bookmarked folder with: |
|
3095 | You can later on access a bookmarked folder with: | |
3097 | %cd -b <name> |
|
3096 | %cd -b <name> | |
3098 | or simply '%cd <name>' if there is no directory called <name> AND |
|
3097 | or simply '%cd <name>' if there is no directory called <name> AND | |
3099 | there is such a bookmark defined. |
|
3098 | there is such a bookmark defined. | |
3100 |
|
3099 | |||
3101 | Your bookmarks persist through IPython sessions, but they are |
|
3100 | Your bookmarks persist through IPython sessions, but they are | |
3102 | associated with each profile.""" |
|
3101 | associated with each profile.""" | |
3103 |
|
3102 | |||
3104 | opts,args = self.parse_options(parameter_s,'drl',mode='list') |
|
3103 | opts,args = self.parse_options(parameter_s,'drl',mode='list') | |
3105 | if len(args) > 2: |
|
3104 | if len(args) > 2: | |
3106 | raise UsageError("%bookmark: too many arguments") |
|
3105 | raise UsageError("%bookmark: too many arguments") | |
3107 |
|
3106 | |||
3108 | bkms = self.db.get('bookmarks',{}) |
|
3107 | bkms = self.db.get('bookmarks',{}) | |
3109 |
|
3108 | |||
3110 | if opts.has_key('d'): |
|
3109 | if opts.has_key('d'): | |
3111 | try: |
|
3110 | try: | |
3112 | todel = args[0] |
|
3111 | todel = args[0] | |
3113 | except IndexError: |
|
3112 | except IndexError: | |
3114 | raise UsageError( |
|
3113 | raise UsageError( | |
3115 | "%bookmark -d: must provide a bookmark to delete") |
|
3114 | "%bookmark -d: must provide a bookmark to delete") | |
3116 | else: |
|
3115 | else: | |
3117 | try: |
|
3116 | try: | |
3118 | del bkms[todel] |
|
3117 | del bkms[todel] | |
3119 | except KeyError: |
|
3118 | except KeyError: | |
3120 | raise UsageError( |
|
3119 | raise UsageError( | |
3121 | "%%bookmark -d: Can't delete bookmark '%s'" % todel) |
|
3120 | "%%bookmark -d: Can't delete bookmark '%s'" % todel) | |
3122 |
|
3121 | |||
3123 | elif opts.has_key('r'): |
|
3122 | elif opts.has_key('r'): | |
3124 | bkms = {} |
|
3123 | bkms = {} | |
3125 | elif opts.has_key('l'): |
|
3124 | elif opts.has_key('l'): | |
3126 | bks = bkms.keys() |
|
3125 | bks = bkms.keys() | |
3127 | bks.sort() |
|
3126 | bks.sort() | |
3128 | if bks: |
|
3127 | if bks: | |
3129 | size = max(map(len,bks)) |
|
3128 | size = max(map(len,bks)) | |
3130 | else: |
|
3129 | else: | |
3131 | size = 0 |
|
3130 | size = 0 | |
3132 | fmt = '%-'+str(size)+'s -> %s' |
|
3131 | fmt = '%-'+str(size)+'s -> %s' | |
3133 | print 'Current bookmarks:' |
|
3132 | print 'Current bookmarks:' | |
3134 | for bk in bks: |
|
3133 | for bk in bks: | |
3135 | print fmt % (bk,bkms[bk]) |
|
3134 | print fmt % (bk,bkms[bk]) | |
3136 | else: |
|
3135 | else: | |
3137 | if not args: |
|
3136 | if not args: | |
3138 | raise UsageError("%bookmark: You must specify the bookmark name") |
|
3137 | raise UsageError("%bookmark: You must specify the bookmark name") | |
3139 | elif len(args)==1: |
|
3138 | elif len(args)==1: | |
3140 | bkms[args[0]] = os.getcwdu() |
|
3139 | bkms[args[0]] = os.getcwdu() | |
3141 | elif len(args)==2: |
|
3140 | elif len(args)==2: | |
3142 | bkms[args[0]] = args[1] |
|
3141 | bkms[args[0]] = args[1] | |
3143 | self.db['bookmarks'] = bkms |
|
3142 | self.db['bookmarks'] = bkms | |
3144 |
|
3143 | |||
3145 | def magic_pycat(self, parameter_s=''): |
|
3144 | def magic_pycat(self, parameter_s=''): | |
3146 | """Show a syntax-highlighted file through a pager. |
|
3145 | """Show a syntax-highlighted file through a pager. | |
3147 |
|
3146 | |||
3148 | This magic is similar to the cat utility, but it will assume the file |
|
3147 | This magic is similar to the cat utility, but it will assume the file | |
3149 | to be Python source and will show it with syntax highlighting. """ |
|
3148 | to be Python source and will show it with syntax highlighting. """ | |
3150 |
|
3149 | |||
3151 | try: |
|
3150 | try: | |
3152 | filename = get_py_filename(parameter_s) |
|
3151 | filename = get_py_filename(parameter_s) | |
3153 | cont = file_read(filename) |
|
3152 | cont = file_read(filename) | |
3154 | except IOError: |
|
3153 | except IOError: | |
3155 | try: |
|
3154 | try: | |
3156 | cont = eval(parameter_s,self.user_ns) |
|
3155 | cont = eval(parameter_s,self.user_ns) | |
3157 | except NameError: |
|
3156 | except NameError: | |
3158 | cont = None |
|
3157 | cont = None | |
3159 | if cont is None: |
|
3158 | if cont is None: | |
3160 | print "Error: no such file or variable" |
|
3159 | print "Error: no such file or variable" | |
3161 | return |
|
3160 | return | |
3162 |
|
3161 | |||
3163 | page.page(self.shell.pycolorize(cont)) |
|
3162 | page.page(self.shell.pycolorize(cont)) | |
3164 |
|
3163 | |||
3165 | def _rerun_pasted(self): |
|
3164 | def _rerun_pasted(self): | |
3166 | """ Rerun a previously pasted command. |
|
3165 | """ Rerun a previously pasted command. | |
3167 | """ |
|
3166 | """ | |
3168 | b = self.user_ns.get('pasted_block', None) |
|
3167 | b = self.user_ns.get('pasted_block', None) | |
3169 | if b is None: |
|
3168 | if b is None: | |
3170 | raise UsageError('No previous pasted block available') |
|
3169 | raise UsageError('No previous pasted block available') | |
3171 | print "Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b)) |
|
3170 | print "Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b)) | |
3172 | exec b in self.user_ns |
|
3171 | exec b in self.user_ns | |
3173 |
|
3172 | |||
3174 | def _get_pasted_lines(self, sentinel): |
|
3173 | def _get_pasted_lines(self, sentinel): | |
3175 | """ Yield pasted lines until the user enters the given sentinel value. |
|
3174 | """ Yield pasted lines until the user enters the given sentinel value. | |
3176 | """ |
|
3175 | """ | |
3177 | from IPython.core import interactiveshell |
|
3176 | from IPython.core import interactiveshell | |
3178 | print "Pasting code; enter '%s' alone on the line to stop." % sentinel |
|
3177 | print "Pasting code; enter '%s' alone on the line to stop." % sentinel | |
3179 | while True: |
|
3178 | while True: | |
3180 | l = interactiveshell.raw_input_original(':') |
|
3179 | l = interactiveshell.raw_input_original(':') | |
3181 | if l == sentinel: |
|
3180 | if l == sentinel: | |
3182 | return |
|
3181 | return | |
3183 | else: |
|
3182 | else: | |
3184 | yield l |
|
3183 | yield l | |
3185 |
|
3184 | |||
3186 | def _strip_pasted_lines_for_code(self, raw_lines): |
|
3185 | def _strip_pasted_lines_for_code(self, raw_lines): | |
3187 | """ Strip non-code parts of a sequence of lines to return a block of |
|
3186 | """ Strip non-code parts of a sequence of lines to return a block of | |
3188 | code. |
|
3187 | code. | |
3189 | """ |
|
3188 | """ | |
3190 | # Regular expressions that declare text we strip from the input: |
|
3189 | # Regular expressions that declare text we strip from the input: | |
3191 | strip_re = [r'^\s*In \[\d+\]:', # IPython input prompt |
|
3190 | strip_re = [r'^\s*In \[\d+\]:', # IPython input prompt | |
3192 | r'^\s*(\s?>)+', # Python input prompt |
|
3191 | r'^\s*(\s?>)+', # Python input prompt | |
3193 | r'^\s*\.{3,}', # Continuation prompts |
|
3192 | r'^\s*\.{3,}', # Continuation prompts | |
3194 | r'^\++', |
|
3193 | r'^\++', | |
3195 | ] |
|
3194 | ] | |
3196 |
|
3195 | |||
3197 | strip_from_start = map(re.compile,strip_re) |
|
3196 | strip_from_start = map(re.compile,strip_re) | |
3198 |
|
3197 | |||
3199 | lines = [] |
|
3198 | lines = [] | |
3200 | for l in raw_lines: |
|
3199 | for l in raw_lines: | |
3201 | for pat in strip_from_start: |
|
3200 | for pat in strip_from_start: | |
3202 | l = pat.sub('',l) |
|
3201 | l = pat.sub('',l) | |
3203 | lines.append(l) |
|
3202 | lines.append(l) | |
3204 |
|
3203 | |||
3205 | block = "\n".join(lines) + '\n' |
|
3204 | block = "\n".join(lines) + '\n' | |
3206 | #print "block:\n",block |
|
3205 | #print "block:\n",block | |
3207 | return block |
|
3206 | return block | |
3208 |
|
3207 | |||
3209 | def _execute_block(self, block, par): |
|
3208 | def _execute_block(self, block, par): | |
3210 | """ Execute a block, or store it in a variable, per the user's request. |
|
3209 | """ Execute a block, or store it in a variable, per the user's request. | |
3211 | """ |
|
3210 | """ | |
3212 | if not par: |
|
3211 | if not par: | |
3213 | b = textwrap.dedent(block) |
|
3212 | b = textwrap.dedent(block) | |
3214 | self.user_ns['pasted_block'] = b |
|
3213 | self.user_ns['pasted_block'] = b | |
3215 | exec b in self.user_ns |
|
3214 | exec b in self.user_ns | |
3216 | else: |
|
3215 | else: | |
3217 | self.user_ns[par] = SList(block.splitlines()) |
|
3216 | self.user_ns[par] = SList(block.splitlines()) | |
3218 | print "Block assigned to '%s'" % par |
|
3217 | print "Block assigned to '%s'" % par | |
3219 |
|
3218 | |||
3220 | def magic_quickref(self,arg): |
|
3219 | def magic_quickref(self,arg): | |
3221 | """ Show a quick reference sheet """ |
|
3220 | """ Show a quick reference sheet """ | |
3222 | import IPython.core.usage |
|
3221 | import IPython.core.usage | |
3223 | qr = IPython.core.usage.quick_reference + self.magic_magic('-brief') |
|
3222 | qr = IPython.core.usage.quick_reference + self.magic_magic('-brief') | |
3224 |
|
3223 | |||
3225 | page.page(qr) |
|
3224 | page.page(qr) | |
3226 |
|
3225 | |||
3227 | def magic_doctest_mode(self,parameter_s=''): |
|
3226 | def magic_doctest_mode(self,parameter_s=''): | |
3228 | """Toggle doctest mode on and off. |
|
3227 | """Toggle doctest mode on and off. | |
3229 |
|
3228 | |||
3230 | This mode is intended to make IPython behave as much as possible like a |
|
3229 | This mode is intended to make IPython behave as much as possible like a | |
3231 | plain Python shell, from the perspective of how its prompts, exceptions |
|
3230 | plain Python shell, from the perspective of how its prompts, exceptions | |
3232 | and output look. This makes it easy to copy and paste parts of a |
|
3231 | and output look. This makes it easy to copy and paste parts of a | |
3233 | session into doctests. It does so by: |
|
3232 | session into doctests. It does so by: | |
3234 |
|
3233 | |||
3235 | - Changing the prompts to the classic ``>>>`` ones. |
|
3234 | - Changing the prompts to the classic ``>>>`` ones. | |
3236 | - Changing the exception reporting mode to 'Plain'. |
|
3235 | - Changing the exception reporting mode to 'Plain'. | |
3237 | - Disabling pretty-printing of output. |
|
3236 | - Disabling pretty-printing of output. | |
3238 |
|
3237 | |||
3239 | Note that IPython also supports the pasting of code snippets that have |
|
3238 | Note that IPython also supports the pasting of code snippets that have | |
3240 | leading '>>>' and '...' prompts in them. This means that you can paste |
|
3239 | leading '>>>' and '...' prompts in them. This means that you can paste | |
3241 | doctests from files or docstrings (even if they have leading |
|
3240 | doctests from files or docstrings (even if they have leading | |
3242 | whitespace), and the code will execute correctly. You can then use |
|
3241 | whitespace), and the code will execute correctly. You can then use | |
3243 | '%history -t' to see the translated history; this will give you the |
|
3242 | '%history -t' to see the translated history; this will give you the | |
3244 | input after removal of all the leading prompts and whitespace, which |
|
3243 | input after removal of all the leading prompts and whitespace, which | |
3245 | can be pasted back into an editor. |
|
3244 | can be pasted back into an editor. | |
3246 |
|
3245 | |||
3247 | With these features, you can switch into this mode easily whenever you |
|
3246 | With these features, you can switch into this mode easily whenever you | |
3248 | need to do testing and changes to doctests, without having to leave |
|
3247 | need to do testing and changes to doctests, without having to leave | |
3249 | your existing IPython session. |
|
3248 | your existing IPython session. | |
3250 | """ |
|
3249 | """ | |
3251 |
|
3250 | |||
3252 | from IPython.utils.ipstruct import Struct |
|
3251 | from IPython.utils.ipstruct import Struct | |
3253 |
|
3252 | |||
3254 | # Shorthands |
|
3253 | # Shorthands | |
3255 | shell = self.shell |
|
3254 | shell = self.shell | |
3256 | oc = shell.displayhook |
|
3255 | oc = shell.displayhook | |
3257 | meta = shell.meta |
|
3256 | meta = shell.meta | |
3258 | disp_formatter = self.shell.display_formatter |
|
3257 | disp_formatter = self.shell.display_formatter | |
3259 | ptformatter = disp_formatter.formatters['text/plain'] |
|
3258 | ptformatter = disp_formatter.formatters['text/plain'] | |
3260 | # dstore is a data store kept in the instance metadata bag to track any |
|
3259 | # dstore is a data store kept in the instance metadata bag to track any | |
3261 | # changes we make, so we can undo them later. |
|
3260 | # changes we make, so we can undo them later. | |
3262 | dstore = meta.setdefault('doctest_mode',Struct()) |
|
3261 | dstore = meta.setdefault('doctest_mode',Struct()) | |
3263 | save_dstore = dstore.setdefault |
|
3262 | save_dstore = dstore.setdefault | |
3264 |
|
3263 | |||
3265 | # save a few values we'll need to recover later |
|
3264 | # save a few values we'll need to recover later | |
3266 | mode = save_dstore('mode',False) |
|
3265 | mode = save_dstore('mode',False) | |
3267 | save_dstore('rc_pprint',ptformatter.pprint) |
|
3266 | save_dstore('rc_pprint',ptformatter.pprint) | |
3268 | save_dstore('xmode',shell.InteractiveTB.mode) |
|
3267 | save_dstore('xmode',shell.InteractiveTB.mode) | |
3269 | save_dstore('rc_separate_out',shell.separate_out) |
|
3268 | save_dstore('rc_separate_out',shell.separate_out) | |
3270 | save_dstore('rc_separate_out2',shell.separate_out2) |
|
3269 | save_dstore('rc_separate_out2',shell.separate_out2) | |
3271 | save_dstore('rc_prompts_pad_left',shell.prompts_pad_left) |
|
3270 | save_dstore('rc_prompts_pad_left',shell.prompts_pad_left) | |
3272 | save_dstore('rc_separate_in',shell.separate_in) |
|
3271 | save_dstore('rc_separate_in',shell.separate_in) | |
3273 | save_dstore('rc_plain_text_only',disp_formatter.plain_text_only) |
|
3272 | save_dstore('rc_plain_text_only',disp_formatter.plain_text_only) | |
3274 |
|
3273 | |||
3275 | if mode == False: |
|
3274 | if mode == False: | |
3276 | # turn on |
|
3275 | # turn on | |
3277 | oc.prompt1.p_template = '>>> ' |
|
3276 | oc.prompt1.p_template = '>>> ' | |
3278 | oc.prompt2.p_template = '... ' |
|
3277 | oc.prompt2.p_template = '... ' | |
3279 | oc.prompt_out.p_template = '' |
|
3278 | oc.prompt_out.p_template = '' | |
3280 |
|
3279 | |||
3281 | # Prompt separators like plain python |
|
3280 | # Prompt separators like plain python | |
3282 | oc.input_sep = oc.prompt1.sep = '' |
|
3281 | oc.input_sep = oc.prompt1.sep = '' | |
3283 | oc.output_sep = '' |
|
3282 | oc.output_sep = '' | |
3284 | oc.output_sep2 = '' |
|
3283 | oc.output_sep2 = '' | |
3285 |
|
3284 | |||
3286 | oc.prompt1.pad_left = oc.prompt2.pad_left = \ |
|
3285 | oc.prompt1.pad_left = oc.prompt2.pad_left = \ | |
3287 | oc.prompt_out.pad_left = False |
|
3286 | oc.prompt_out.pad_left = False | |
3288 |
|
3287 | |||
3289 | ptformatter.pprint = False |
|
3288 | ptformatter.pprint = False | |
3290 | disp_formatter.plain_text_only = True |
|
3289 | disp_formatter.plain_text_only = True | |
3291 |
|
3290 | |||
3292 | shell.magic_xmode('Plain') |
|
3291 | shell.magic_xmode('Plain') | |
3293 | else: |
|
3292 | else: | |
3294 | # turn off |
|
3293 | # turn off | |
3295 | oc.prompt1.p_template = shell.prompt_in1 |
|
3294 | oc.prompt1.p_template = shell.prompt_in1 | |
3296 | oc.prompt2.p_template = shell.prompt_in2 |
|
3295 | oc.prompt2.p_template = shell.prompt_in2 | |
3297 | oc.prompt_out.p_template = shell.prompt_out |
|
3296 | oc.prompt_out.p_template = shell.prompt_out | |
3298 |
|
3297 | |||
3299 | oc.input_sep = oc.prompt1.sep = dstore.rc_separate_in |
|
3298 | oc.input_sep = oc.prompt1.sep = dstore.rc_separate_in | |
3300 |
|
3299 | |||
3301 | oc.output_sep = dstore.rc_separate_out |
|
3300 | oc.output_sep = dstore.rc_separate_out | |
3302 | oc.output_sep2 = dstore.rc_separate_out2 |
|
3301 | oc.output_sep2 = dstore.rc_separate_out2 | |
3303 |
|
3302 | |||
3304 | oc.prompt1.pad_left = oc.prompt2.pad_left = \ |
|
3303 | oc.prompt1.pad_left = oc.prompt2.pad_left = \ | |
3305 | oc.prompt_out.pad_left = dstore.rc_prompts_pad_left |
|
3304 | oc.prompt_out.pad_left = dstore.rc_prompts_pad_left | |
3306 |
|
3305 | |||
3307 | ptformatter.pprint = dstore.rc_pprint |
|
3306 | ptformatter.pprint = dstore.rc_pprint | |
3308 | disp_formatter.plain_text_only = dstore.rc_plain_text_only |
|
3307 | disp_formatter.plain_text_only = dstore.rc_plain_text_only | |
3309 |
|
3308 | |||
3310 | shell.magic_xmode(dstore.xmode) |
|
3309 | shell.magic_xmode(dstore.xmode) | |
3311 |
|
3310 | |||
3312 | # Store new mode and inform |
|
3311 | # Store new mode and inform | |
3313 | dstore.mode = bool(1-int(mode)) |
|
3312 | dstore.mode = bool(1-int(mode)) | |
3314 | mode_label = ['OFF','ON'][dstore.mode] |
|
3313 | mode_label = ['OFF','ON'][dstore.mode] | |
3315 | print 'Doctest mode is:', mode_label |
|
3314 | print 'Doctest mode is:', mode_label | |
3316 |
|
3315 | |||
3317 | def magic_gui(self, parameter_s=''): |
|
3316 | def magic_gui(self, parameter_s=''): | |
3318 | """Enable or disable IPython GUI event loop integration. |
|
3317 | """Enable or disable IPython GUI event loop integration. | |
3319 |
|
3318 | |||
3320 | %gui [GUINAME] |
|
3319 | %gui [GUINAME] | |
3321 |
|
3320 | |||
3322 | This magic replaces IPython's threaded shells that were activated |
|
3321 | This magic replaces IPython's threaded shells that were activated | |
3323 | using the (pylab/wthread/etc.) command line flags. GUI toolkits |
|
3322 | using the (pylab/wthread/etc.) command line flags. GUI toolkits | |
3324 | can now be enabled, disabled and changed at runtime and keyboard |
|
3323 | can now be enabled, disabled and changed at runtime and keyboard | |
3325 | interrupts should work without any problems. The following toolkits |
|
3324 | interrupts should work without any problems. The following toolkits | |
3326 | are supported: wxPython, PyQt4, PyGTK, and Tk:: |
|
3325 | are supported: wxPython, PyQt4, PyGTK, and Tk:: | |
3327 |
|
3326 | |||
3328 | %gui wx # enable wxPython event loop integration |
|
3327 | %gui wx # enable wxPython event loop integration | |
3329 | %gui qt4|qt # enable PyQt4 event loop integration |
|
3328 | %gui qt4|qt # enable PyQt4 event loop integration | |
3330 | %gui gtk # enable PyGTK event loop integration |
|
3329 | %gui gtk # enable PyGTK event loop integration | |
3331 | %gui tk # enable Tk event loop integration |
|
3330 | %gui tk # enable Tk event loop integration | |
3332 | %gui # disable all event loop integration |
|
3331 | %gui # disable all event loop integration | |
3333 |
|
3332 | |||
3334 | WARNING: after any of these has been called you can simply create |
|
3333 | WARNING: after any of these has been called you can simply create | |
3335 | an application object, but DO NOT start the event loop yourself, as |
|
3334 | an application object, but DO NOT start the event loop yourself, as | |
3336 | we have already handled that. |
|
3335 | we have already handled that. | |
3337 | """ |
|
3336 | """ | |
3338 | from IPython.lib.inputhook import enable_gui |
|
3337 | from IPython.lib.inputhook import enable_gui | |
3339 | opts, arg = self.parse_options(parameter_s, '') |
|
3338 | opts, arg = self.parse_options(parameter_s, '') | |
3340 | if arg=='': arg = None |
|
3339 | if arg=='': arg = None | |
3341 | return enable_gui(arg) |
|
3340 | return enable_gui(arg) | |
3342 |
|
3341 | |||
3343 | def magic_load_ext(self, module_str): |
|
3342 | def magic_load_ext(self, module_str): | |
3344 | """Load an IPython extension by its module name.""" |
|
3343 | """Load an IPython extension by its module name.""" | |
3345 | return self.extension_manager.load_extension(module_str) |
|
3344 | return self.extension_manager.load_extension(module_str) | |
3346 |
|
3345 | |||
3347 | def magic_unload_ext(self, module_str): |
|
3346 | def magic_unload_ext(self, module_str): | |
3348 | """Unload an IPython extension by its module name.""" |
|
3347 | """Unload an IPython extension by its module name.""" | |
3349 | self.extension_manager.unload_extension(module_str) |
|
3348 | self.extension_manager.unload_extension(module_str) | |
3350 |
|
3349 | |||
3351 | def magic_reload_ext(self, module_str): |
|
3350 | def magic_reload_ext(self, module_str): | |
3352 | """Reload an IPython extension by its module name.""" |
|
3351 | """Reload an IPython extension by its module name.""" | |
3353 | self.extension_manager.reload_extension(module_str) |
|
3352 | self.extension_manager.reload_extension(module_str) | |
3354 |
|
3353 | |||
3355 | @skip_doctest |
|
3354 | @skip_doctest | |
3356 | def magic_install_profiles(self, s): |
|
3355 | def magic_install_profiles(self, s): | |
3357 | """Install the default IPython profiles into the .ipython dir. |
|
3356 | """Install the default IPython profiles into the .ipython dir. | |
3358 |
|
3357 | |||
3359 | If the default profiles have already been installed, they will not |
|
3358 | If the default profiles have already been installed, they will not | |
3360 | be overwritten. You can force overwriting them by using the ``-o`` |
|
3359 | be overwritten. You can force overwriting them by using the ``-o`` | |
3361 | option:: |
|
3360 | option:: | |
3362 |
|
3361 | |||
3363 | In [1]: %install_profiles -o |
|
3362 | In [1]: %install_profiles -o | |
3364 | """ |
|
3363 | """ | |
3365 | if '-o' in s: |
|
3364 | if '-o' in s: | |
3366 | overwrite = True |
|
3365 | overwrite = True | |
3367 | else: |
|
3366 | else: | |
3368 | overwrite = False |
|
3367 | overwrite = False | |
3369 | from IPython.config import profile |
|
3368 | from IPython.config import profile | |
3370 | profile_dir = os.path.dirname(profile.__file__) |
|
3369 | profile_dir = os.path.dirname(profile.__file__) | |
3371 | ipython_dir = self.ipython_dir |
|
3370 | ipython_dir = self.ipython_dir | |
3372 | print "Installing profiles to: %s [overwrite=%s]"%(ipython_dir,overwrite) |
|
3371 | print "Installing profiles to: %s [overwrite=%s]"%(ipython_dir,overwrite) | |
3373 | for src in os.listdir(profile_dir): |
|
3372 | for src in os.listdir(profile_dir): | |
3374 | if src.startswith('profile_'): |
|
3373 | if src.startswith('profile_'): | |
3375 | name = src.replace('profile_', '') |
|
3374 | name = src.replace('profile_', '') | |
3376 | print " %s"%name |
|
3375 | print " %s"%name | |
3377 | pd = ProfileDir.create_profile_dir_by_name(ipython_dir, name) |
|
3376 | pd = ProfileDir.create_profile_dir_by_name(ipython_dir, name) | |
3378 | pd.copy_config_file('ipython_config.py', path=src, |
|
3377 | pd.copy_config_file('ipython_config.py', path=src, | |
3379 | overwrite=overwrite) |
|
3378 | overwrite=overwrite) | |
3380 |
|
3379 | |||
3381 | @skip_doctest |
|
3380 | @skip_doctest | |
3382 | def magic_install_default_config(self, s): |
|
3381 | def magic_install_default_config(self, s): | |
3383 | """Install IPython's default config file into the .ipython dir. |
|
3382 | """Install IPython's default config file into the .ipython dir. | |
3384 |
|
3383 | |||
3385 | If the default config file (:file:`ipython_config.py`) is already |
|
3384 | If the default config file (:file:`ipython_config.py`) is already | |
3386 | installed, it will not be overwritten. You can force overwriting |
|
3385 | installed, it will not be overwritten. You can force overwriting | |
3387 | by using the ``-o`` option:: |
|
3386 | by using the ``-o`` option:: | |
3388 |
|
3387 | |||
3389 | In [1]: %install_default_config |
|
3388 | In [1]: %install_default_config | |
3390 | """ |
|
3389 | """ | |
3391 | if '-o' in s: |
|
3390 | if '-o' in s: | |
3392 | overwrite = True |
|
3391 | overwrite = True | |
3393 | else: |
|
3392 | else: | |
3394 | overwrite = False |
|
3393 | overwrite = False | |
3395 | pd = self.shell.profile_dir |
|
3394 | pd = self.shell.profile_dir | |
3396 | print "Installing default config file in: %s" % pd.location |
|
3395 | print "Installing default config file in: %s" % pd.location | |
3397 | pd.copy_config_file('ipython_config.py', overwrite=overwrite) |
|
3396 | pd.copy_config_file('ipython_config.py', overwrite=overwrite) | |
3398 |
|
3397 | |||
3399 | # Pylab support: simple wrappers that activate pylab, load gui input |
|
3398 | # Pylab support: simple wrappers that activate pylab, load gui input | |
3400 | # handling and modify slightly %run |
|
3399 | # handling and modify slightly %run | |
3401 |
|
3400 | |||
3402 | @skip_doctest |
|
3401 | @skip_doctest | |
3403 | def _pylab_magic_run(self, parameter_s=''): |
|
3402 | def _pylab_magic_run(self, parameter_s=''): | |
3404 | Magic.magic_run(self, parameter_s, |
|
3403 | Magic.magic_run(self, parameter_s, | |
3405 | runner=mpl_runner(self.shell.safe_execfile)) |
|
3404 | runner=mpl_runner(self.shell.safe_execfile)) | |
3406 |
|
3405 | |||
3407 | _pylab_magic_run.__doc__ = magic_run.__doc__ |
|
3406 | _pylab_magic_run.__doc__ = magic_run.__doc__ | |
3408 |
|
3407 | |||
3409 | @skip_doctest |
|
3408 | @skip_doctest | |
3410 | def magic_pylab(self, s): |
|
3409 | def magic_pylab(self, s): | |
3411 | """Load numpy and matplotlib to work interactively. |
|
3410 | """Load numpy and matplotlib to work interactively. | |
3412 |
|
3411 | |||
3413 | %pylab [GUINAME] |
|
3412 | %pylab [GUINAME] | |
3414 |
|
3413 | |||
3415 | This function lets you activate pylab (matplotlib, numpy and |
|
3414 | This function lets you activate pylab (matplotlib, numpy and | |
3416 | interactive support) at any point during an IPython session. |
|
3415 | interactive support) at any point during an IPython session. | |
3417 |
|
3416 | |||
3418 | It will import at the top level numpy as np, pyplot as plt, matplotlib, |
|
3417 | It will import at the top level numpy as np, pyplot as plt, matplotlib, | |
3419 | pylab and mlab, as well as all names from numpy and pylab. |
|
3418 | pylab and mlab, as well as all names from numpy and pylab. | |
3420 |
|
3419 | |||
3421 | Parameters |
|
3420 | Parameters | |
3422 | ---------- |
|
3421 | ---------- | |
3423 | guiname : optional |
|
3422 | guiname : optional | |
3424 | One of the valid arguments to the %gui magic ('qt', 'wx', 'gtk', 'osx' or |
|
3423 | One of the valid arguments to the %gui magic ('qt', 'wx', 'gtk', 'osx' or | |
3425 | 'tk'). If given, the corresponding Matplotlib backend is used, |
|
3424 | 'tk'). If given, the corresponding Matplotlib backend is used, | |
3426 | otherwise matplotlib's default (which you can override in your |
|
3425 | otherwise matplotlib's default (which you can override in your | |
3427 | matplotlib config file) is used. |
|
3426 | matplotlib config file) is used. | |
3428 |
|
3427 | |||
3429 | Examples |
|
3428 | Examples | |
3430 | -------- |
|
3429 | -------- | |
3431 | In this case, where the MPL default is TkAgg: |
|
3430 | In this case, where the MPL default is TkAgg: | |
3432 | In [2]: %pylab |
|
3431 | In [2]: %pylab | |
3433 |
|
3432 | |||
3434 | Welcome to pylab, a matplotlib-based Python environment. |
|
3433 | Welcome to pylab, a matplotlib-based Python environment. | |
3435 | Backend in use: TkAgg |
|
3434 | Backend in use: TkAgg | |
3436 | For more information, type 'help(pylab)'. |
|
3435 | For more information, type 'help(pylab)'. | |
3437 |
|
3436 | |||
3438 | But you can explicitly request a different backend: |
|
3437 | But you can explicitly request a different backend: | |
3439 | In [3]: %pylab qt |
|
3438 | In [3]: %pylab qt | |
3440 |
|
3439 | |||
3441 | Welcome to pylab, a matplotlib-based Python environment. |
|
3440 | Welcome to pylab, a matplotlib-based Python environment. | |
3442 | Backend in use: Qt4Agg |
|
3441 | Backend in use: Qt4Agg | |
3443 | For more information, type 'help(pylab)'. |
|
3442 | For more information, type 'help(pylab)'. | |
3444 | """ |
|
3443 | """ | |
3445 | self.shell.enable_pylab(s) |
|
3444 | self.shell.enable_pylab(s) | |
3446 |
|
3445 | |||
3447 | def magic_tb(self, s): |
|
3446 | def magic_tb(self, s): | |
3448 | """Print the last traceback with the currently active exception mode. |
|
3447 | """Print the last traceback with the currently active exception mode. | |
3449 |
|
3448 | |||
3450 | See %xmode for changing exception reporting modes.""" |
|
3449 | See %xmode for changing exception reporting modes.""" | |
3451 | self.shell.showtraceback() |
|
3450 | self.shell.showtraceback() | |
3452 |
|
3451 | |||
3453 | @skip_doctest |
|
3452 | @skip_doctest | |
3454 | def magic_precision(self, s=''): |
|
3453 | def magic_precision(self, s=''): | |
3455 | """Set floating point precision for pretty printing. |
|
3454 | """Set floating point precision for pretty printing. | |
3456 |
|
3455 | |||
3457 | Can set either integer precision or a format string. |
|
3456 | Can set either integer precision or a format string. | |
3458 |
|
3457 | |||
3459 | If numpy has been imported and precision is an int, |
|
3458 | If numpy has been imported and precision is an int, | |
3460 | numpy display precision will also be set, via ``numpy.set_printoptions``. |
|
3459 | numpy display precision will also be set, via ``numpy.set_printoptions``. | |
3461 |
|
3460 | |||
3462 | If no argument is given, defaults will be restored. |
|
3461 | If no argument is given, defaults will be restored. | |
3463 |
|
3462 | |||
3464 | Examples |
|
3463 | Examples | |
3465 | -------- |
|
3464 | -------- | |
3466 | :: |
|
3465 | :: | |
3467 |
|
3466 | |||
3468 | In [1]: from math import pi |
|
3467 | In [1]: from math import pi | |
3469 |
|
3468 | |||
3470 | In [2]: %precision 3 |
|
3469 | In [2]: %precision 3 | |
3471 | Out[2]: u'%.3f' |
|
3470 | Out[2]: u'%.3f' | |
3472 |
|
3471 | |||
3473 | In [3]: pi |
|
3472 | In [3]: pi | |
3474 | Out[3]: 3.142 |
|
3473 | Out[3]: 3.142 | |
3475 |
|
3474 | |||
3476 | In [4]: %precision %i |
|
3475 | In [4]: %precision %i | |
3477 | Out[4]: u'%i' |
|
3476 | Out[4]: u'%i' | |
3478 |
|
3477 | |||
3479 | In [5]: pi |
|
3478 | In [5]: pi | |
3480 | Out[5]: 3 |
|
3479 | Out[5]: 3 | |
3481 |
|
3480 | |||
3482 | In [6]: %precision %e |
|
3481 | In [6]: %precision %e | |
3483 | Out[6]: u'%e' |
|
3482 | Out[6]: u'%e' | |
3484 |
|
3483 | |||
3485 | In [7]: pi**10 |
|
3484 | In [7]: pi**10 | |
3486 | Out[7]: 9.364805e+04 |
|
3485 | Out[7]: 9.364805e+04 | |
3487 |
|
3486 | |||
3488 | In [8]: %precision |
|
3487 | In [8]: %precision | |
3489 | Out[8]: u'%r' |
|
3488 | Out[8]: u'%r' | |
3490 |
|
3489 | |||
3491 | In [9]: pi**10 |
|
3490 | In [9]: pi**10 | |
3492 | Out[9]: 93648.047476082982 |
|
3491 | Out[9]: 93648.047476082982 | |
3493 |
|
3492 | |||
3494 | """ |
|
3493 | """ | |
3495 |
|
3494 | |||
3496 | ptformatter = self.shell.display_formatter.formatters['text/plain'] |
|
3495 | ptformatter = self.shell.display_formatter.formatters['text/plain'] | |
3497 | ptformatter.float_precision = s |
|
3496 | ptformatter.float_precision = s | |
3498 | return ptformatter.float_format |
|
3497 | return ptformatter.float_format | |
3499 |
|
3498 | |||
3500 |
|
3499 | |||
3501 | @magic_arguments.magic_arguments() |
|
3500 | @magic_arguments.magic_arguments() | |
3502 | @magic_arguments.argument( |
|
3501 | @magic_arguments.argument( | |
3503 | '-e', '--export', action='store_true', default=False, |
|
3502 | '-e', '--export', action='store_true', default=False, | |
3504 | help='Export IPython history as a notebook. The filename argument ' |
|
3503 | help='Export IPython history as a notebook. The filename argument ' | |
3505 | 'is used to specify the notebook name and format. For example ' |
|
3504 | 'is used to specify the notebook name and format. For example ' | |
3506 | 'a filename of notebook.ipynb will result in a notebook name ' |
|
3505 | 'a filename of notebook.ipynb will result in a notebook name ' | |
3507 | 'of "notebook" and a format of "xml". Likewise using a ".json" ' |
|
3506 | 'of "notebook" and a format of "xml". Likewise using a ".json" ' | |
3508 | 'or ".py" file extension will write the notebook in the json ' |
|
3507 | 'or ".py" file extension will write the notebook in the json ' | |
3509 | 'or py formats.' |
|
3508 | 'or py formats.' | |
3510 | ) |
|
3509 | ) | |
3511 | @magic_arguments.argument( |
|
3510 | @magic_arguments.argument( | |
3512 | '-f', '--format', |
|
3511 | '-f', '--format', | |
3513 | help='Convert an existing IPython notebook to a new format. This option ' |
|
3512 | help='Convert an existing IPython notebook to a new format. This option ' | |
3514 | 'specifies the new format and can have the values: xml, json, py. ' |
|
3513 | 'specifies the new format and can have the values: xml, json, py. ' | |
3515 | 'The target filename is choosen automatically based on the new ' |
|
3514 | 'The target filename is choosen automatically based on the new ' | |
3516 | 'format. The filename argument gives the name of the source file.' |
|
3515 | 'format. The filename argument gives the name of the source file.' | |
3517 | ) |
|
3516 | ) | |
3518 | @magic_arguments.argument( |
|
3517 | @magic_arguments.argument( | |
3519 | 'filename', type=unicode, |
|
3518 | 'filename', type=unicode, | |
3520 | help='Notebook name or filename' |
|
3519 | help='Notebook name or filename' | |
3521 | ) |
|
3520 | ) | |
3522 | def magic_notebook(self, s): |
|
3521 | def magic_notebook(self, s): | |
3523 | """Export and convert IPython notebooks. |
|
3522 | """Export and convert IPython notebooks. | |
3524 |
|
3523 | |||
3525 | This function can export the current IPython history to a notebook file |
|
3524 | This function can export the current IPython history to a notebook file | |
3526 | or can convert an existing notebook file into a different format. For |
|
3525 | or can convert an existing notebook file into a different format. For | |
3527 | example, to export the history to "foo.ipynb" do "%notebook -e foo.ipynb". |
|
3526 | example, to export the history to "foo.ipynb" do "%notebook -e foo.ipynb". | |
3528 | To export the history to "foo.py" do "%notebook -e foo.py". To convert |
|
3527 | To export the history to "foo.py" do "%notebook -e foo.py". To convert | |
3529 | "foo.ipynb" to "foo.json" do "%notebook -f json foo.ipynb". Possible |
|
3528 | "foo.ipynb" to "foo.json" do "%notebook -f json foo.ipynb". Possible | |
3530 | formats include (xml/ipynb, json, py). |
|
3529 | formats include (xml/ipynb, json, py). | |
3531 | """ |
|
3530 | """ | |
3532 | args = magic_arguments.parse_argstring(self.magic_notebook, s) |
|
3531 | args = magic_arguments.parse_argstring(self.magic_notebook, s) | |
3533 |
|
3532 | |||
3534 | from IPython.nbformat import current |
|
3533 | from IPython.nbformat import current | |
3535 | if args.export: |
|
3534 | if args.export: | |
3536 | fname, name, format = current.parse_filename(args.filename) |
|
3535 | fname, name, format = current.parse_filename(args.filename) | |
3537 | cells = [] |
|
3536 | cells = [] | |
3538 | hist = list(self.history_manager.get_range()) |
|
3537 | hist = list(self.history_manager.get_range()) | |
3539 | for session, prompt_number, input in hist[:-1]: |
|
3538 | for session, prompt_number, input in hist[:-1]: | |
3540 | cells.append(current.new_code_cell(prompt_number=prompt_number, input=input)) |
|
3539 | cells.append(current.new_code_cell(prompt_number=prompt_number, input=input)) | |
3541 | worksheet = current.new_worksheet(cells=cells) |
|
3540 | worksheet = current.new_worksheet(cells=cells) | |
3542 | nb = current.new_notebook(name=name,worksheets=[worksheet]) |
|
3541 | nb = current.new_notebook(name=name,worksheets=[worksheet]) | |
3543 | with open(fname, 'w') as f: |
|
3542 | with open(fname, 'w') as f: | |
3544 | current.write(nb, f, format); |
|
3543 | current.write(nb, f, format); | |
3545 | elif args.format is not None: |
|
3544 | elif args.format is not None: | |
3546 | old_fname, old_name, old_format = current.parse_filename(args.filename) |
|
3545 | old_fname, old_name, old_format = current.parse_filename(args.filename) | |
3547 | new_format = args.format |
|
3546 | new_format = args.format | |
3548 | if new_format == u'xml' or new_format == u'ipynb': |
|
3547 | if new_format == u'xml' or new_format == u'ipynb': | |
3549 | new_fname = old_name + u'.ipynb' |
|
3548 | new_fname = old_name + u'.ipynb' | |
3550 | new_format = u'xml' |
|
3549 | new_format = u'xml' | |
3551 | elif new_format == u'py': |
|
3550 | elif new_format == u'py': | |
3552 | new_fname = old_name + u'.py' |
|
3551 | new_fname = old_name + u'.py' | |
3553 | elif new_format == u'json': |
|
3552 | elif new_format == u'json': | |
3554 | new_fname = old_name + u'.json' |
|
3553 | new_fname = old_name + u'.json' | |
3555 | else: |
|
3554 | else: | |
3556 | raise ValueError('Invalid notebook format: %s' % newformat) |
|
3555 | raise ValueError('Invalid notebook format: %s' % newformat) | |
3557 | with open(old_fname, 'r') as f: |
|
3556 | with open(old_fname, 'r') as f: | |
3558 | nb = current.read(f, old_format) |
|
3557 | nb = current.read(f, old_format) | |
3559 | with open(new_fname, 'w') as f: |
|
3558 | with open(new_fname, 'w') as f: | |
3560 | current.write(nb, f, new_format) |
|
3559 | current.write(nb, f, new_format) | |
3561 |
|
3560 | |||
3562 |
|
3561 | |||
3563 | # end Magic |
|
3562 | # end Magic |
@@ -1,249 +1,250 b'' | |||||
1 | # encoding: utf-8 |
|
1 | # encoding: utf-8 | |
2 | """ |
|
2 | """ | |
3 | An application for managing IPython profiles. |
|
3 | An application for managing IPython profiles. | |
4 |
|
4 | |||
5 | To be invoked as the `ipython profile` subcommand. |
|
5 | To be invoked as the `ipython profile` subcommand. | |
6 |
|
6 | |||
7 | Authors: |
|
7 | Authors: | |
8 |
|
8 | |||
9 | * Min RK |
|
9 | * Min RK | |
10 |
|
10 | |||
11 | """ |
|
11 | """ | |
12 |
|
12 | |||
13 | #----------------------------------------------------------------------------- |
|
13 | #----------------------------------------------------------------------------- | |
14 | # Copyright (C) 2008-2011 The IPython Development Team |
|
14 | # Copyright (C) 2008-2011 The IPython Development Team | |
15 | # |
|
15 | # | |
16 | # Distributed under the terms of the BSD License. The full license is in |
|
16 | # Distributed under the terms of the BSD License. The full license is in | |
17 | # the file COPYING, distributed as part of this software. |
|
17 | # the file COPYING, distributed as part of this software. | |
18 | #----------------------------------------------------------------------------- |
|
18 | #----------------------------------------------------------------------------- | |
19 |
|
19 | |||
20 | #----------------------------------------------------------------------------- |
|
20 | #----------------------------------------------------------------------------- | |
21 | # Imports |
|
21 | # Imports | |
22 | #----------------------------------------------------------------------------- |
|
22 | #----------------------------------------------------------------------------- | |
23 |
|
23 | |||
24 | import logging |
|
24 | import logging | |
25 | import os |
|
25 | import os | |
26 |
|
26 | |||
27 | from IPython.config.application import Application, boolean_flag |
|
27 | from IPython.config.application import Application, boolean_flag | |
28 | from IPython.core.application import ( |
|
28 | from IPython.core.application import ( | |
29 | BaseIPythonApplication, base_flags, base_aliases |
|
29 | BaseIPythonApplication, base_flags, base_aliases | |
30 | ) |
|
30 | ) | |
31 | from IPython.core.profiledir import ProfileDir |
|
31 | from IPython.core.profiledir import ProfileDir | |
32 | from IPython.utils.path import get_ipython_dir |
|
32 | from IPython.utils.path import get_ipython_dir | |
33 | from IPython.utils.traitlets import Unicode, Bool, Dict |
|
33 | from IPython.utils.traitlets import Unicode, Bool, Dict | |
34 |
|
34 | |||
35 | #----------------------------------------------------------------------------- |
|
35 | #----------------------------------------------------------------------------- | |
36 | # Constants |
|
36 | # Constants | |
37 | #----------------------------------------------------------------------------- |
|
37 | #----------------------------------------------------------------------------- | |
38 |
|
38 | |||
39 | create_help = """Create an IPython profile by name |
|
39 | create_help = """Create an IPython profile by name | |
40 |
|
40 | |||
41 | Create an ipython profile directory by its name or |
|
41 | Create an ipython profile directory by its name or | |
42 | profile directory path. Profile directories contain |
|
42 | profile directory path. Profile directories contain | |
43 | configuration, log and security related files and are named |
|
43 | configuration, log and security related files and are named | |
44 | using the convention 'profile_<name>'. By default they are |
|
44 | using the convention 'profile_<name>'. By default they are | |
45 | located in your ipython directory. Once created, you will |
|
45 | located in your ipython directory. Once created, you will | |
46 | can edit the configuration files in the profile |
|
46 | can edit the configuration files in the profile | |
47 | directory to configure IPython. Most users will create a |
|
47 | directory to configure IPython. Most users will create a | |
48 | profile directory by name, |
|
48 | profile directory by name, | |
49 | `ipython profile create myprofile`, which will put the directory |
|
49 | `ipython profile create myprofile`, which will put the directory | |
50 | in `<ipython_dir>/profile_myprofile`. |
|
50 | in `<ipython_dir>/profile_myprofile`. | |
51 | """ |
|
51 | """ | |
52 | list_help = """List available IPython profiles |
|
52 | list_help = """List available IPython profiles | |
53 |
|
53 | |||
54 | List all available profiles, by profile location, that can |
|
54 | List all available profiles, by profile location, that can | |
55 | be found in the current working directly or in the ipython |
|
55 | be found in the current working directly or in the ipython | |
56 | directory. Profile directories are named using the convention |
|
56 | directory. Profile directories are named using the convention | |
57 | 'profile_<profile>'. |
|
57 | 'profile_<profile>'. | |
58 | """ |
|
58 | """ | |
59 | profile_help = """Manage IPython profiles |
|
59 | profile_help = """Manage IPython profiles | |
60 |
|
60 | |||
61 | Profile directories contain |
|
61 | Profile directories contain | |
62 | configuration, log and security related files and are named |
|
62 | configuration, log and security related files and are named | |
63 | using the convention 'profile_<name>'. By default they are |
|
63 | using the convention 'profile_<name>'. By default they are | |
64 | located in your ipython directory. You can create profiles |
|
64 | located in your ipython directory. You can create profiles | |
65 | with `ipython profile create <name>`, or see the profiles you |
|
65 | with `ipython profile create <name>`, or see the profiles you | |
66 | already have with `ipython profile list` |
|
66 | already have with `ipython profile list` | |
67 |
|
67 | |||
68 | To get started configuring IPython, simply do: |
|
68 | To get started configuring IPython, simply do: | |
69 |
|
69 | |||
70 | $> ipython profile create |
|
70 | $> ipython profile create | |
71 |
|
71 | |||
72 | and IPython will create the default profile in <ipython_dir>/profile_default, |
|
72 | and IPython will create the default profile in <ipython_dir>/profile_default, | |
73 | where you can edit ipython_config.py to start configuring IPython. |
|
73 | where you can edit ipython_config.py to start configuring IPython. | |
74 |
|
74 | |||
75 | """ |
|
75 | """ | |
76 |
|
76 | |||
77 | _list_examples = "ipython profile list # list all profiles" |
|
77 | _list_examples = "ipython profile list # list all profiles" | |
78 |
|
78 | |||
79 | _create_examples = """ |
|
79 | _create_examples = """ | |
80 | ipython profile create foo # create profile foo w/ default config files |
|
80 | ipython profile create foo # create profile foo w/ default config files | |
81 | ipython profile create foo --reset # restage default config files over current |
|
81 | ipython profile create foo --reset # restage default config files over current | |
82 | ipython profile create foo --parallel # also stage parallel config files |
|
82 | ipython profile create foo --parallel # also stage parallel config files | |
83 | """ |
|
83 | """ | |
84 |
|
84 | |||
85 | _main_examples = """ |
|
85 | _main_examples = """ | |
86 | ipython profile create -h # show the help string for the create subcommand |
|
86 | ipython profile create -h # show the help string for the create subcommand | |
87 | ipython profile list -h # show the help string for the list subcommand |
|
87 | ipython profile list -h # show the help string for the list subcommand | |
88 | """ |
|
88 | """ | |
89 |
|
89 | |||
90 | #----------------------------------------------------------------------------- |
|
90 | #----------------------------------------------------------------------------- | |
91 | # Profile Application Class (for `ipython profile` subcommand) |
|
91 | # Profile Application Class (for `ipython profile` subcommand) | |
92 | #----------------------------------------------------------------------------- |
|
92 | #----------------------------------------------------------------------------- | |
93 |
|
93 | |||
94 |
|
94 | |||
95 | class ProfileList(Application): |
|
95 | class ProfileList(Application): | |
96 | name = u'ipython-profile' |
|
96 | name = u'ipython-profile' | |
97 | description = list_help |
|
97 | description = list_help | |
98 | examples = _list_examples |
|
98 | examples = _list_examples | |
99 |
|
99 | |||
100 | aliases = Dict({ |
|
100 | aliases = Dict({ | |
101 | 'ipython-dir' : 'ProfileList.ipython_dir', |
|
101 | 'ipython-dir' : 'ProfileList.ipython_dir', | |
102 | 'log-level' : 'Application.log_level', |
|
102 | 'log-level' : 'Application.log_level', | |
103 | }) |
|
103 | }) | |
104 | flags = Dict(dict( |
|
104 | flags = Dict(dict( | |
105 | debug = ({'Application' : {'log_level' : 0}}, |
|
105 | debug = ({'Application' : {'log_level' : 0}}, | |
106 | "Set Application.log_level to 0, maximizing log output." |
|
106 | "Set Application.log_level to 0, maximizing log output." | |
107 | ) |
|
107 | ) | |
108 | )) |
|
108 | )) | |
109 |
|
109 | |||
110 | ipython_dir = Unicode(get_ipython_dir(), config=True, |
|
110 | ipython_dir = Unicode(get_ipython_dir(), config=True, | |
111 | help=""" |
|
111 | help=""" | |
112 | The name of the IPython directory. This directory is used for logging |
|
112 | The name of the IPython directory. This directory is used for logging | |
113 | configuration (through profiles), history storage, etc. The default |
|
113 | configuration (through profiles), history storage, etc. The default | |
114 | is usually $HOME/.ipython. This options can also be specified through |
|
114 | is usually $HOME/.ipython. This options can also be specified through | |
115 | the environment variable IPYTHON_DIR. |
|
115 | the environment variable IPYTHON_DIR. | |
116 | """ |
|
116 | """ | |
117 | ) |
|
117 | ) | |
118 |
|
118 | |||
119 | def list_profile_dirs(self): |
|
119 | def list_profile_dirs(self): | |
120 | # Find the search paths |
|
120 | # Find the search paths | |
121 | paths = [os.getcwdu(), self.ipython_dir] |
|
121 | paths = [os.getcwdu(), self.ipython_dir] | |
122 |
|
122 | |||
123 | self.log.warn('Searching for IPython profiles in paths: %r' % paths) |
|
123 | self.log.warn('Searching for IPython profiles in paths: %r' % paths) | |
124 | for path in paths: |
|
124 | for path in paths: | |
125 | files = os.listdir(path) |
|
125 | files = os.listdir(path) | |
126 | for f in files: |
|
126 | for f in files: | |
127 | full_path = os.path.join(path, f) |
|
127 | full_path = os.path.join(path, f) | |
128 | if os.path.isdir(full_path) and f.startswith('profile_'): |
|
128 | if os.path.isdir(full_path) and f.startswith('profile_'): | |
129 | profile = f.split('_',1)[-1] |
|
129 | profile = f.split('_',1)[-1] | |
130 | start_cmd = 'ipython profile=%s' % profile |
|
130 | start_cmd = 'ipython profile=%s' % profile | |
131 | print start_cmd + " ==> " + full_path |
|
131 | print start_cmd + " ==> " + full_path | |
132 |
|
132 | |||
133 | def start(self): |
|
133 | def start(self): | |
134 | self.list_profile_dirs() |
|
134 | self.list_profile_dirs() | |
135 |
|
135 | |||
136 |
|
136 | |||
137 | create_flags = {} |
|
137 | create_flags = {} | |
138 | create_flags.update(base_flags) |
|
138 | create_flags.update(base_flags) | |
139 | # don't include '--init' flag, which implies running profile create in other apps |
|
139 | # don't include '--init' flag, which implies running profile create in other apps | |
140 | create_flags.pop('init') |
|
140 | create_flags.pop('init') | |
141 | create_flags['reset'] = ({'ProfileCreate': {'overwrite' : True}}, |
|
141 | create_flags['reset'] = ({'ProfileCreate': {'overwrite' : True}}, | |
142 | "reset config files in this profile to the defaults.") |
|
142 | "reset config files in this profile to the defaults.") | |
143 | create_flags['parallel'] = ({'ProfileCreate': {'parallel' : True}}, |
|
143 | create_flags['parallel'] = ({'ProfileCreate': {'parallel' : True}}, | |
144 | "Include the config files for parallel " |
|
144 | "Include the config files for parallel " | |
145 | "computing apps (ipengine, ipcontroller, etc.)") |
|
145 | "computing apps (ipengine, ipcontroller, etc.)") | |
146 |
|
146 | |||
147 |
|
147 | |||
148 | class ProfileCreate(BaseIPythonApplication): |
|
148 | class ProfileCreate(BaseIPythonApplication): | |
149 | name = u'ipython-profile' |
|
149 | name = u'ipython-profile' | |
150 | description = create_help |
|
150 | description = create_help | |
151 | examples = _create_examples |
|
151 | examples = _create_examples | |
152 | auto_create = Bool(True, config=False) |
|
152 | auto_create = Bool(True, config=False) | |
153 |
|
153 | |||
154 | def _copy_config_files_default(self): |
|
154 | def _copy_config_files_default(self): | |
155 | return True |
|
155 | return True | |
156 |
|
156 | |||
157 | parallel = Bool(False, config=True, |
|
157 | parallel = Bool(False, config=True, | |
158 | help="whether to include parallel computing config files") |
|
158 | help="whether to include parallel computing config files") | |
159 | def _parallel_changed(self, name, old, new): |
|
159 | def _parallel_changed(self, name, old, new): | |
160 | parallel_files = [ 'ipcontroller_config.py', |
|
160 | parallel_files = [ 'ipcontroller_config.py', | |
161 | 'ipengine_config.py', |
|
161 | 'ipengine_config.py', | |
162 | 'ipcluster_config.py' |
|
162 | 'ipcluster_config.py' | |
163 | ] |
|
163 | ] | |
164 | if new: |
|
164 | if new: | |
165 | for cf in parallel_files: |
|
165 | for cf in parallel_files: | |
166 | self.config_files.append(cf) |
|
166 | self.config_files.append(cf) | |
167 | else: |
|
167 | else: | |
168 | for cf in parallel_files: |
|
168 | for cf in parallel_files: | |
169 | if cf in self.config_files: |
|
169 | if cf in self.config_files: | |
170 | self.config_files.remove(cf) |
|
170 | self.config_files.remove(cf) | |
171 |
|
171 | |||
172 | def parse_command_line(self, argv): |
|
172 | def parse_command_line(self, argv): | |
173 | super(ProfileCreate, self).parse_command_line(argv) |
|
173 | super(ProfileCreate, self).parse_command_line(argv) | |
174 | # accept positional arg as profile name |
|
174 | # accept positional arg as profile name | |
175 | if self.extra_args: |
|
175 | if self.extra_args: | |
176 | self.profile = self.extra_args[0] |
|
176 | self.profile = self.extra_args[0] | |
177 |
|
177 | |||
178 | flags = Dict(create_flags) |
|
178 | flags = Dict(create_flags) | |
179 |
|
179 | |||
180 | classes = [ProfileDir] |
|
180 | classes = [ProfileDir] | |
181 |
|
181 | |||
182 | def init_config_files(self): |
|
182 | def init_config_files(self): | |
183 | super(ProfileCreate, self).init_config_files() |
|
183 | super(ProfileCreate, self).init_config_files() | |
184 | # use local imports, since these classes may import from here |
|
184 | # use local imports, since these classes may import from here | |
185 | from IPython.frontend.terminal.ipapp import TerminalIPythonApp |
|
185 | from IPython.frontend.terminal.ipapp import TerminalIPythonApp | |
186 | apps = [TerminalIPythonApp] |
|
186 | apps = [TerminalIPythonApp] | |
187 | try: |
|
187 | try: | |
188 | from IPython.frontend.qt.console.qtconsoleapp import IPythonQtConsoleApp |
|
188 | from IPython.frontend.qt.console.qtconsoleapp import IPythonQtConsoleApp | |
189 | except Exception: |
|
189 | except Exception: | |
190 | # this should be ImportError, but under weird circumstances |
|
190 | # this should be ImportError, but under weird circumstances | |
191 | # this might be an AttributeError, or possibly others |
|
191 | # this might be an AttributeError, or possibly others | |
192 | # in any case, nothing should cause the profile creation to crash. |
|
192 | # in any case, nothing should cause the profile creation to crash. | |
193 | pass |
|
193 | pass | |
194 | else: |
|
194 | else: | |
195 | apps.append(IPythonQtConsoleApp) |
|
195 | apps.append(IPythonQtConsoleApp) | |
196 | try: |
|
196 | try: | |
197 | from IPython.frontend.html.notebook.notebookapp import IPythonNotebookApp |
|
197 | from IPython.frontend.html.notebook.notebookapp import IPythonNotebookApp | |
198 |
except |
|
198 | except ImportError: | |
199 | # this should be ImportError, but under weird circumstances |
|
|||
200 | # this might be an AttributeError, or possibly others |
|
|||
201 | # in any case, nothing should cause the profile creation to crash. |
|
|||
202 | pass |
|
199 | pass | |
|
200 | except Exception: | |||
|
201 | self.log.debug('Unexpected error when importing IPythonNotebookApp', | |||
|
202 | exc_info=True | |||
|
203 | ) | |||
203 | else: |
|
204 | else: | |
204 | apps.append(IPythonNotebookApp) |
|
205 | apps.append(IPythonNotebookApp) | |
205 | if self.parallel: |
|
206 | if self.parallel: | |
206 | from IPython.parallel.apps.ipcontrollerapp import IPControllerApp |
|
207 | from IPython.parallel.apps.ipcontrollerapp import IPControllerApp | |
207 | from IPython.parallel.apps.ipengineapp import IPEngineApp |
|
208 | from IPython.parallel.apps.ipengineapp import IPEngineApp | |
208 | from IPython.parallel.apps.ipclusterapp import IPClusterStart |
|
209 | from IPython.parallel.apps.ipclusterapp import IPClusterStart | |
209 | from IPython.parallel.apps.iploggerapp import IPLoggerApp |
|
210 | from IPython.parallel.apps.iploggerapp import IPLoggerApp | |
210 | apps.extend([ |
|
211 | apps.extend([ | |
211 | IPControllerApp, |
|
212 | IPControllerApp, | |
212 | IPEngineApp, |
|
213 | IPEngineApp, | |
213 | IPClusterStart, |
|
214 | IPClusterStart, | |
214 | IPLoggerApp, |
|
215 | IPLoggerApp, | |
215 | ]) |
|
216 | ]) | |
216 | for App in apps: |
|
217 | for App in apps: | |
217 | app = App() |
|
218 | app = App() | |
218 | app.config.update(self.config) |
|
219 | app.config.update(self.config) | |
219 | app.log = self.log |
|
220 | app.log = self.log | |
220 | app.overwrite = self.overwrite |
|
221 | app.overwrite = self.overwrite | |
221 | app.copy_config_files=True |
|
222 | app.copy_config_files=True | |
222 | app.profile = self.profile |
|
223 | app.profile = self.profile | |
223 | app.init_profile_dir() |
|
224 | app.init_profile_dir() | |
224 | app.init_config_files() |
|
225 | app.init_config_files() | |
225 |
|
226 | |||
226 | def stage_default_config_file(self): |
|
227 | def stage_default_config_file(self): | |
227 | pass |
|
228 | pass | |
228 |
|
229 | |||
229 |
|
230 | |||
230 | class ProfileApp(Application): |
|
231 | class ProfileApp(Application): | |
231 | name = u'ipython-profile' |
|
232 | name = u'ipython-profile' | |
232 | description = profile_help |
|
233 | description = profile_help | |
233 | examples = _main_examples |
|
234 | examples = _main_examples | |
234 |
|
235 | |||
235 | subcommands = Dict(dict( |
|
236 | subcommands = Dict(dict( | |
236 | create = (ProfileCreate, "Create a new profile dir with default config files"), |
|
237 | create = (ProfileCreate, "Create a new profile dir with default config files"), | |
237 | list = (ProfileList, "List existing profiles") |
|
238 | list = (ProfileList, "List existing profiles") | |
238 | )) |
|
239 | )) | |
239 |
|
240 | |||
240 | def start(self): |
|
241 | def start(self): | |
241 | if self.subapp is None: |
|
242 | if self.subapp is None: | |
242 | print "No subcommand specified. Must specify one of: %s"%(self.subcommands.keys()) |
|
243 | print "No subcommand specified. Must specify one of: %s"%(self.subcommands.keys()) | |
243 |
|
244 | |||
244 | self.print_description() |
|
245 | self.print_description() | |
245 | self.print_subcommands() |
|
246 | self.print_subcommands() | |
246 | self.exit(1) |
|
247 | self.exit(1) | |
247 | else: |
|
248 | else: | |
248 | return self.subapp.start() |
|
249 | return self.subapp.start() | |
249 |
|
250 |
@@ -1,326 +1,337 b'' | |||||
1 |
"""Tornado handlers for the notebook. |
|
1 | """Tornado handlers for the notebook. | |
|
2 | ||||
|
3 | Authors: | |||
|
4 | ||||
|
5 | * Brian Granger | |||
|
6 | """ | |||
2 |
|
7 | |||
3 | #----------------------------------------------------------------------------- |
|
8 | #----------------------------------------------------------------------------- | |
4 | # Imports |
|
9 | # Copyright (C) 2008-2011 The IPython Development Team | |
|
10 | # | |||
|
11 | # Distributed under the terms of the BSD License. The full license is in | |||
|
12 | # the file COPYING, distributed as part of this software. | |||
5 | #----------------------------------------------------------------------------- |
|
13 | #----------------------------------------------------------------------------- | |
6 |
|
14 | |||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | # Imports | |||
|
17 | #----------------------------------------------------------------------------- | |||
7 |
|
18 | |||
8 | from tornado import web |
|
19 | from tornado import web | |
9 | from tornado import websocket |
|
20 | from tornado import websocket | |
10 |
|
21 | |||
11 | from zmq.eventloop import ioloop |
|
22 | from zmq.eventloop import ioloop | |
12 | from zmq.utils import jsonapi |
|
23 | from zmq.utils import jsonapi | |
13 |
|
24 | |||
14 | from IPython.zmq.session import Session |
|
25 | from IPython.zmq.session import Session | |
15 |
|
26 | |||
16 | try: |
|
27 | try: | |
17 | from docutils.core import publish_string |
|
28 | from docutils.core import publish_string | |
18 | except ImportError: |
|
29 | except ImportError: | |
19 | publish_string = None |
|
30 | publish_string = None | |
20 |
|
31 | |||
21 |
|
32 | |||
22 |
|
33 | |||
23 | #----------------------------------------------------------------------------- |
|
34 | #----------------------------------------------------------------------------- | |
24 | # Top-level handlers |
|
35 | # Top-level handlers | |
25 | #----------------------------------------------------------------------------- |
|
36 | #----------------------------------------------------------------------------- | |
26 |
|
37 | |||
27 |
|
38 | |||
28 | class NBBrowserHandler(web.RequestHandler): |
|
39 | class NBBrowserHandler(web.RequestHandler): | |
29 | def get(self): |
|
40 | def get(self): | |
30 | nbm = self.application.notebook_manager |
|
41 | nbm = self.application.notebook_manager | |
31 | project = nbm.notebook_dir |
|
42 | project = nbm.notebook_dir | |
32 | self.render('nbbrowser.html', project=project) |
|
43 | self.render('nbbrowser.html', project=project) | |
33 |
|
44 | |||
34 |
|
45 | |||
35 | class NewHandler(web.RequestHandler): |
|
46 | class NewHandler(web.RequestHandler): | |
36 | def get(self): |
|
47 | def get(self): | |
37 | notebook_id = self.application.notebook_manager.new_notebook() |
|
48 | notebook_id = self.application.notebook_manager.new_notebook() | |
38 | self.render('notebook.html', notebook_id=notebook_id) |
|
49 | self.render('notebook.html', notebook_id=notebook_id) | |
39 |
|
50 | |||
40 |
|
51 | |||
41 | class NamedNotebookHandler(web.RequestHandler): |
|
52 | class NamedNotebookHandler(web.RequestHandler): | |
42 | def get(self, notebook_id): |
|
53 | def get(self, notebook_id): | |
43 | nbm = self.application.notebook_manager |
|
54 | nbm = self.application.notebook_manager | |
44 | if not nbm.notebook_exists(notebook_id): |
|
55 | if not nbm.notebook_exists(notebook_id): | |
45 | raise web.HTTPError(404) |
|
56 | raise web.HTTPError(404) | |
46 | self.render('notebook.html', notebook_id=notebook_id) |
|
57 | self.render('notebook.html', notebook_id=notebook_id) | |
47 |
|
58 | |||
48 |
|
59 | |||
49 | #----------------------------------------------------------------------------- |
|
60 | #----------------------------------------------------------------------------- | |
50 | # Kernel handlers |
|
61 | # Kernel handlers | |
51 | #----------------------------------------------------------------------------- |
|
62 | #----------------------------------------------------------------------------- | |
52 |
|
63 | |||
53 |
|
64 | |||
54 | class MainKernelHandler(web.RequestHandler): |
|
65 | class MainKernelHandler(web.RequestHandler): | |
55 |
|
66 | |||
56 | def get(self): |
|
67 | def get(self): | |
57 | km = self.application.kernel_manager |
|
68 | km = self.application.kernel_manager | |
58 | self.finish(jsonapi.dumps(km.kernel_ids)) |
|
69 | self.finish(jsonapi.dumps(km.kernel_ids)) | |
59 |
|
70 | |||
60 | def post(self): |
|
71 | def post(self): | |
61 | km = self.application.kernel_manager |
|
72 | km = self.application.kernel_manager | |
62 | notebook_id = self.get_argument('notebook', default=None) |
|
73 | notebook_id = self.get_argument('notebook', default=None) | |
63 | kernel_id = km.start_kernel(notebook_id) |
|
74 | kernel_id = km.start_kernel(notebook_id) | |
64 | ws_url = self.application.ipython_app.get_ws_url() |
|
75 | ws_url = self.application.ipython_app.get_ws_url() | |
65 | data = {'ws_url':ws_url,'kernel_id':kernel_id} |
|
76 | data = {'ws_url':ws_url,'kernel_id':kernel_id} | |
66 | self.set_header('Location', '/'+kernel_id) |
|
77 | self.set_header('Location', '/'+kernel_id) | |
67 | self.finish(jsonapi.dumps(data)) |
|
78 | self.finish(jsonapi.dumps(data)) | |
68 |
|
79 | |||
69 |
|
80 | |||
70 | class KernelHandler(web.RequestHandler): |
|
81 | class KernelHandler(web.RequestHandler): | |
71 |
|
82 | |||
72 | SUPPORTED_METHODS = ('DELETE') |
|
83 | SUPPORTED_METHODS = ('DELETE') | |
73 |
|
84 | |||
74 | def delete(self, kernel_id): |
|
85 | def delete(self, kernel_id): | |
75 | km = self.application.kernel_manager |
|
86 | km = self.application.kernel_manager | |
76 | km.kill_kernel(kernel_id) |
|
87 | km.kill_kernel(kernel_id) | |
77 | self.set_status(204) |
|
88 | self.set_status(204) | |
78 | self.finish() |
|
89 | self.finish() | |
79 |
|
90 | |||
80 |
|
91 | |||
81 | class KernelActionHandler(web.RequestHandler): |
|
92 | class KernelActionHandler(web.RequestHandler): | |
82 |
|
93 | |||
83 | def post(self, kernel_id, action): |
|
94 | def post(self, kernel_id, action): | |
84 | km = self.application.kernel_manager |
|
95 | km = self.application.kernel_manager | |
85 | if action == 'interrupt': |
|
96 | if action == 'interrupt': | |
86 | km.interrupt_kernel(kernel_id) |
|
97 | km.interrupt_kernel(kernel_id) | |
87 | self.set_status(204) |
|
98 | self.set_status(204) | |
88 | if action == 'restart': |
|
99 | if action == 'restart': | |
89 | new_kernel_id = km.restart_kernel(kernel_id) |
|
100 | new_kernel_id = km.restart_kernel(kernel_id) | |
90 | ws_url = self.application.ipython_app.get_ws_url() |
|
101 | ws_url = self.application.ipython_app.get_ws_url() | |
91 | data = {'ws_url':ws_url,'kernel_id':new_kernel_id} |
|
102 | data = {'ws_url':ws_url,'kernel_id':new_kernel_id} | |
92 | self.set_header('Location', '/'+new_kernel_id) |
|
103 | self.set_header('Location', '/'+new_kernel_id) | |
93 | self.write(jsonapi.dumps(data)) |
|
104 | self.write(jsonapi.dumps(data)) | |
94 | self.finish() |
|
105 | self.finish() | |
95 |
|
106 | |||
96 |
|
107 | |||
97 | class ZMQStreamHandler(websocket.WebSocketHandler): |
|
108 | class ZMQStreamHandler(websocket.WebSocketHandler): | |
98 |
|
109 | |||
99 | def _reserialize_reply(self, msg_list): |
|
110 | def _reserialize_reply(self, msg_list): | |
100 | """Reserialize a reply message using JSON. |
|
111 | """Reserialize a reply message using JSON. | |
101 |
|
112 | |||
102 | This takes the msg list from the ZMQ socket, unserializes it using |
|
113 | This takes the msg list from the ZMQ socket, unserializes it using | |
103 | self.session and then serializes the result using JSON. This method |
|
114 | self.session and then serializes the result using JSON. This method | |
104 | should be used by self._on_zmq_reply to build messages that can |
|
115 | should be used by self._on_zmq_reply to build messages that can | |
105 | be sent back to the browser. |
|
116 | be sent back to the browser. | |
106 | """ |
|
117 | """ | |
107 | idents, msg_list = self.session.feed_identities(msg_list) |
|
118 | idents, msg_list = self.session.feed_identities(msg_list) | |
108 | msg = self.session.unserialize(msg_list) |
|
119 | msg = self.session.unserialize(msg_list) | |
109 | try: |
|
120 | try: | |
110 | msg['header'].pop('date') |
|
121 | msg['header'].pop('date') | |
111 | except KeyError: |
|
122 | except KeyError: | |
112 | pass |
|
123 | pass | |
113 | try: |
|
124 | try: | |
114 | msg['parent_header'].pop('date') |
|
125 | msg['parent_header'].pop('date') | |
115 | except KeyError: |
|
126 | except KeyError: | |
116 | pass |
|
127 | pass | |
117 | msg.pop('buffers') |
|
128 | msg.pop('buffers') | |
118 | return jsonapi.dumps(msg) |
|
129 | return jsonapi.dumps(msg) | |
119 |
|
130 | |||
120 | def _on_zmq_reply(self, msg_list): |
|
131 | def _on_zmq_reply(self, msg_list): | |
121 | try: |
|
132 | try: | |
122 | msg = self._reserialize_reply(msg_list) |
|
133 | msg = self._reserialize_reply(msg_list) | |
123 | except: |
|
134 | except: | |
124 | self.application.kernel_manager.log.critical("Malformed message: %r" % msg_list) |
|
135 | self.application.kernel_manager.log.critical("Malformed message: %r" % msg_list) | |
125 | else: |
|
136 | else: | |
126 | self.write_message(msg) |
|
137 | self.write_message(msg) | |
127 |
|
138 | |||
128 |
|
139 | |||
129 | class IOPubHandler(ZMQStreamHandler): |
|
140 | class IOPubHandler(ZMQStreamHandler): | |
130 |
|
141 | |||
131 | def initialize(self, *args, **kwargs): |
|
142 | def initialize(self, *args, **kwargs): | |
132 | self._kernel_alive = True |
|
143 | self._kernel_alive = True | |
133 | self._beating = False |
|
144 | self._beating = False | |
134 | self.iopub_stream = None |
|
145 | self.iopub_stream = None | |
135 | self.hb_stream = None |
|
146 | self.hb_stream = None | |
136 |
|
147 | |||
137 | def open(self, kernel_id): |
|
148 | def open(self, kernel_id): | |
138 | km = self.application.kernel_manager |
|
149 | km = self.application.kernel_manager | |
139 | self.kernel_id = kernel_id |
|
150 | self.kernel_id = kernel_id | |
140 | self.session = Session() |
|
151 | self.session = Session() | |
141 | self.time_to_dead = km.time_to_dead |
|
152 | self.time_to_dead = km.time_to_dead | |
142 | try: |
|
153 | try: | |
143 | self.iopub_stream = km.create_iopub_stream(kernel_id) |
|
154 | self.iopub_stream = km.create_iopub_stream(kernel_id) | |
144 | self.hb_stream = km.create_hb_stream(kernel_id) |
|
155 | self.hb_stream = km.create_hb_stream(kernel_id) | |
145 | except web.HTTPError: |
|
156 | except web.HTTPError: | |
146 | # WebSockets don't response to traditional error codes so we |
|
157 | # WebSockets don't response to traditional error codes so we | |
147 | # close the connection. |
|
158 | # close the connection. | |
148 | if not self.stream.closed(): |
|
159 | if not self.stream.closed(): | |
149 | self.stream.close() |
|
160 | self.stream.close() | |
150 | else: |
|
161 | else: | |
151 | self.iopub_stream.on_recv(self._on_zmq_reply) |
|
162 | self.iopub_stream.on_recv(self._on_zmq_reply) | |
152 | self.start_hb(self.kernel_died) |
|
163 | self.start_hb(self.kernel_died) | |
153 |
|
164 | |||
154 | def on_close(self): |
|
165 | def on_close(self): | |
155 | # This method can be called twice, once by self.kernel_died and once |
|
166 | # This method can be called twice, once by self.kernel_died and once | |
156 | # from the WebSocket close event. If the WebSocket connection is |
|
167 | # from the WebSocket close event. If the WebSocket connection is | |
157 | # closed before the ZMQ streams are setup, they could be None. |
|
168 | # closed before the ZMQ streams are setup, they could be None. | |
158 | self.stop_hb() |
|
169 | self.stop_hb() | |
159 | if self.iopub_stream is not None and not self.iopub_stream.closed(): |
|
170 | if self.iopub_stream is not None and not self.iopub_stream.closed(): | |
160 | self.iopub_stream.on_recv(None) |
|
171 | self.iopub_stream.on_recv(None) | |
161 | self.iopub_stream.close() |
|
172 | self.iopub_stream.close() | |
162 | if self.hb_stream is not None and not self.hb_stream.closed(): |
|
173 | if self.hb_stream is not None and not self.hb_stream.closed(): | |
163 | self.hb_stream.close() |
|
174 | self.hb_stream.close() | |
164 |
|
175 | |||
165 | def start_hb(self, callback): |
|
176 | def start_hb(self, callback): | |
166 | """Start the heartbeating and call the callback if the kernel dies.""" |
|
177 | """Start the heartbeating and call the callback if the kernel dies.""" | |
167 | if not self._beating: |
|
178 | if not self._beating: | |
168 | self._kernel_alive = True |
|
179 | self._kernel_alive = True | |
169 |
|
180 | |||
170 | def ping_or_dead(): |
|
181 | def ping_or_dead(): | |
171 | if self._kernel_alive: |
|
182 | if self._kernel_alive: | |
172 | self._kernel_alive = False |
|
183 | self._kernel_alive = False | |
173 | self.hb_stream.send(b'ping') |
|
184 | self.hb_stream.send(b'ping') | |
174 | else: |
|
185 | else: | |
175 | try: |
|
186 | try: | |
176 | callback() |
|
187 | callback() | |
177 | except: |
|
188 | except: | |
178 | pass |
|
189 | pass | |
179 | finally: |
|
190 | finally: | |
180 | self._hb_periodic_callback.stop() |
|
191 | self._hb_periodic_callback.stop() | |
181 |
|
192 | |||
182 | def beat_received(msg): |
|
193 | def beat_received(msg): | |
183 | self._kernel_alive = True |
|
194 | self._kernel_alive = True | |
184 |
|
195 | |||
185 | self.hb_stream.on_recv(beat_received) |
|
196 | self.hb_stream.on_recv(beat_received) | |
186 | self._hb_periodic_callback = ioloop.PeriodicCallback(ping_or_dead, self.time_to_dead*1000) |
|
197 | self._hb_periodic_callback = ioloop.PeriodicCallback(ping_or_dead, self.time_to_dead*1000) | |
187 | self._hb_periodic_callback.start() |
|
198 | self._hb_periodic_callback.start() | |
188 | self._beating= True |
|
199 | self._beating= True | |
189 |
|
200 | |||
190 | def stop_hb(self): |
|
201 | def stop_hb(self): | |
191 | """Stop the heartbeating and cancel all related callbacks.""" |
|
202 | """Stop the heartbeating and cancel all related callbacks.""" | |
192 | if self._beating: |
|
203 | if self._beating: | |
193 | self._hb_periodic_callback.stop() |
|
204 | self._hb_periodic_callback.stop() | |
194 | if not self.hb_stream.closed(): |
|
205 | if not self.hb_stream.closed(): | |
195 | self.hb_stream.on_recv(None) |
|
206 | self.hb_stream.on_recv(None) | |
196 |
|
207 | |||
197 | def kernel_died(self): |
|
208 | def kernel_died(self): | |
198 | self.application.kernel_manager.delete_mapping_for_kernel(self.kernel_id) |
|
209 | self.application.kernel_manager.delete_mapping_for_kernel(self.kernel_id) | |
199 | self.write_message( |
|
210 | self.write_message( | |
200 | {'header': {'msg_type': 'status'}, |
|
211 | {'header': {'msg_type': 'status'}, | |
201 | 'parent_header': {}, |
|
212 | 'parent_header': {}, | |
202 | 'content': {'execution_state':'dead'} |
|
213 | 'content': {'execution_state':'dead'} | |
203 | } |
|
214 | } | |
204 | ) |
|
215 | ) | |
205 | self.on_close() |
|
216 | self.on_close() | |
206 |
|
217 | |||
207 |
|
218 | |||
208 | class ShellHandler(ZMQStreamHandler): |
|
219 | class ShellHandler(ZMQStreamHandler): | |
209 |
|
220 | |||
210 | def initialize(self, *args, **kwargs): |
|
221 | def initialize(self, *args, **kwargs): | |
211 | self.shell_stream = None |
|
222 | self.shell_stream = None | |
212 |
|
223 | |||
213 | def open(self, kernel_id): |
|
224 | def open(self, kernel_id): | |
214 | km = self.application.kernel_manager |
|
225 | km = self.application.kernel_manager | |
215 | self.max_msg_size = km.max_msg_size |
|
226 | self.max_msg_size = km.max_msg_size | |
216 | self.kernel_id = kernel_id |
|
227 | self.kernel_id = kernel_id | |
217 | try: |
|
228 | try: | |
218 | self.shell_stream = km.create_shell_stream(kernel_id) |
|
229 | self.shell_stream = km.create_shell_stream(kernel_id) | |
219 | except web.HTTPError: |
|
230 | except web.HTTPError: | |
220 | # WebSockets don't response to traditional error codes so we |
|
231 | # WebSockets don't response to traditional error codes so we | |
221 | # close the connection. |
|
232 | # close the connection. | |
222 | if not self.stream.closed(): |
|
233 | if not self.stream.closed(): | |
223 | self.stream.close() |
|
234 | self.stream.close() | |
224 | else: |
|
235 | else: | |
225 | self.session = Session() |
|
236 | self.session = Session() | |
226 | self.shell_stream.on_recv(self._on_zmq_reply) |
|
237 | self.shell_stream.on_recv(self._on_zmq_reply) | |
227 |
|
238 | |||
228 | def on_message(self, msg): |
|
239 | def on_message(self, msg): | |
229 | if len(msg) < self.max_msg_size: |
|
240 | if len(msg) < self.max_msg_size: | |
230 | msg = jsonapi.loads(msg) |
|
241 | msg = jsonapi.loads(msg) | |
231 | self.session.send(self.shell_stream, msg) |
|
242 | self.session.send(self.shell_stream, msg) | |
232 |
|
243 | |||
233 | def on_close(self): |
|
244 | def on_close(self): | |
234 | # Make sure the stream exists and is not already closed. |
|
245 | # Make sure the stream exists and is not already closed. | |
235 | if self.shell_stream is not None and not self.shell_stream.closed(): |
|
246 | if self.shell_stream is not None and not self.shell_stream.closed(): | |
236 | self.shell_stream.close() |
|
247 | self.shell_stream.close() | |
237 |
|
248 | |||
238 |
|
249 | |||
239 | #----------------------------------------------------------------------------- |
|
250 | #----------------------------------------------------------------------------- | |
240 | # Notebook web service handlers |
|
251 | # Notebook web service handlers | |
241 | #----------------------------------------------------------------------------- |
|
252 | #----------------------------------------------------------------------------- | |
242 |
|
253 | |||
243 | class NotebookRootHandler(web.RequestHandler): |
|
254 | class NotebookRootHandler(web.RequestHandler): | |
244 |
|
255 | |||
245 | def get(self): |
|
256 | def get(self): | |
246 | nbm = self.application.notebook_manager |
|
257 | nbm = self.application.notebook_manager | |
247 | files = nbm.list_notebooks() |
|
258 | files = nbm.list_notebooks() | |
248 | self.finish(jsonapi.dumps(files)) |
|
259 | self.finish(jsonapi.dumps(files)) | |
249 |
|
260 | |||
250 | def post(self): |
|
261 | def post(self): | |
251 | nbm = self.application.notebook_manager |
|
262 | nbm = self.application.notebook_manager | |
252 | body = self.request.body.strip() |
|
263 | body = self.request.body.strip() | |
253 | format = self.get_argument('format', default='json') |
|
264 | format = self.get_argument('format', default='json') | |
254 | name = self.get_argument('name', default=None) |
|
265 | name = self.get_argument('name', default=None) | |
255 | if body: |
|
266 | if body: | |
256 | notebook_id = nbm.save_new_notebook(body, name=name, format=format) |
|
267 | notebook_id = nbm.save_new_notebook(body, name=name, format=format) | |
257 | else: |
|
268 | else: | |
258 | notebook_id = nbm.new_notebook() |
|
269 | notebook_id = nbm.new_notebook() | |
259 | self.set_header('Location', '/'+notebook_id) |
|
270 | self.set_header('Location', '/'+notebook_id) | |
260 | self.finish(jsonapi.dumps(notebook_id)) |
|
271 | self.finish(jsonapi.dumps(notebook_id)) | |
261 |
|
272 | |||
262 |
|
273 | |||
263 | class NotebookHandler(web.RequestHandler): |
|
274 | class NotebookHandler(web.RequestHandler): | |
264 |
|
275 | |||
265 | SUPPORTED_METHODS = ('GET', 'PUT', 'DELETE') |
|
276 | SUPPORTED_METHODS = ('GET', 'PUT', 'DELETE') | |
266 |
|
277 | |||
267 | def get(self, notebook_id): |
|
278 | def get(self, notebook_id): | |
268 | nbm = self.application.notebook_manager |
|
279 | nbm = self.application.notebook_manager | |
269 | format = self.get_argument('format', default='json') |
|
280 | format = self.get_argument('format', default='json') | |
270 | last_mod, name, data = nbm.get_notebook(notebook_id, format) |
|
281 | last_mod, name, data = nbm.get_notebook(notebook_id, format) | |
271 | if format == u'json': |
|
282 | if format == u'json': | |
272 | self.set_header('Content-Type', 'application/json') |
|
283 | self.set_header('Content-Type', 'application/json') | |
273 | self.set_header('Content-Disposition','attachment; filename="%s.json"' % name) |
|
284 | self.set_header('Content-Disposition','attachment; filename="%s.json"' % name) | |
274 | elif format == u'xml': |
|
285 | elif format == u'xml': | |
275 | self.set_header('Content-Type', 'application/xml') |
|
286 | self.set_header('Content-Type', 'application/xml') | |
276 | self.set_header('Content-Disposition','attachment; filename="%s.ipynb"' % name) |
|
287 | self.set_header('Content-Disposition','attachment; filename="%s.ipynb"' % name) | |
277 | elif format == u'py': |
|
288 | elif format == u'py': | |
278 | self.set_header('Content-Type', 'application/x-python') |
|
289 | self.set_header('Content-Type', 'application/x-python') | |
279 | self.set_header('Content-Disposition','attachment; filename="%s.py"' % name) |
|
290 | self.set_header('Content-Disposition','attachment; filename="%s.py"' % name) | |
280 | self.set_header('Last-Modified', last_mod) |
|
291 | self.set_header('Last-Modified', last_mod) | |
281 | self.finish(data) |
|
292 | self.finish(data) | |
282 |
|
293 | |||
283 | def put(self, notebook_id): |
|
294 | def put(self, notebook_id): | |
284 | nbm = self.application.notebook_manager |
|
295 | nbm = self.application.notebook_manager | |
285 | format = self.get_argument('format', default='json') |
|
296 | format = self.get_argument('format', default='json') | |
286 | name = self.get_argument('name', default=None) |
|
297 | name = self.get_argument('name', default=None) | |
287 | nbm.save_notebook(notebook_id, self.request.body, name=name, format=format) |
|
298 | nbm.save_notebook(notebook_id, self.request.body, name=name, format=format) | |
288 | self.set_status(204) |
|
299 | self.set_status(204) | |
289 | self.finish() |
|
300 | self.finish() | |
290 |
|
301 | |||
291 | def delete(self, notebook_id): |
|
302 | def delete(self, notebook_id): | |
292 | nbm = self.application.notebook_manager |
|
303 | nbm = self.application.notebook_manager | |
293 | nbm.delete_notebook(notebook_id) |
|
304 | nbm.delete_notebook(notebook_id) | |
294 | self.set_status(204) |
|
305 | self.set_status(204) | |
295 | self.finish() |
|
306 | self.finish() | |
296 |
|
307 | |||
297 | #----------------------------------------------------------------------------- |
|
308 | #----------------------------------------------------------------------------- | |
298 | # RST web service handlers |
|
309 | # RST web service handlers | |
299 | #----------------------------------------------------------------------------- |
|
310 | #----------------------------------------------------------------------------- | |
300 |
|
311 | |||
301 |
|
312 | |||
302 | class RSTHandler(web.RequestHandler): |
|
313 | class RSTHandler(web.RequestHandler): | |
303 |
|
314 | |||
304 | def post(self): |
|
315 | def post(self): | |
305 | if publish_string is None: |
|
316 | if publish_string is None: | |
306 | raise web.HTTPError(503) |
|
317 | raise web.HTTPError(503) | |
307 | body = self.request.body.strip() |
|
318 | body = self.request.body.strip() | |
308 | source = body |
|
319 | source = body | |
309 | # template_path=os.path.join(os.path.dirname(__file__), u'templates', u'rst_template.html') |
|
320 | # template_path=os.path.join(os.path.dirname(__file__), u'templates', u'rst_template.html') | |
310 | defaults = {'file_insertion_enabled': 0, |
|
321 | defaults = {'file_insertion_enabled': 0, | |
311 | 'raw_enabled': 0, |
|
322 | 'raw_enabled': 0, | |
312 | '_disable_config': 1, |
|
323 | '_disable_config': 1, | |
313 | 'stylesheet_path': 0 |
|
324 | 'stylesheet_path': 0 | |
314 | # 'template': template_path |
|
325 | # 'template': template_path | |
315 | } |
|
326 | } | |
316 | try: |
|
327 | try: | |
317 | html = publish_string(source, writer_name='html', |
|
328 | html = publish_string(source, writer_name='html', | |
318 | settings_overrides=defaults |
|
329 | settings_overrides=defaults | |
319 | ) |
|
330 | ) | |
320 | except: |
|
331 | except: | |
321 | raise web.HTTPError(400) |
|
332 | raise web.HTTPError(400) | |
322 | print html |
|
333 | print html | |
323 | self.set_header('Content-Type', 'text/html') |
|
334 | self.set_header('Content-Type', 'text/html') | |
324 | self.finish(html) |
|
335 | self.finish(html) | |
325 |
|
336 | |||
326 |
|
337 |
@@ -1,320 +1,325 b'' | |||||
1 |
"""A kernel manager for multiple kernels. |
|
1 | """A kernel manager for multiple kernels. | |
|
2 | ||||
|
3 | Authors: | |||
|
4 | ||||
|
5 | * Brian Granger | |||
|
6 | """ | |||
2 |
|
7 | |||
3 | #----------------------------------------------------------------------------- |
|
8 | #----------------------------------------------------------------------------- | |
4 | # Copyright (C) 2011 The IPython Development Team |
|
9 | # Copyright (C) 2008-2011 The IPython Development Team | |
5 | # |
|
10 | # | |
6 | # Distributed under the terms of the BSD License. The full license is in |
|
11 | # Distributed under the terms of the BSD License. The full license is in | |
7 |
# the file COPYING |
|
12 | # the file COPYING, distributed as part of this software. | |
8 | #----------------------------------------------------------------------------- |
|
13 | #----------------------------------------------------------------------------- | |
9 |
|
14 | |||
10 | #----------------------------------------------------------------------------- |
|
15 | #----------------------------------------------------------------------------- | |
11 | # Imports |
|
16 | # Imports | |
12 | #----------------------------------------------------------------------------- |
|
17 | #----------------------------------------------------------------------------- | |
13 |
|
18 | |||
14 | import signal |
|
19 | import signal | |
15 | import sys |
|
20 | import sys | |
16 | import uuid |
|
21 | import uuid | |
17 |
|
22 | |||
18 | import zmq |
|
23 | import zmq | |
19 | from zmq.eventloop.zmqstream import ZMQStream |
|
24 | from zmq.eventloop.zmqstream import ZMQStream | |
20 |
|
25 | |||
21 | from tornado import web |
|
26 | from tornado import web | |
22 |
|
27 | |||
23 | from IPython.config.configurable import LoggingConfigurable |
|
28 | from IPython.config.configurable import LoggingConfigurable | |
24 | from IPython.zmq.ipkernel import launch_kernel |
|
29 | from IPython.zmq.ipkernel import launch_kernel | |
25 | from IPython.utils.traitlets import Instance, Dict, List, Unicode, Float, Int |
|
30 | from IPython.utils.traitlets import Instance, Dict, List, Unicode, Float, Int | |
26 |
|
31 | |||
27 | #----------------------------------------------------------------------------- |
|
32 | #----------------------------------------------------------------------------- | |
28 | # Classes |
|
33 | # Classes | |
29 | #----------------------------------------------------------------------------- |
|
34 | #----------------------------------------------------------------------------- | |
30 |
|
35 | |||
31 | class DuplicateKernelError(Exception): |
|
36 | class DuplicateKernelError(Exception): | |
32 | pass |
|
37 | pass | |
33 |
|
38 | |||
34 |
|
39 | |||
35 | class KernelManager(LoggingConfigurable): |
|
40 | class KernelManager(LoggingConfigurable): | |
36 | """A class for managing multiple kernels.""" |
|
41 | """A class for managing multiple kernels.""" | |
37 |
|
42 | |||
38 | context = Instance('zmq.Context') |
|
43 | context = Instance('zmq.Context') | |
39 | def _context_default(self): |
|
44 | def _context_default(self): | |
40 | return zmq.Context.instance() |
|
45 | return zmq.Context.instance() | |
41 |
|
46 | |||
42 | _kernels = Dict() |
|
47 | _kernels = Dict() | |
43 |
|
48 | |||
44 | @property |
|
49 | @property | |
45 | def kernel_ids(self): |
|
50 | def kernel_ids(self): | |
46 | """Return a list of the kernel ids of the active kernels.""" |
|
51 | """Return a list of the kernel ids of the active kernels.""" | |
47 | return self._kernels.keys() |
|
52 | return self._kernels.keys() | |
48 |
|
53 | |||
49 | def __len__(self): |
|
54 | def __len__(self): | |
50 | """Return the number of running kernels.""" |
|
55 | """Return the number of running kernels.""" | |
51 | return len(self.kernel_ids) |
|
56 | return len(self.kernel_ids) | |
52 |
|
57 | |||
53 | def __contains__(self, kernel_id): |
|
58 | def __contains__(self, kernel_id): | |
54 | if kernel_id in self.kernel_ids: |
|
59 | if kernel_id in self.kernel_ids: | |
55 | return True |
|
60 | return True | |
56 | else: |
|
61 | else: | |
57 | return False |
|
62 | return False | |
58 |
|
63 | |||
59 | def start_kernel(self, **kwargs): |
|
64 | def start_kernel(self, **kwargs): | |
60 | """Start a new kernel.""" |
|
65 | """Start a new kernel.""" | |
61 | kernel_id = unicode(uuid.uuid4()) |
|
66 | kernel_id = unicode(uuid.uuid4()) | |
62 | (process, shell_port, iopub_port, stdin_port, hb_port) = launch_kernel(**kwargs) |
|
67 | (process, shell_port, iopub_port, stdin_port, hb_port) = launch_kernel(**kwargs) | |
63 | # Store the information for contacting the kernel. This assumes the kernel is |
|
68 | # Store the information for contacting the kernel. This assumes the kernel is | |
64 | # running on localhost. |
|
69 | # running on localhost. | |
65 | d = dict( |
|
70 | d = dict( | |
66 | process = process, |
|
71 | process = process, | |
67 | stdin_port = stdin_port, |
|
72 | stdin_port = stdin_port, | |
68 | iopub_port = iopub_port, |
|
73 | iopub_port = iopub_port, | |
69 | shell_port = shell_port, |
|
74 | shell_port = shell_port, | |
70 | hb_port = hb_port, |
|
75 | hb_port = hb_port, | |
71 | ip = '127.0.0.1' |
|
76 | ip = '127.0.0.1' | |
72 | ) |
|
77 | ) | |
73 | self._kernels[kernel_id] = d |
|
78 | self._kernels[kernel_id] = d | |
74 | return kernel_id |
|
79 | return kernel_id | |
75 |
|
80 | |||
76 | def kill_kernel(self, kernel_id): |
|
81 | def kill_kernel(self, kernel_id): | |
77 | """Kill a kernel by its kernel uuid. |
|
82 | """Kill a kernel by its kernel uuid. | |
78 |
|
83 | |||
79 | Parameters |
|
84 | Parameters | |
80 | ========== |
|
85 | ========== | |
81 | kernel_id : uuid |
|
86 | kernel_id : uuid | |
82 | The id of the kernel to kill. |
|
87 | The id of the kernel to kill. | |
83 | """ |
|
88 | """ | |
84 | kernel_process = self.get_kernel_process(kernel_id) |
|
89 | kernel_process = self.get_kernel_process(kernel_id) | |
85 | if kernel_process is not None: |
|
90 | if kernel_process is not None: | |
86 | # Attempt to kill the kernel. |
|
91 | # Attempt to kill the kernel. | |
87 | try: |
|
92 | try: | |
88 | kernel_process.kill() |
|
93 | kernel_process.kill() | |
89 | except OSError, e: |
|
94 | except OSError, e: | |
90 | # In Windows, we will get an Access Denied error if the process |
|
95 | # In Windows, we will get an Access Denied error if the process | |
91 | # has already terminated. Ignore it. |
|
96 | # has already terminated. Ignore it. | |
92 | if not (sys.platform == 'win32' and e.winerror == 5): |
|
97 | if not (sys.platform == 'win32' and e.winerror == 5): | |
93 | raise |
|
98 | raise | |
94 | del self._kernels[kernel_id] |
|
99 | del self._kernels[kernel_id] | |
95 |
|
100 | |||
96 | def interrupt_kernel(self, kernel_id): |
|
101 | def interrupt_kernel(self, kernel_id): | |
97 | """Interrupt (SIGINT) the kernel by its uuid. |
|
102 | """Interrupt (SIGINT) the kernel by its uuid. | |
98 |
|
103 | |||
99 | Parameters |
|
104 | Parameters | |
100 | ========== |
|
105 | ========== | |
101 | kernel_id : uuid |
|
106 | kernel_id : uuid | |
102 | The id of the kernel to interrupt. |
|
107 | The id of the kernel to interrupt. | |
103 | """ |
|
108 | """ | |
104 | kernel_process = self.get_kernel_process(kernel_id) |
|
109 | kernel_process = self.get_kernel_process(kernel_id) | |
105 | if kernel_process is not None: |
|
110 | if kernel_process is not None: | |
106 | if sys.platform == 'win32': |
|
111 | if sys.platform == 'win32': | |
107 | from parentpoller import ParentPollerWindows as Poller |
|
112 | from parentpoller import ParentPollerWindows as Poller | |
108 | Poller.send_interrupt(kernel_process.win32_interrupt_event) |
|
113 | Poller.send_interrupt(kernel_process.win32_interrupt_event) | |
109 | else: |
|
114 | else: | |
110 | kernel_process.send_signal(signal.SIGINT) |
|
115 | kernel_process.send_signal(signal.SIGINT) | |
111 |
|
116 | |||
112 |
|
117 | |||
113 | def signal_kernel(self, kernel_id, signum): |
|
118 | def signal_kernel(self, kernel_id, signum): | |
114 | """ Sends a signal to the kernel by its uuid. |
|
119 | """ Sends a signal to the kernel by its uuid. | |
115 |
|
120 | |||
116 | Note that since only SIGTERM is supported on Windows, this function |
|
121 | Note that since only SIGTERM is supported on Windows, this function | |
117 | is only useful on Unix systems. |
|
122 | is only useful on Unix systems. | |
118 |
|
123 | |||
119 | Parameters |
|
124 | Parameters | |
120 | ========== |
|
125 | ========== | |
121 | kernel_id : uuid |
|
126 | kernel_id : uuid | |
122 | The id of the kernel to signal. |
|
127 | The id of the kernel to signal. | |
123 | """ |
|
128 | """ | |
124 | kernel_process = self.get_kernel_process(kernel_id) |
|
129 | kernel_process = self.get_kernel_process(kernel_id) | |
125 | if kernel_process is not None: |
|
130 | if kernel_process is not None: | |
126 | kernel_process.send_signal(signum) |
|
131 | kernel_process.send_signal(signum) | |
127 |
|
132 | |||
128 | def get_kernel_process(self, kernel_id): |
|
133 | def get_kernel_process(self, kernel_id): | |
129 | """Get the process object for a kernel by its uuid. |
|
134 | """Get the process object for a kernel by its uuid. | |
130 |
|
135 | |||
131 | Parameters |
|
136 | Parameters | |
132 | ========== |
|
137 | ========== | |
133 | kernel_id : uuid |
|
138 | kernel_id : uuid | |
134 | The id of the kernel. |
|
139 | The id of the kernel. | |
135 | """ |
|
140 | """ | |
136 | d = self._kernels.get(kernel_id) |
|
141 | d = self._kernels.get(kernel_id) | |
137 | if d is not None: |
|
142 | if d is not None: | |
138 | return d['process'] |
|
143 | return d['process'] | |
139 | else: |
|
144 | else: | |
140 | raise KeyError("Kernel with id not found: %s" % kernel_id) |
|
145 | raise KeyError("Kernel with id not found: %s" % kernel_id) | |
141 |
|
146 | |||
142 | def get_kernel_ports(self, kernel_id): |
|
147 | def get_kernel_ports(self, kernel_id): | |
143 | """Return a dictionary of ports for a kernel. |
|
148 | """Return a dictionary of ports for a kernel. | |
144 |
|
149 | |||
145 | Parameters |
|
150 | Parameters | |
146 | ========== |
|
151 | ========== | |
147 | kernel_id : uuid |
|
152 | kernel_id : uuid | |
148 | The id of the kernel. |
|
153 | The id of the kernel. | |
149 |
|
154 | |||
150 | Returns |
|
155 | Returns | |
151 | ======= |
|
156 | ======= | |
152 | port_dict : dict |
|
157 | port_dict : dict | |
153 | A dict of key, value pairs where the keys are the names |
|
158 | A dict of key, value pairs where the keys are the names | |
154 | (stdin_port,iopub_port,shell_port) and the values are the |
|
159 | (stdin_port,iopub_port,shell_port) and the values are the | |
155 | integer port numbers for those channels. |
|
160 | integer port numbers for those channels. | |
156 | """ |
|
161 | """ | |
157 | d = self._kernels.get(kernel_id) |
|
162 | d = self._kernels.get(kernel_id) | |
158 | if d is not None: |
|
163 | if d is not None: | |
159 | dcopy = d.copy() |
|
164 | dcopy = d.copy() | |
160 | dcopy.pop('process') |
|
165 | dcopy.pop('process') | |
161 | dcopy.pop('ip') |
|
166 | dcopy.pop('ip') | |
162 | return dcopy |
|
167 | return dcopy | |
163 | else: |
|
168 | else: | |
164 | raise KeyError("Kernel with id not found: %s" % kernel_id) |
|
169 | raise KeyError("Kernel with id not found: %s" % kernel_id) | |
165 |
|
170 | |||
166 | def get_kernel_ip(self, kernel_id): |
|
171 | def get_kernel_ip(self, kernel_id): | |
167 | """Return ip address for a kernel. |
|
172 | """Return ip address for a kernel. | |
168 |
|
173 | |||
169 | Parameters |
|
174 | Parameters | |
170 | ========== |
|
175 | ========== | |
171 | kernel_id : uuid |
|
176 | kernel_id : uuid | |
172 | The id of the kernel. |
|
177 | The id of the kernel. | |
173 |
|
178 | |||
174 | Returns |
|
179 | Returns | |
175 | ======= |
|
180 | ======= | |
176 | ip : str |
|
181 | ip : str | |
177 | The ip address of the kernel. |
|
182 | The ip address of the kernel. | |
178 | """ |
|
183 | """ | |
179 | d = self._kernels.get(kernel_id) |
|
184 | d = self._kernels.get(kernel_id) | |
180 | if d is not None: |
|
185 | if d is not None: | |
181 | return d['ip'] |
|
186 | return d['ip'] | |
182 | else: |
|
187 | else: | |
183 | raise KeyError("Kernel with id not found: %s" % kernel_id) |
|
188 | raise KeyError("Kernel with id not found: %s" % kernel_id) | |
184 |
|
189 | |||
185 | def create_connected_stream(self, ip, port, socket_type): |
|
190 | def create_connected_stream(self, ip, port, socket_type): | |
186 | sock = self.context.socket(socket_type) |
|
191 | sock = self.context.socket(socket_type) | |
187 | addr = "tcp://%s:%i" % (ip, port) |
|
192 | addr = "tcp://%s:%i" % (ip, port) | |
188 | self.log.info("Connecting to: %s" % addr) |
|
193 | self.log.info("Connecting to: %s" % addr) | |
189 | sock.connect(addr) |
|
194 | sock.connect(addr) | |
190 | return ZMQStream(sock) |
|
195 | return ZMQStream(sock) | |
191 |
|
196 | |||
192 | def create_iopub_stream(self, kernel_id): |
|
197 | def create_iopub_stream(self, kernel_id): | |
193 | ip = self.get_kernel_ip(kernel_id) |
|
198 | ip = self.get_kernel_ip(kernel_id) | |
194 | ports = self.get_kernel_ports(kernel_id) |
|
199 | ports = self.get_kernel_ports(kernel_id) | |
195 | iopub_stream = self.create_connected_stream(ip, ports['iopub_port'], zmq.SUB) |
|
200 | iopub_stream = self.create_connected_stream(ip, ports['iopub_port'], zmq.SUB) | |
196 | iopub_stream.socket.setsockopt(zmq.SUBSCRIBE, b'') |
|
201 | iopub_stream.socket.setsockopt(zmq.SUBSCRIBE, b'') | |
197 | return iopub_stream |
|
202 | return iopub_stream | |
198 |
|
203 | |||
199 | def create_shell_stream(self, kernel_id): |
|
204 | def create_shell_stream(self, kernel_id): | |
200 | ip = self.get_kernel_ip(kernel_id) |
|
205 | ip = self.get_kernel_ip(kernel_id) | |
201 | ports = self.get_kernel_ports(kernel_id) |
|
206 | ports = self.get_kernel_ports(kernel_id) | |
202 | shell_stream = self.create_connected_stream(ip, ports['shell_port'], zmq.XREQ) |
|
207 | shell_stream = self.create_connected_stream(ip, ports['shell_port'], zmq.XREQ) | |
203 | return shell_stream |
|
208 | return shell_stream | |
204 |
|
209 | |||
205 | def create_hb_stream(self, kernel_id): |
|
210 | def create_hb_stream(self, kernel_id): | |
206 | ip = self.get_kernel_ip(kernel_id) |
|
211 | ip = self.get_kernel_ip(kernel_id) | |
207 | ports = self.get_kernel_ports(kernel_id) |
|
212 | ports = self.get_kernel_ports(kernel_id) | |
208 | hb_stream = self.create_connected_stream(ip, ports['hb_port'], zmq.REQ) |
|
213 | hb_stream = self.create_connected_stream(ip, ports['hb_port'], zmq.REQ) | |
209 | return hb_stream |
|
214 | return hb_stream | |
210 |
|
215 | |||
211 |
|
216 | |||
212 | class MappingKernelManager(KernelManager): |
|
217 | class MappingKernelManager(KernelManager): | |
213 | """A KernelManager that handles notebok mapping and HTTP error handling""" |
|
218 | """A KernelManager that handles notebok mapping and HTTP error handling""" | |
214 |
|
219 | |||
215 | kernel_argv = List(Unicode) |
|
220 | kernel_argv = List(Unicode) | |
216 | kernel_manager = Instance(KernelManager) |
|
221 | kernel_manager = Instance(KernelManager) | |
217 | time_to_dead = Float(3.0, config=True, help="""Kernel heartbeat interval in seconds.""") |
|
222 | time_to_dead = Float(3.0, config=True, help="""Kernel heartbeat interval in seconds.""") | |
218 | max_msg_size = Int(65536, config=True, help=""" |
|
223 | max_msg_size = Int(65536, config=True, help=""" | |
219 | The max raw message size accepted from the browser |
|
224 | The max raw message size accepted from the browser | |
220 | over a WebSocket connection. |
|
225 | over a WebSocket connection. | |
221 | """) |
|
226 | """) | |
222 |
|
227 | |||
223 | _notebook_mapping = Dict() |
|
228 | _notebook_mapping = Dict() | |
224 |
|
229 | |||
225 | #------------------------------------------------------------------------- |
|
230 | #------------------------------------------------------------------------- | |
226 | # Methods for managing kernels and sessions |
|
231 | # Methods for managing kernels and sessions | |
227 | #------------------------------------------------------------------------- |
|
232 | #------------------------------------------------------------------------- | |
228 |
|
233 | |||
229 | def kernel_for_notebook(self, notebook_id): |
|
234 | def kernel_for_notebook(self, notebook_id): | |
230 | """Return the kernel_id for a notebook_id or None.""" |
|
235 | """Return the kernel_id for a notebook_id or None.""" | |
231 | return self._notebook_mapping.get(notebook_id) |
|
236 | return self._notebook_mapping.get(notebook_id) | |
232 |
|
237 | |||
233 | def set_kernel_for_notebook(self, notebook_id, kernel_id): |
|
238 | def set_kernel_for_notebook(self, notebook_id, kernel_id): | |
234 | """Associate a notebook with a kernel.""" |
|
239 | """Associate a notebook with a kernel.""" | |
235 | if notebook_id is not None: |
|
240 | if notebook_id is not None: | |
236 | self._notebook_mapping[notebook_id] = kernel_id |
|
241 | self._notebook_mapping[notebook_id] = kernel_id | |
237 |
|
242 | |||
238 | def notebook_for_kernel(self, kernel_id): |
|
243 | def notebook_for_kernel(self, kernel_id): | |
239 | """Return the notebook_id for a kernel_id or None.""" |
|
244 | """Return the notebook_id for a kernel_id or None.""" | |
240 | notebook_ids = [k for k, v in self._notebook_mapping.iteritems() if v == kernel_id] |
|
245 | notebook_ids = [k for k, v in self._notebook_mapping.iteritems() if v == kernel_id] | |
241 | if len(notebook_ids) == 1: |
|
246 | if len(notebook_ids) == 1: | |
242 | return notebook_ids[0] |
|
247 | return notebook_ids[0] | |
243 | else: |
|
248 | else: | |
244 | return None |
|
249 | return None | |
245 |
|
250 | |||
246 | def delete_mapping_for_kernel(self, kernel_id): |
|
251 | def delete_mapping_for_kernel(self, kernel_id): | |
247 | """Remove the kernel/notebook mapping for kernel_id.""" |
|
252 | """Remove the kernel/notebook mapping for kernel_id.""" | |
248 | notebook_id = self.notebook_for_kernel(kernel_id) |
|
253 | notebook_id = self.notebook_for_kernel(kernel_id) | |
249 | if notebook_id is not None: |
|
254 | if notebook_id is not None: | |
250 | del self._notebook_mapping[notebook_id] |
|
255 | del self._notebook_mapping[notebook_id] | |
251 |
|
256 | |||
252 | def start_kernel(self, notebook_id=None): |
|
257 | def start_kernel(self, notebook_id=None): | |
253 | """Start a kernel for a notebok an return its kernel_id. |
|
258 | """Start a kernel for a notebok an return its kernel_id. | |
254 |
|
259 | |||
255 | Parameters |
|
260 | Parameters | |
256 | ---------- |
|
261 | ---------- | |
257 | notebook_id : uuid |
|
262 | notebook_id : uuid | |
258 | The uuid of the notebook to associate the new kernel with. If this |
|
263 | The uuid of the notebook to associate the new kernel with. If this | |
259 | is not None, this kernel will be persistent whenever the notebook |
|
264 | is not None, this kernel will be persistent whenever the notebook | |
260 | requests a kernel. |
|
265 | requests a kernel. | |
261 | """ |
|
266 | """ | |
262 | kernel_id = self.kernel_for_notebook(notebook_id) |
|
267 | kernel_id = self.kernel_for_notebook(notebook_id) | |
263 | if kernel_id is None: |
|
268 | if kernel_id is None: | |
264 | kwargs = dict() |
|
269 | kwargs = dict() | |
265 | kwargs['extra_arguments'] = self.kernel_argv |
|
270 | kwargs['extra_arguments'] = self.kernel_argv | |
266 | kernel_id = super(MappingKernelManager, self).start_kernel(**kwargs) |
|
271 | kernel_id = super(MappingKernelManager, self).start_kernel(**kwargs) | |
267 | self.set_kernel_for_notebook(notebook_id, kernel_id) |
|
272 | self.set_kernel_for_notebook(notebook_id, kernel_id) | |
268 | self.log.info("Kernel started: %s" % kernel_id) |
|
273 | self.log.info("Kernel started: %s" % kernel_id) | |
269 | self.log.debug("Kernel args: %r" % kwargs) |
|
274 | self.log.debug("Kernel args: %r" % kwargs) | |
270 | else: |
|
275 | else: | |
271 | self.log.info("Using existing kernel: %s" % kernel_id) |
|
276 | self.log.info("Using existing kernel: %s" % kernel_id) | |
272 | return kernel_id |
|
277 | return kernel_id | |
273 |
|
278 | |||
274 | def kill_kernel(self, kernel_id): |
|
279 | def kill_kernel(self, kernel_id): | |
275 | """Kill a kernel and remove its notebook association.""" |
|
280 | """Kill a kernel and remove its notebook association.""" | |
276 | if kernel_id not in self: |
|
281 | if kernel_id not in self: | |
277 | raise web.HTTPError(404) |
|
282 | raise web.HTTPError(404) | |
278 | super(MappingKernelManager, self).kill_kernel(kernel_id) |
|
283 | super(MappingKernelManager, self).kill_kernel(kernel_id) | |
279 | self.delete_mapping_for_kernel(kernel_id) |
|
284 | self.delete_mapping_for_kernel(kernel_id) | |
280 | self.log.info("Kernel killed: %s" % kernel_id) |
|
285 | self.log.info("Kernel killed: %s" % kernel_id) | |
281 |
|
286 | |||
282 | def interrupt_kernel(self, kernel_id): |
|
287 | def interrupt_kernel(self, kernel_id): | |
283 | """Interrupt a kernel.""" |
|
288 | """Interrupt a kernel.""" | |
284 | if kernel_id not in self: |
|
289 | if kernel_id not in self: | |
285 | raise web.HTTPError(404) |
|
290 | raise web.HTTPError(404) | |
286 | super(MappingKernelManager, self).interrupt_kernel(kernel_id) |
|
291 | super(MappingKernelManager, self).interrupt_kernel(kernel_id) | |
287 | self.log.info("Kernel interrupted: %s" % kernel_id) |
|
292 | self.log.info("Kernel interrupted: %s" % kernel_id) | |
288 |
|
293 | |||
289 | def restart_kernel(self, kernel_id): |
|
294 | def restart_kernel(self, kernel_id): | |
290 | """Restart a kernel while keeping clients connected.""" |
|
295 | """Restart a kernel while keeping clients connected.""" | |
291 | if kernel_id not in self: |
|
296 | if kernel_id not in self: | |
292 | raise web.HTTPError(404) |
|
297 | raise web.HTTPError(404) | |
293 |
|
298 | |||
294 | # Get the notebook_id to preserve the kernel/notebook association. |
|
299 | # Get the notebook_id to preserve the kernel/notebook association. | |
295 | notebook_id = self.notebook_for_kernel(kernel_id) |
|
300 | notebook_id = self.notebook_for_kernel(kernel_id) | |
296 | # Create the new kernel first so we can move the clients over. |
|
301 | # Create the new kernel first so we can move the clients over. | |
297 | new_kernel_id = self.start_kernel() |
|
302 | new_kernel_id = self.start_kernel() | |
298 | # Now kill the old kernel. |
|
303 | # Now kill the old kernel. | |
299 | self.kill_kernel(kernel_id) |
|
304 | self.kill_kernel(kernel_id) | |
300 | # Now save the new kernel/notebook association. We have to save it |
|
305 | # Now save the new kernel/notebook association. We have to save it | |
301 | # after the old kernel is killed as that will delete the mapping. |
|
306 | # after the old kernel is killed as that will delete the mapping. | |
302 | self.set_kernel_for_notebook(notebook_id, new_kernel_id) |
|
307 | self.set_kernel_for_notebook(notebook_id, new_kernel_id) | |
303 | self.log.info("Kernel restarted: %s" % new_kernel_id) |
|
308 | self.log.info("Kernel restarted: %s" % new_kernel_id) | |
304 | return new_kernel_id |
|
309 | return new_kernel_id | |
305 |
|
310 | |||
306 | def create_iopub_stream(self, kernel_id): |
|
311 | def create_iopub_stream(self, kernel_id): | |
307 | if kernel_id not in self: |
|
312 | if kernel_id not in self: | |
308 | raise web.HTTPError(404) |
|
313 | raise web.HTTPError(404) | |
309 | return super(MappingKernelManager, self).create_iopub_stream(kernel_id) |
|
314 | return super(MappingKernelManager, self).create_iopub_stream(kernel_id) | |
310 |
|
315 | |||
311 | def create_shell_stream(self, kernel_id): |
|
316 | def create_shell_stream(self, kernel_id): | |
312 | if kernel_id not in self: |
|
317 | if kernel_id not in self: | |
313 | raise web.HTTPError(404) |
|
318 | raise web.HTTPError(404) | |
314 | return super(MappingKernelManager, self).create_shell_stream(kernel_id) |
|
319 | return super(MappingKernelManager, self).create_shell_stream(kernel_id) | |
315 |
|
320 | |||
316 | def create_hb_stream(self, kernel_id): |
|
321 | def create_hb_stream(self, kernel_id): | |
317 | if kernel_id not in self: |
|
322 | if kernel_id not in self: | |
318 | raise web.HTTPError(404) |
|
323 | raise web.HTTPError(404) | |
319 | return super(MappingKernelManager, self).create_hb_stream(kernel_id) |
|
324 | return super(MappingKernelManager, self).create_hb_stream(kernel_id) | |
320 |
|
325 |
@@ -1,270 +1,276 b'' | |||||
1 |
"""A tornado based IPython notebook server. |
|
1 | """A tornado based IPython notebook server. | |
|
2 | ||||
|
3 | Authors: | |||
|
4 | ||||
|
5 | * Brian Granger | |||
|
6 | """ | |||
2 |
|
7 | |||
3 | #----------------------------------------------------------------------------- |
|
8 | #----------------------------------------------------------------------------- | |
4 | # Copyright (C) 2011 The IPython Development Team |
|
9 | # Copyright (C) 2008-2011 The IPython Development Team | |
5 | # |
|
10 | # | |
6 | # Distributed under the terms of the BSD License. The full license is in |
|
11 | # Distributed under the terms of the BSD License. The full license is in | |
7 |
# the file COPYING |
|
12 | # the file COPYING, distributed as part of this software. | |
8 | #----------------------------------------------------------------------------- |
|
13 | #----------------------------------------------------------------------------- | |
9 |
|
14 | |||
10 | #----------------------------------------------------------------------------- |
|
15 | #----------------------------------------------------------------------------- | |
11 | # Imports |
|
16 | # Imports | |
12 | #----------------------------------------------------------------------------- |
|
17 | #----------------------------------------------------------------------------- | |
13 |
|
18 | |||
14 | import errno |
|
19 | import errno | |
15 | import logging |
|
20 | import logging | |
16 | import os |
|
21 | import os | |
17 | import signal |
|
22 | import signal | |
18 | import socket |
|
23 | import socket | |
19 | import sys |
|
24 | import sys | |
20 |
|
25 | |||
21 | import zmq |
|
26 | import zmq | |
22 |
|
27 | |||
23 | # Install the pyzmq ioloop. This has to be done before anything else from |
|
28 | # Install the pyzmq ioloop. This has to be done before anything else from | |
24 | # tornado is imported. |
|
29 | # tornado is imported. | |
25 | from zmq.eventloop import ioloop |
|
30 | from zmq.eventloop import ioloop | |
26 | import tornado.ioloop |
|
31 | import tornado.ioloop | |
27 | tornado.ioloop = ioloop |
|
32 | tornado.ioloop = ioloop | |
28 |
|
33 | |||
29 | from tornado import httpserver |
|
34 | from tornado import httpserver | |
30 | from tornado import web |
|
35 | from tornado import web | |
31 |
|
36 | |||
32 | from .kernelmanager import MappingKernelManager |
|
37 | from .kernelmanager import MappingKernelManager | |
33 | from .handlers import ( |
|
38 | from .handlers import ( | |
34 | NBBrowserHandler, NewHandler, NamedNotebookHandler, |
|
39 | NBBrowserHandler, NewHandler, NamedNotebookHandler, | |
35 | MainKernelHandler, KernelHandler, KernelActionHandler, IOPubHandler, |
|
40 | MainKernelHandler, KernelHandler, KernelActionHandler, IOPubHandler, | |
36 | ShellHandler, NotebookRootHandler, NotebookHandler, RSTHandler |
|
41 | ShellHandler, NotebookRootHandler, NotebookHandler, RSTHandler | |
37 | ) |
|
42 | ) | |
38 | from .notebookmanager import NotebookManager |
|
43 | from .notebookmanager import NotebookManager | |
39 |
|
44 | |||
40 | from IPython.core.application import BaseIPythonApplication |
|
45 | from IPython.core.application import BaseIPythonApplication | |
41 | from IPython.core.profiledir import ProfileDir |
|
46 | from IPython.core.profiledir import ProfileDir | |
42 | from IPython.zmq.session import Session |
|
47 | from IPython.zmq.session import Session | |
43 | from IPython.zmq.zmqshell import ZMQInteractiveShell |
|
48 | from IPython.zmq.zmqshell import ZMQInteractiveShell | |
44 | from IPython.zmq.ipkernel import ( |
|
49 | from IPython.zmq.ipkernel import ( | |
45 | flags as ipkernel_flags, |
|
50 | flags as ipkernel_flags, | |
46 | aliases as ipkernel_aliases, |
|
51 | aliases as ipkernel_aliases, | |
47 | IPKernelApp |
|
52 | IPKernelApp | |
48 | ) |
|
53 | ) | |
49 | from IPython.utils.traitlets import Dict, Unicode, Int, List, Enum |
|
54 | from IPython.utils.traitlets import Dict, Unicode, Int, List, Enum | |
50 |
|
55 | |||
51 | #----------------------------------------------------------------------------- |
|
56 | #----------------------------------------------------------------------------- | |
52 | # Module globals |
|
57 | # Module globals | |
53 | #----------------------------------------------------------------------------- |
|
58 | #----------------------------------------------------------------------------- | |
54 |
|
59 | |||
55 | _kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)" |
|
60 | _kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)" | |
56 | _kernel_action_regex = r"(?P<action>restart|interrupt)" |
|
61 | _kernel_action_regex = r"(?P<action>restart|interrupt)" | |
57 | _notebook_id_regex = r"(?P<notebook_id>\w+-\w+-\w+-\w+-\w+)" |
|
62 | _notebook_id_regex = r"(?P<notebook_id>\w+-\w+-\w+-\w+-\w+)" | |
58 |
|
63 | |||
59 | LOCALHOST = '127.0.0.1' |
|
64 | LOCALHOST = '127.0.0.1' | |
60 |
|
65 | |||
61 | _examples = """ |
|
66 | _examples = """ | |
62 | ipython notebook # start the notebook |
|
67 | ipython notebook # start the notebook | |
63 | ipython notebook --profile=sympy # use the sympy profile |
|
68 | ipython notebook --profile=sympy # use the sympy profile | |
64 | ipython notebook --pylab=inline # pylab in inline plotting mode |
|
69 | ipython notebook --pylab=inline # pylab in inline plotting mode | |
65 | ipython notebook --certfile=mycert.pem # use SSL/TLS certificate |
|
70 | ipython notebook --certfile=mycert.pem # use SSL/TLS certificate | |
66 | ipython notebook --port=5555 --ip=* # Listen on port 5555, all interfaces |
|
71 | ipython notebook --port=5555 --ip=* # Listen on port 5555, all interfaces | |
67 | """ |
|
72 | """ | |
68 |
|
73 | |||
69 | #----------------------------------------------------------------------------- |
|
74 | #----------------------------------------------------------------------------- | |
70 | # The Tornado web application |
|
75 | # The Tornado web application | |
71 | #----------------------------------------------------------------------------- |
|
76 | #----------------------------------------------------------------------------- | |
72 |
|
77 | |||
73 | class NotebookWebApplication(web.Application): |
|
78 | class NotebookWebApplication(web.Application): | |
74 |
|
79 | |||
75 | def __init__(self, ipython_app, kernel_manager, notebook_manager, log): |
|
80 | def __init__(self, ipython_app, kernel_manager, notebook_manager, log): | |
76 | handlers = [ |
|
81 | handlers = [ | |
77 | (r"/", NBBrowserHandler), |
|
82 | (r"/", NBBrowserHandler), | |
78 | (r"/new", NewHandler), |
|
83 | (r"/new", NewHandler), | |
79 | (r"/%s" % _notebook_id_regex, NamedNotebookHandler), |
|
84 | (r"/%s" % _notebook_id_regex, NamedNotebookHandler), | |
80 | (r"/kernels", MainKernelHandler), |
|
85 | (r"/kernels", MainKernelHandler), | |
81 | (r"/kernels/%s" % _kernel_id_regex, KernelHandler), |
|
86 | (r"/kernels/%s" % _kernel_id_regex, KernelHandler), | |
82 | (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler), |
|
87 | (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler), | |
83 | (r"/kernels/%s/iopub" % _kernel_id_regex, IOPubHandler), |
|
88 | (r"/kernels/%s/iopub" % _kernel_id_regex, IOPubHandler), | |
84 | (r"/kernels/%s/shell" % _kernel_id_regex, ShellHandler), |
|
89 | (r"/kernels/%s/shell" % _kernel_id_regex, ShellHandler), | |
85 | (r"/notebooks", NotebookRootHandler), |
|
90 | (r"/notebooks", NotebookRootHandler), | |
86 | (r"/notebooks/%s" % _notebook_id_regex, NotebookHandler), |
|
91 | (r"/notebooks/%s" % _notebook_id_regex, NotebookHandler), | |
87 | (r"/rstservice/render", RSTHandler) |
|
92 | (r"/rstservice/render", RSTHandler) | |
88 | ] |
|
93 | ] | |
89 | settings = dict( |
|
94 | settings = dict( | |
90 | template_path=os.path.join(os.path.dirname(__file__), "templates"), |
|
95 | template_path=os.path.join(os.path.dirname(__file__), "templates"), | |
91 | static_path=os.path.join(os.path.dirname(__file__), "static"), |
|
96 | static_path=os.path.join(os.path.dirname(__file__), "static"), | |
92 | ) |
|
97 | ) | |
93 | web.Application.__init__(self, handlers, **settings) |
|
98 | web.Application.__init__(self, handlers, **settings) | |
94 |
|
99 | |||
95 | self.kernel_manager = kernel_manager |
|
100 | self.kernel_manager = kernel_manager | |
96 | self.log = log |
|
101 | self.log = log | |
97 | self.notebook_manager = notebook_manager |
|
102 | self.notebook_manager = notebook_manager | |
98 | self.ipython_app = ipython_app |
|
103 | self.ipython_app = ipython_app | |
99 |
|
104 | |||
100 |
|
105 | |||
101 | #----------------------------------------------------------------------------- |
|
106 | #----------------------------------------------------------------------------- | |
102 | # Aliases and Flags |
|
107 | # Aliases and Flags | |
103 | #----------------------------------------------------------------------------- |
|
108 | #----------------------------------------------------------------------------- | |
104 |
|
109 | |||
105 | flags = dict(ipkernel_flags) |
|
110 | flags = dict(ipkernel_flags) | |
106 |
|
111 | |||
107 | # the flags that are specific to the frontend |
|
112 | # the flags that are specific to the frontend | |
108 | # these must be scrubbed before being passed to the kernel, |
|
113 | # these must be scrubbed before being passed to the kernel, | |
109 | # or it will raise an error on unrecognized flags |
|
114 | # or it will raise an error on unrecognized flags | |
110 | notebook_flags = [] |
|
115 | notebook_flags = [] | |
111 |
|
116 | |||
112 | aliases = dict(ipkernel_aliases) |
|
117 | aliases = dict(ipkernel_aliases) | |
113 |
|
118 | |||
114 | aliases.update({ |
|
119 | aliases.update({ | |
115 | 'ip': 'IPythonNotebookApp.ip', |
|
120 | 'ip': 'IPythonNotebookApp.ip', | |
116 | 'port': 'IPythonNotebookApp.port', |
|
121 | 'port': 'IPythonNotebookApp.port', | |
117 | 'keyfile': 'IPythonNotebookApp.keyfile', |
|
122 | 'keyfile': 'IPythonNotebookApp.keyfile', | |
118 | 'certfile': 'IPythonNotebookApp.certfile', |
|
123 | 'certfile': 'IPythonNotebookApp.certfile', | |
119 | 'ws-hostname': 'IPythonNotebookApp.ws_hostname', |
|
124 | 'ws-hostname': 'IPythonNotebookApp.ws_hostname', | |
120 | 'notebook-dir': 'NotebookManager.notebook_dir' |
|
125 | 'notebook-dir': 'NotebookManager.notebook_dir' | |
121 | }) |
|
126 | }) | |
122 |
|
127 | |||
123 | notebook_aliases = [u'port', u'ip', u'keyfile', u'certfile', u'ws-hostname', |
|
128 | notebook_aliases = [u'port', u'ip', u'keyfile', u'certfile', u'ws-hostname', | |
124 | u'notebook-dir'] |
|
129 | u'notebook-dir'] | |
125 |
|
130 | |||
126 | #----------------------------------------------------------------------------- |
|
131 | #----------------------------------------------------------------------------- | |
127 | # IPythonNotebookApp |
|
132 | # IPythonNotebookApp | |
128 | #----------------------------------------------------------------------------- |
|
133 | #----------------------------------------------------------------------------- | |
129 |
|
134 | |||
130 | class IPythonNotebookApp(BaseIPythonApplication): |
|
135 | class IPythonNotebookApp(BaseIPythonApplication): | |
131 |
|
136 | |||
132 | name = 'ipython-notebook' |
|
137 | name = 'ipython-notebook' | |
133 | default_config_file_name='ipython_notebook_config.py' |
|
138 | default_config_file_name='ipython_notebook_config.py' | |
134 |
|
139 | |||
135 | description = """ |
|
140 | description = """ | |
136 | The IPython HTML Notebook. |
|
141 | The IPython HTML Notebook. | |
137 |
|
142 | |||
138 | This launches a Tornado based HTML Notebook Server that serves up an |
|
143 | This launches a Tornado based HTML Notebook Server that serves up an | |
139 | HTML5/Javascript Notebook client. |
|
144 | HTML5/Javascript Notebook client. | |
140 | """ |
|
145 | """ | |
141 | examples = _examples |
|
146 | examples = _examples | |
142 |
|
147 | |||
143 | classes = [IPKernelApp, ZMQInteractiveShell, ProfileDir, Session, |
|
148 | classes = [IPKernelApp, ZMQInteractiveShell, ProfileDir, Session, | |
144 | MappingKernelManager, NotebookManager] |
|
149 | MappingKernelManager, NotebookManager] | |
145 | flags = Dict(flags) |
|
150 | flags = Dict(flags) | |
146 | aliases = Dict(aliases) |
|
151 | aliases = Dict(aliases) | |
147 |
|
152 | |||
148 | kernel_argv = List(Unicode) |
|
153 | kernel_argv = List(Unicode) | |
149 |
|
154 | |||
150 | log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'), |
|
155 | log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'), | |
151 | default_value=logging.INFO, |
|
156 | default_value=logging.INFO, | |
152 | config=True, |
|
157 | config=True, | |
153 | help="Set the log level by value or name.") |
|
158 | help="Set the log level by value or name.") | |
154 |
|
159 | |||
155 | # Network related information. |
|
160 | # Network related information. | |
156 |
|
161 | |||
157 | ip = Unicode(LOCALHOST, config=True, |
|
162 | ip = Unicode(LOCALHOST, config=True, | |
158 | help="The IP address the notebook server will listen on." |
|
163 | help="The IP address the notebook server will listen on." | |
159 | ) |
|
164 | ) | |
160 |
|
165 | |||
161 | def _ip_changed(self, name, old, new): |
|
166 | def _ip_changed(self, name, old, new): | |
162 | if new == u'*': self.ip = u'' |
|
167 | if new == u'*': self.ip = u'' | |
163 |
|
168 | |||
164 | port = Int(8888, config=True, |
|
169 | port = Int(8888, config=True, | |
165 | help="The port the notebook server will listen on." |
|
170 | help="The port the notebook server will listen on." | |
166 | ) |
|
171 | ) | |
167 |
|
172 | |||
168 | ws_hostname = Unicode(LOCALHOST, config=True, |
|
173 | ws_hostname = Unicode(LOCALHOST, config=True, | |
169 | help="""The FQDN or IP for WebSocket connections. The default will work |
|
174 | help="""The FQDN or IP for WebSocket connections. The default will work | |
170 | fine when the server is listening on localhost, but this needs to |
|
175 | fine when the server is listening on localhost, but this needs to | |
171 | be set if the ip option is used. It will be used as the hostname part |
|
176 | be set if the ip option is used. It will be used as the hostname part | |
172 | of the WebSocket url: ws://hostname/path.""" |
|
177 | of the WebSocket url: ws://hostname/path.""" | |
173 | ) |
|
178 | ) | |
174 |
|
179 | |||
175 | certfile = Unicode(u'', config=True, |
|
180 | certfile = Unicode(u'', config=True, | |
176 | help="""The full path to an SSL/TLS certificate file.""" |
|
181 | help="""The full path to an SSL/TLS certificate file.""" | |
177 | ) |
|
182 | ) | |
178 |
|
183 | |||
179 | keyfile = Unicode(u'', config=True, |
|
184 | keyfile = Unicode(u'', config=True, | |
180 | help="""The full path to a private key file for usage with SSL/TLS.""" |
|
185 | help="""The full path to a private key file for usage with SSL/TLS.""" | |
181 | ) |
|
186 | ) | |
182 |
|
187 | |||
183 | def get_ws_url(self): |
|
188 | def get_ws_url(self): | |
184 | """Return the WebSocket URL for this server.""" |
|
189 | """Return the WebSocket URL for this server.""" | |
185 | if self.certfile: |
|
190 | if self.certfile: | |
186 | prefix = u'wss://' |
|
191 | prefix = u'wss://' | |
187 | else: |
|
192 | else: | |
188 | prefix = u'ws://' |
|
193 | prefix = u'ws://' | |
189 | return prefix + self.ws_hostname + u':' + unicode(self.port) |
|
194 | return prefix + self.ws_hostname + u':' + unicode(self.port) | |
190 |
|
195 | |||
191 | def parse_command_line(self, argv=None): |
|
196 | def parse_command_line(self, argv=None): | |
192 | super(IPythonNotebookApp, self).parse_command_line(argv) |
|
197 | super(IPythonNotebookApp, self).parse_command_line(argv) | |
193 | if argv is None: |
|
198 | if argv is None: | |
194 | argv = sys.argv[1:] |
|
199 | argv = sys.argv[1:] | |
195 |
|
200 | |||
196 | self.kernel_argv = list(argv) # copy |
|
201 | self.kernel_argv = list(argv) # copy | |
197 |
# |
|
202 | # Kernel should inherit default config file from frontend | |
198 | self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name) |
|
203 | self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name) | |
199 |
# |
|
204 | # Scrub frontend-specific flags | |
200 | for a in argv: |
|
205 | for a in argv: | |
201 | if a.startswith('-') and a.lstrip('-') in notebook_flags: |
|
206 | if a.startswith('-') and a.lstrip('-') in notebook_flags: | |
202 | self.kernel_argv.remove(a) |
|
207 | self.kernel_argv.remove(a) | |
203 | for a in argv: |
|
208 | for a in argv: | |
204 | if a.startswith('-'): |
|
209 | if a.startswith('-'): | |
205 | alias = a.lstrip('-').split('=')[0] |
|
210 | alias = a.lstrip('-').split('=')[0] | |
206 | if alias in notebook_aliases: |
|
211 | if alias in notebook_aliases: | |
207 | self.kernel_argv.remove(a) |
|
212 | self.kernel_argv.remove(a) | |
208 | print self.kernel_argv |
|
|||
209 |
|
213 | |||
210 | def init_configurables(self): |
|
214 | def init_configurables(self): | |
211 | # Don't let Qt or ZMQ swallow KeyboardInterupts. |
|
215 | # Don't let Qt or ZMQ swallow KeyboardInterupts. | |
212 | signal.signal(signal.SIGINT, signal.SIG_DFL) |
|
216 | signal.signal(signal.SIGINT, signal.SIG_DFL) | |
213 |
|
217 | |||
214 | # Create a KernelManager and start a kernel. |
|
218 | # Create a KernelManager and start a kernel. | |
215 | self.kernel_manager = MappingKernelManager( |
|
219 | self.kernel_manager = MappingKernelManager( | |
216 | config=self.config, log=self.log, kernel_argv=self.kernel_argv |
|
220 | config=self.config, log=self.log, kernel_argv=self.kernel_argv | |
217 | ) |
|
221 | ) | |
218 | self.notebook_manager = NotebookManager(config=self.config, log=self.log) |
|
222 | self.notebook_manager = NotebookManager(config=self.config, log=self.log) | |
219 |
|
223 | |||
220 | def init_logging(self): |
|
224 | def init_logging(self): | |
221 | super(IPythonNotebookApp, self).init_logging() |
|
225 | super(IPythonNotebookApp, self).init_logging() | |
222 | # This prevents double log messages because tornado use a root logger that |
|
226 | # This prevents double log messages because tornado use a root logger that | |
223 | # self.log is a child of. The logging module dipatches log messages to a log |
|
227 | # self.log is a child of. The logging module dipatches log messages to a log | |
224 | # and all of its ancenstors until propagate is set to False. |
|
228 | # and all of its ancenstors until propagate is set to False. | |
225 | self.log.propagate = False |
|
229 | self.log.propagate = False | |
226 |
|
230 | |||
227 | def initialize(self, argv=None): |
|
231 | def initialize(self, argv=None): | |
228 | super(IPythonNotebookApp, self).initialize(argv) |
|
232 | super(IPythonNotebookApp, self).initialize(argv) | |
229 | self.init_configurables() |
|
233 | self.init_configurables() | |
230 | self.web_app = NotebookWebApplication( |
|
234 | self.web_app = NotebookWebApplication( | |
231 | self, self.kernel_manager, self.notebook_manager, self.log |
|
235 | self, self.kernel_manager, self.notebook_manager, self.log | |
232 | ) |
|
236 | ) | |
233 | if self.certfile: |
|
237 | if self.certfile: | |
234 | ssl_options = dict(certfile=self.certfile) |
|
238 | ssl_options = dict(certfile=self.certfile) | |
235 | if self.keyfile: |
|
239 | if self.keyfile: | |
236 | ssl_options['keyfile'] = self.keyfile |
|
240 | ssl_options['keyfile'] = self.keyfile | |
237 | else: |
|
241 | else: | |
238 | ssl_options = None |
|
242 | ssl_options = None | |
239 | self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options) |
|
243 | self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options) | |
240 | if ssl_options is None and not self.ip: |
|
244 | if ssl_options is None and not self.ip: | |
241 | self.log.critical('WARNING: the notebook server is listening on all IP addresses ' |
|
245 | self.log.critical('WARNING: the notebook server is listening on all IP addresses ' | |
242 | 'but not using any encryption or authentication. This is highly ' |
|
246 | 'but not using any encryption or authentication. This is highly ' | |
243 | 'insecure and not recommended.') |
|
247 | 'insecure and not recommended.') | |
244 | for i in range(10): |
|
248 | ||
|
249 | # Try random ports centered around the default. | |||
|
250 | from random import randint | |||
|
251 | n = 50 # Max number of attempts, keep reasonably large. | |||
|
252 | for port in [self.port] + [self.port + randint(-2*n, 2*n) for i in range(n)]: | |||
245 | try: |
|
253 | try: | |
246 | port = self.port + i |
|
|||
247 | self.http_server.listen(port, self.ip) |
|
254 | self.http_server.listen(port, self.ip) | |
248 | except socket.error, e: |
|
255 | except socket.error, e: | |
249 | if e.errno != errno.EADDRINUSE: |
|
256 | if e.errno != errno.EADDRINUSE: | |
250 | raise |
|
257 | raise | |
251 |
self.log.info('The port %i is already in use, trying |
|
258 | self.log.info('The port %i is already in use, trying another random port.' % port) | |
252 | else: |
|
259 | else: | |
253 | self.port = port |
|
260 | self.port = port | |
254 | break |
|
261 | break | |
255 |
|
||||
256 |
|
262 | |||
257 | def start(self): |
|
263 | def start(self): | |
258 | ip = self.ip if self.ip else '[all ip addresses on your system]' |
|
264 | ip = self.ip if self.ip else '[all ip addresses on your system]' | |
259 | self.log.info("The IPython Notebook is running at: http://%s:%i" % (ip, self.port)) |
|
265 | self.log.info("The IPython Notebook is running at: http://%s:%i" % (ip, self.port)) | |
260 | ioloop.IOLoop.instance().start() |
|
266 | ioloop.IOLoop.instance().start() | |
261 |
|
267 | |||
262 | #----------------------------------------------------------------------------- |
|
268 | #----------------------------------------------------------------------------- | |
263 | # Main entry point |
|
269 | # Main entry point | |
264 | #----------------------------------------------------------------------------- |
|
270 | #----------------------------------------------------------------------------- | |
265 |
|
271 | |||
266 | def launch_new_instance(): |
|
272 | def launch_new_instance(): | |
267 | app = IPythonNotebookApp() |
|
273 | app = IPythonNotebookApp() | |
268 | app.initialize() |
|
274 | app.initialize() | |
269 | app.start() |
|
275 | app.start() | |
270 |
|
276 |
@@ -1,227 +1,232 b'' | |||||
|
1 | """A notebook manager that uses the local file system for storage. | |||
|
2 | ||||
|
3 | Authors: | |||
|
4 | ||||
|
5 | * Brian Granger | |||
|
6 | """ | |||
|
7 | ||||
1 | #----------------------------------------------------------------------------- |
|
8 | #----------------------------------------------------------------------------- | |
2 | # Copyright (C) 2011 The IPython Development Team |
|
9 | # Copyright (C) 2008-2011 The IPython Development Team | |
3 | # |
|
10 | # | |
4 | # Distributed under the terms of the BSD License. The full license is in |
|
11 | # Distributed under the terms of the BSD License. The full license is in | |
5 |
# the file COPYING |
|
12 | # the file COPYING, distributed as part of this software. | |
6 | #----------------------------------------------------------------------------- |
|
13 | #----------------------------------------------------------------------------- | |
7 |
|
14 | |||
8 | #----------------------------------------------------------------------------- |
|
15 | #----------------------------------------------------------------------------- | |
9 | # Imports |
|
16 | # Imports | |
10 | #----------------------------------------------------------------------------- |
|
17 | #----------------------------------------------------------------------------- | |
11 |
|
18 | |||
12 | import datetime |
|
19 | import datetime | |
13 | import os |
|
20 | import os | |
14 | import uuid |
|
21 | import uuid | |
15 |
|
22 | |||
16 | from tornado import web |
|
23 | from tornado import web | |
17 |
|
24 | |||
18 | from IPython.config.configurable import LoggingConfigurable |
|
25 | from IPython.config.configurable import LoggingConfigurable | |
19 | from IPython.nbformat import current |
|
26 | from IPython.nbformat import current | |
20 | from IPython.utils.traitlets import Unicode, List, Dict |
|
27 | from IPython.utils.traitlets import Unicode, List, Dict | |
21 |
|
28 | |||
22 |
|
29 | |||
23 | #----------------------------------------------------------------------------- |
|
30 | #----------------------------------------------------------------------------- | |
24 | # Code |
|
31 | # Code | |
25 | #----------------------------------------------------------------------------- |
|
32 | #----------------------------------------------------------------------------- | |
26 |
|
33 | |||
27 |
|
34 | |||
28 | class NotebookManager(LoggingConfigurable): |
|
35 | class NotebookManager(LoggingConfigurable): | |
29 |
|
36 | |||
30 | notebook_dir = Unicode(os.getcwd(), config=True, help=""" |
|
37 | notebook_dir = Unicode(os.getcwd(), config=True, help=""" | |
31 | The directory to use for notebooks. |
|
38 | The directory to use for notebooks. | |
32 | """) |
|
39 | """) | |
33 | filename_ext = Unicode(u'.ipynb') |
|
40 | filename_ext = Unicode(u'.ipynb') | |
34 | allowed_formats = List([u'json',u'xml',u'py']) |
|
41 | allowed_formats = List([u'json',u'xml',u'py']) | |
35 |
|
42 | |||
36 | # Map notebook_ids to notebook names |
|
43 | # Map notebook_ids to notebook names | |
37 | mapping = Dict() |
|
44 | mapping = Dict() | |
38 | # Map notebook names to notebook_ids |
|
45 | # Map notebook names to notebook_ids | |
39 | rev_mapping = Dict() |
|
46 | rev_mapping = Dict() | |
40 |
|
47 | |||
41 | def list_notebooks(self): |
|
48 | def list_notebooks(self): | |
42 | """List all notebooks in the notebook dir. |
|
49 | """List all notebooks in the notebook dir. | |
43 |
|
50 | |||
44 | This returns a list of dicts of the form:: |
|
51 | This returns a list of dicts of the form:: | |
45 |
|
52 | |||
46 | dict(notebook_id=notebook,name=name) |
|
53 | dict(notebook_id=notebook,name=name) | |
47 | """ |
|
54 | """ | |
48 | names = os.listdir(self.notebook_dir) |
|
55 | names = os.listdir(self.notebook_dir) | |
49 |
names = [name.split(u'.')[0] |
|
56 | names = [name.split(u'.')[0] | |
50 | for name in names if name.endswith(self.filename_ext)] |
|
57 | for name in names if name.endswith(self.filename_ext)] | |
51 | data = [] |
|
58 | data = [] | |
52 | for name in names: |
|
59 | for name in names: | |
53 | if name not in self.rev_mapping: |
|
60 | if name not in self.rev_mapping: | |
54 | notebook_id = self.new_notebook_id(name) |
|
61 | notebook_id = self.new_notebook_id(name) | |
55 | else: |
|
62 | else: | |
56 | notebook_id = self.rev_mapping[name] |
|
63 | notebook_id = self.rev_mapping[name] | |
57 | data.append(dict(notebook_id=notebook_id,name=name)) |
|
64 | data.append(dict(notebook_id=notebook_id,name=name)) | |
58 | data = sorted(data, key=lambda item: item['name']) |
|
65 | data = sorted(data, key=lambda item: item['name']) | |
59 | return data |
|
66 | return data | |
60 |
|
67 | |||
61 | def new_notebook_id(self, name): |
|
68 | def new_notebook_id(self, name): | |
62 | """Generate a new notebook_id for a name and store its mappings.""" |
|
69 | """Generate a new notebook_id for a name and store its mappings.""" | |
63 | notebook_id = unicode(uuid.uuid4()) |
|
70 | notebook_id = unicode(uuid.uuid4()) | |
64 | self.mapping[notebook_id] = name |
|
71 | self.mapping[notebook_id] = name | |
65 | self.rev_mapping[name] = notebook_id |
|
72 | self.rev_mapping[name] = notebook_id | |
66 | return notebook_id |
|
73 | return notebook_id | |
67 |
|
74 | |||
68 | def delete_notebook_id(self, notebook_id): |
|
75 | def delete_notebook_id(self, notebook_id): | |
69 | """Delete a notebook's id only. This doesn't delete the actual notebook.""" |
|
76 | """Delete a notebook's id only. This doesn't delete the actual notebook.""" | |
70 | name = self.mapping[notebook_id] |
|
77 | name = self.mapping[notebook_id] | |
71 | del self.mapping[notebook_id] |
|
78 | del self.mapping[notebook_id] | |
72 | del self.rev_mapping[name] |
|
79 | del self.rev_mapping[name] | |
73 |
|
80 | |||
74 | def notebook_exists(self, notebook_id): |
|
81 | def notebook_exists(self, notebook_id): | |
75 | """Does a notebook exist?""" |
|
82 | """Does a notebook exist?""" | |
76 | if notebook_id not in self.mapping: |
|
83 | if notebook_id not in self.mapping: | |
77 | return False |
|
84 | return False | |
78 | path = self.get_path_by_name(self.mapping[notebook_id]) |
|
85 | path = self.get_path_by_name(self.mapping[notebook_id]) | |
79 |
|
|
86 | return os.path.isfile(path) | |
80 | return False |
|
|||
81 | return True |
|
|||
82 |
|
87 | |||
83 | def find_path(self, notebook_id): |
|
88 | def find_path(self, notebook_id): | |
84 | """Return a full path to a notebook given its notebook_id.""" |
|
89 | """Return a full path to a notebook given its notebook_id.""" | |
85 | try: |
|
90 | try: | |
86 | name = self.mapping[notebook_id] |
|
91 | name = self.mapping[notebook_id] | |
87 | except KeyError: |
|
92 | except KeyError: | |
88 | raise web.HTTPError(404) |
|
93 | raise web.HTTPError(404) | |
89 | return self.get_path_by_name(name) |
|
94 | return self.get_path_by_name(name) | |
90 |
|
95 | |||
91 | def get_path_by_name(self, name): |
|
96 | def get_path_by_name(self, name): | |
92 | """Return a full path to a notebook given its name.""" |
|
97 | """Return a full path to a notebook given its name.""" | |
93 | filename = name + self.filename_ext |
|
98 | filename = name + self.filename_ext | |
94 | path = os.path.join(self.notebook_dir, filename) |
|
99 | path = os.path.join(self.notebook_dir, filename) | |
95 | return path |
|
100 | return path | |
96 |
|
101 | |||
97 | def get_notebook(self, notebook_id, format=u'json'): |
|
102 | def get_notebook(self, notebook_id, format=u'json'): | |
98 | """Get the representation of a notebook in format by notebook_id.""" |
|
103 | """Get the representation of a notebook in format by notebook_id.""" | |
99 | format = unicode(format) |
|
104 | format = unicode(format) | |
100 | if format not in self.allowed_formats: |
|
105 | if format not in self.allowed_formats: | |
101 | raise web.HTTPError(415) |
|
106 | raise web.HTTPError(415) | |
102 | last_modified, nb = self.get_notebook_object(notebook_id) |
|
107 | last_modified, nb = self.get_notebook_object(notebook_id) | |
103 | data = current.writes(nb, format) |
|
108 | data = current.writes(nb, format) | |
104 | name = nb.get('name','notebook') |
|
109 | name = nb.get('name','notebook') | |
105 | return last_modified, name, data |
|
110 | return last_modified, name, data | |
106 |
|
111 | |||
107 | def get_notebook_object(self, notebook_id): |
|
112 | def get_notebook_object(self, notebook_id): | |
108 | """Get the NotebookNode representation of a notebook by notebook_id.""" |
|
113 | """Get the NotebookNode representation of a notebook by notebook_id.""" | |
109 | path = self.find_path(notebook_id) |
|
114 | path = self.find_path(notebook_id) | |
110 | if not os.path.isfile(path): |
|
115 | if not os.path.isfile(path): | |
111 | raise web.HTTPError(404) |
|
116 | raise web.HTTPError(404) | |
112 | info = os.stat(path) |
|
117 | info = os.stat(path) | |
113 | last_modified = datetime.datetime.utcfromtimestamp(info.st_mtime) |
|
118 | last_modified = datetime.datetime.utcfromtimestamp(info.st_mtime) | |
114 | try: |
|
119 | try: | |
115 | with open(path,'r') as f: |
|
120 | with open(path,'r') as f: | |
116 | s = f.read() |
|
121 | s = f.read() | |
117 | try: |
|
122 | try: | |
118 | # v2 and later have xml in the .ipynb files. |
|
123 | # v2 and later have xml in the .ipynb files. | |
119 | nb = current.reads(s, 'xml') |
|
124 | nb = current.reads(s, 'xml') | |
120 | except: |
|
125 | except: | |
121 | # v1 had json in the .ipynb files. |
|
126 | # v1 had json in the .ipynb files. | |
122 | nb = current.reads(s, 'json') |
|
127 | nb = current.reads(s, 'json') | |
123 | # v1 notebooks don't have a name field, so use the filename. |
|
128 | # v1 notebooks don't have a name field, so use the filename. | |
124 | nb.name = os.path.split(path)[-1].split(u'.')[0] |
|
129 | nb.name = os.path.split(path)[-1].split(u'.')[0] | |
125 | except: |
|
130 | except: | |
126 | raise web.HTTPError(404) |
|
131 | raise web.HTTPError(404) | |
127 | return last_modified, nb |
|
132 | return last_modified, nb | |
128 |
|
133 | |||
129 | def save_new_notebook(self, data, name=None, format=u'json'): |
|
134 | def save_new_notebook(self, data, name=None, format=u'json'): | |
130 | """Save a new notebook and return its notebook_id. |
|
135 | """Save a new notebook and return its notebook_id. | |
131 |
|
136 | |||
132 | If a name is passed in, it overrides any values in the notebook data |
|
137 | If a name is passed in, it overrides any values in the notebook data | |
133 | and the value in the data is updated to use that value. |
|
138 | and the value in the data is updated to use that value. | |
134 | """ |
|
139 | """ | |
135 | if format not in self.allowed_formats: |
|
140 | if format not in self.allowed_formats: | |
136 | raise web.HTTPError(415) |
|
141 | raise web.HTTPError(415) | |
137 |
|
142 | |||
138 | try: |
|
143 | try: | |
139 | nb = current.reads(data, format) |
|
144 | nb = current.reads(data, format) | |
140 | except: |
|
145 | except: | |
141 | if format == u'xml': |
|
146 | if format == u'xml': | |
142 | # v1 notebooks might come in with a format='xml' but be json. |
|
147 | # v1 notebooks might come in with a format='xml' but be json. | |
143 | try: |
|
148 | try: | |
144 | nb = current.reads(data, u'json') |
|
149 | nb = current.reads(data, u'json') | |
145 | except: |
|
150 | except: | |
146 | raise web.HTTPError(400) |
|
151 | raise web.HTTPError(400) | |
147 | else: |
|
152 | else: | |
148 | raise web.HTTPError(400) |
|
153 | raise web.HTTPError(400) | |
149 |
|
154 | |||
150 | if name is None: |
|
155 | if name is None: | |
151 | try: |
|
156 | try: | |
152 | name = nb.name |
|
157 | name = nb.name | |
153 | except AttributeError: |
|
158 | except AttributeError: | |
154 | raise web.HTTPError(400) |
|
159 | raise web.HTTPError(400) | |
155 | nb.name = name |
|
160 | nb.name = name | |
156 |
|
161 | |||
157 | notebook_id = self.new_notebook_id(name) |
|
162 | notebook_id = self.new_notebook_id(name) | |
158 | self.save_notebook_object(notebook_id, nb) |
|
163 | self.save_notebook_object(notebook_id, nb) | |
159 | return notebook_id |
|
164 | return notebook_id | |
160 |
|
165 | |||
161 | def save_notebook(self, notebook_id, data, name=None, format=u'json'): |
|
166 | def save_notebook(self, notebook_id, data, name=None, format=u'json'): | |
162 | """Save an existing notebook by notebook_id.""" |
|
167 | """Save an existing notebook by notebook_id.""" | |
163 | if format not in self.allowed_formats: |
|
168 | if format not in self.allowed_formats: | |
164 | raise web.HTTPError(415) |
|
169 | raise web.HTTPError(415) | |
165 |
|
170 | |||
166 | try: |
|
171 | try: | |
167 | nb = current.reads(data, format) |
|
172 | nb = current.reads(data, format) | |
168 | except: |
|
173 | except: | |
169 | if format == u'xml': |
|
174 | if format == u'xml': | |
170 | # v1 notebooks might come in with a format='xml' but be json. |
|
175 | # v1 notebooks might come in with a format='xml' but be json. | |
171 | try: |
|
176 | try: | |
172 | nb = current.reads(data, u'json') |
|
177 | nb = current.reads(data, u'json') | |
173 | except: |
|
178 | except: | |
174 | raise web.HTTPError(400) |
|
179 | raise web.HTTPError(400) | |
175 | else: |
|
180 | else: | |
176 | raise web.HTTPError(400) |
|
181 | raise web.HTTPError(400) | |
177 |
|
182 | |||
178 | if name is not None: |
|
183 | if name is not None: | |
179 | nb.name = name |
|
184 | nb.name = name | |
180 | self.save_notebook_object(notebook_id, nb) |
|
185 | self.save_notebook_object(notebook_id, nb) | |
181 |
|
186 | |||
182 | def save_notebook_object(self, notebook_id, nb): |
|
187 | def save_notebook_object(self, notebook_id, nb): | |
183 | """Save an existing notebook object by notebook_id.""" |
|
188 | """Save an existing notebook object by notebook_id.""" | |
184 | if notebook_id not in self.mapping: |
|
189 | if notebook_id not in self.mapping: | |
185 | raise web.HTTPError(404) |
|
190 | raise web.HTTPError(404) | |
186 | old_name = self.mapping[notebook_id] |
|
191 | old_name = self.mapping[notebook_id] | |
187 | try: |
|
192 | try: | |
188 | new_name = nb.name |
|
193 | new_name = nb.name | |
189 | except AttributeError: |
|
194 | except AttributeError: | |
190 | raise web.HTTPError(400) |
|
195 | raise web.HTTPError(400) | |
191 | path = self.get_path_by_name(new_name) |
|
196 | path = self.get_path_by_name(new_name) | |
192 | try: |
|
197 | try: | |
193 | with open(path,'w') as f: |
|
198 | with open(path,'w') as f: | |
194 | current.write(nb, f, u'xml') |
|
199 | current.write(nb, f, u'xml') | |
195 | except: |
|
200 | except: | |
196 | raise web.HTTPError(400) |
|
201 | raise web.HTTPError(400) | |
197 | if old_name != new_name: |
|
202 | if old_name != new_name: | |
198 | old_path = self.get_path_by_name(old_name) |
|
203 | old_path = self.get_path_by_name(old_name) | |
199 | if os.path.isfile(old_path): |
|
204 | if os.path.isfile(old_path): | |
200 | os.unlink(old_path) |
|
205 | os.unlink(old_path) | |
201 | self.mapping[notebook_id] = new_name |
|
206 | self.mapping[notebook_id] = new_name | |
202 | self.rev_mapping[new_name] = notebook_id |
|
207 | self.rev_mapping[new_name] = notebook_id | |
203 |
|
208 | |||
204 | def delete_notebook(self, notebook_id): |
|
209 | def delete_notebook(self, notebook_id): | |
205 | """Delete notebook by notebook_id.""" |
|
210 | """Delete notebook by notebook_id.""" | |
206 | path = self.find_path(notebook_id) |
|
211 | path = self.find_path(notebook_id) | |
207 | if not os.path.isfile(path): |
|
212 | if not os.path.isfile(path): | |
208 | raise web.HTTPError(404) |
|
213 | raise web.HTTPError(404) | |
209 | os.unlink(path) |
|
214 | os.unlink(path) | |
210 | self.delete_notebook_id(notebook_id) |
|
215 | self.delete_notebook_id(notebook_id) | |
211 |
|
216 | |||
212 | def new_notebook(self): |
|
217 | def new_notebook(self): | |
213 | """Create a new notebook and returns its notebook_id.""" |
|
218 | """Create a new notebook and returns its notebook_id.""" | |
214 | i = 0 |
|
219 | i = 0 | |
215 | while True: |
|
220 | while True: | |
216 | name = u'Untitled%i' % i |
|
221 | name = u'Untitled%i' % i | |
217 | path = self.get_path_by_name(name) |
|
222 | path = self.get_path_by_name(name) | |
218 | if not os.path.isfile(path): |
|
223 | if not os.path.isfile(path): | |
219 | break |
|
224 | break | |
220 | else: |
|
225 | else: | |
221 | i = i+1 |
|
226 | i = i+1 | |
222 | notebook_id = self.new_notebook_id(name) |
|
227 | notebook_id = self.new_notebook_id(name) | |
223 | nb = current.new_notebook(name=name) |
|
228 | nb = current.new_notebook(name=name) | |
224 | with open(path,'w') as f: |
|
229 | with open(path,'w') as f: | |
225 | current.write(nb, f, u'xml') |
|
230 | current.write(nb, f, u'xml') | |
226 | return notebook_id |
|
231 | return notebook_id | |
227 |
|
232 |
@@ -1,87 +1,93 b'' | |||||
|
1 | //---------------------------------------------------------------------------- | |||
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |||
|
3 | // | |||
|
4 | // Distributed under the terms of the BSD License. The full license is in | |||
|
5 | // the file COPYING, distributed as part of this software. | |||
|
6 | //---------------------------------------------------------------------------- | |||
1 |
|
|
7 | ||
2 | //============================================================================ |
|
8 | //============================================================================ | |
3 | // Cell |
|
9 | // Cell | |
4 | //============================================================================ |
|
10 | //============================================================================ | |
5 |
|
11 | |||
6 | var IPython = (function (IPython) { |
|
12 | var IPython = (function (IPython) { | |
7 |
|
13 | |||
8 | var utils = IPython.utils; |
|
14 | var utils = IPython.utils; | |
9 |
|
15 | |||
10 | var Cell = function (notebook) { |
|
16 | var Cell = function (notebook) { | |
11 | this.notebook = notebook; |
|
17 | this.notebook = notebook; | |
12 | this.selected = false; |
|
18 | this.selected = false; | |
13 | this.element = null; |
|
19 | this.element = null; | |
14 | this.create_element(); |
|
20 | this.create_element(); | |
15 | if (this.element !== null) { |
|
21 | if (this.element !== null) { | |
16 | this.set_autoindent(true); |
|
22 | this.set_autoindent(true); | |
17 | this.element.data("cell", this); |
|
23 | this.element.data("cell", this); | |
18 | this.bind_events(); |
|
24 | this.bind_events(); | |
19 | } |
|
25 | } | |
20 | this.cell_id = utils.uuid(); |
|
26 | this.cell_id = utils.uuid(); | |
21 | }; |
|
27 | }; | |
22 |
|
28 | |||
23 |
|
29 | |||
24 | Cell.prototype.select = function () { |
|
30 | Cell.prototype.select = function () { | |
25 | this.element.addClass('ui-widget-content ui-corner-all'); |
|
31 | this.element.addClass('ui-widget-content ui-corner-all'); | |
26 | this.selected = true; |
|
32 | this.selected = true; | |
27 | }; |
|
33 | }; | |
28 |
|
34 | |||
29 |
|
35 | |||
30 | Cell.prototype.unselect = function () { |
|
36 | Cell.prototype.unselect = function () { | |
31 | this.element.removeClass('ui-widget-content ui-corner-all'); |
|
37 | this.element.removeClass('ui-widget-content ui-corner-all'); | |
32 | this.selected = false; |
|
38 | this.selected = false; | |
33 | }; |
|
39 | }; | |
34 |
|
40 | |||
35 |
|
41 | |||
36 | Cell.prototype.bind_events = function () { |
|
42 | Cell.prototype.bind_events = function () { | |
37 | var that = this; |
|
43 | var that = this; | |
38 | var nb = that.notebook |
|
44 | var nb = that.notebook | |
39 | that.element.click(function (event) { |
|
45 | that.element.click(function (event) { | |
40 | if (that.selected === false) { |
|
46 | if (that.selected === false) { | |
41 | nb.select(nb.find_cell_index(that)); |
|
47 | nb.select(nb.find_cell_index(that)); | |
42 | }; |
|
48 | }; | |
43 | }); |
|
49 | }); | |
44 | that.element.focusin(function (event) { |
|
50 | that.element.focusin(function (event) { | |
45 | if (that.selected === false) { |
|
51 | if (that.selected === false) { | |
46 | nb.select(nb.find_cell_index(that)); |
|
52 | nb.select(nb.find_cell_index(that)); | |
47 | }; |
|
53 | }; | |
48 | }); |
|
54 | }); | |
49 | }; |
|
55 | }; | |
50 |
|
56 | |||
51 | Cell.prototype.grow = function(element) { |
|
57 | Cell.prototype.grow = function(element) { | |
52 | // Grow the cell by hand. This is used upon reloading from JSON, when the |
|
58 | // Grow the cell by hand. This is used upon reloading from JSON, when the | |
53 | // autogrow handler is not called. |
|
59 | // autogrow handler is not called. | |
54 | var dom = element.get(0); |
|
60 | var dom = element.get(0); | |
55 | var lines_count = 0; |
|
61 | var lines_count = 0; | |
56 | // modified split rule from |
|
62 | // modified split rule from | |
57 | // http://stackoverflow.com/questions/2035910/how-to-get-the-number-of-lines-in-a-textarea/2036424#2036424 |
|
63 | // http://stackoverflow.com/questions/2035910/how-to-get-the-number-of-lines-in-a-textarea/2036424#2036424 | |
58 | var lines = dom.value.split(/\r|\r\n|\n/); |
|
64 | var lines = dom.value.split(/\r|\r\n|\n/); | |
59 | lines_count = lines.length; |
|
65 | lines_count = lines.length; | |
60 | if (lines_count >= 1) { |
|
66 | if (lines_count >= 1) { | |
61 | dom.rows = lines_count; |
|
67 | dom.rows = lines_count; | |
62 | } else { |
|
68 | } else { | |
63 | dom.rows = 1; |
|
69 | dom.rows = 1; | |
64 | } |
|
70 | } | |
65 | }; |
|
71 | }; | |
66 |
|
72 | |||
67 |
|
73 | |||
68 | Cell.prototype.set_autoindent = function (state) { |
|
74 | Cell.prototype.set_autoindent = function (state) { | |
69 | if (state) { |
|
75 | if (state) { | |
70 | this.code_mirror.setOption('tabMode', 'indent'); |
|
76 | this.code_mirror.setOption('tabMode', 'indent'); | |
71 | this.code_mirror.setOption('enterMode', 'indent'); |
|
77 | this.code_mirror.setOption('enterMode', 'indent'); | |
72 | } else { |
|
78 | } else { | |
73 | this.code_mirror.setOption('tabMode', 'shift'); |
|
79 | this.code_mirror.setOption('tabMode', 'shift'); | |
74 | this.code_mirror.setOption('enterMode', 'flat'); |
|
80 | this.code_mirror.setOption('enterMode', 'flat'); | |
75 | } |
|
81 | } | |
76 | }; |
|
82 | }; | |
77 |
|
83 | |||
78 |
|
84 | |||
79 | // Subclasses must implement create_element. |
|
85 | // Subclasses must implement create_element. | |
80 | Cell.prototype.create_element = function () {}; |
|
86 | Cell.prototype.create_element = function () {}; | |
81 |
|
87 | |||
82 | IPython.Cell = Cell; |
|
88 | IPython.Cell = Cell; | |
83 |
|
89 | |||
84 | return IPython; |
|
90 | return IPython; | |
85 |
|
91 | |||
86 | }(IPython)); |
|
92 | }(IPython)); | |
87 |
|
93 |
@@ -1,434 +1,440 b'' | |||||
|
1 | //---------------------------------------------------------------------------- | |||
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |||
|
3 | // | |||
|
4 | // Distributed under the terms of the BSD License. The full license is in | |||
|
5 | // the file COPYING, distributed as part of this software. | |||
|
6 | //---------------------------------------------------------------------------- | |||
1 |
|
|
7 | ||
2 | //============================================================================ |
|
8 | //============================================================================ | |
3 | // CodeCell |
|
9 | // CodeCell | |
4 | //============================================================================ |
|
10 | //============================================================================ | |
5 |
|
11 | |||
6 | var IPython = (function (IPython) { |
|
12 | var IPython = (function (IPython) { | |
7 |
|
13 | |||
8 | var utils = IPython.utils; |
|
14 | var utils = IPython.utils; | |
9 |
|
15 | |||
10 | var CodeCell = function (notebook) { |
|
16 | var CodeCell = function (notebook) { | |
11 | this.code_mirror = null; |
|
17 | this.code_mirror = null; | |
12 | this.input_prompt_number = ' '; |
|
18 | this.input_prompt_number = ' '; | |
13 | this.is_completing = false; |
|
19 | this.is_completing = false; | |
14 | this.completion_cursor = null; |
|
20 | this.completion_cursor = null; | |
15 | this.outputs = []; |
|
21 | this.outputs = []; | |
16 | this.collapsed = false; |
|
22 | this.collapsed = false; | |
17 | IPython.Cell.apply(this, arguments); |
|
23 | IPython.Cell.apply(this, arguments); | |
18 | }; |
|
24 | }; | |
19 |
|
25 | |||
20 |
|
26 | |||
21 | CodeCell.prototype = new IPython.Cell(); |
|
27 | CodeCell.prototype = new IPython.Cell(); | |
22 |
|
28 | |||
23 |
|
29 | |||
24 | CodeCell.prototype.create_element = function () { |
|
30 | CodeCell.prototype.create_element = function () { | |
25 | var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox'); |
|
31 | var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox'); | |
26 | var input = $('<div></div>').addClass('input hbox'); |
|
32 | var input = $('<div></div>').addClass('input hbox'); | |
27 | input.append($('<div/>').addClass('prompt input_prompt')); |
|
33 | input.append($('<div/>').addClass('prompt input_prompt')); | |
28 | var input_area = $('<div/>').addClass('input_area box-flex1'); |
|
34 | var input_area = $('<div/>').addClass('input_area box-flex1'); | |
29 | this.code_mirror = CodeMirror(input_area.get(0), { |
|
35 | this.code_mirror = CodeMirror(input_area.get(0), { | |
30 | indentUnit : 4, |
|
36 | indentUnit : 4, | |
31 | mode: 'python', |
|
37 | mode: 'python', | |
32 | theme: 'ipython', |
|
38 | theme: 'ipython', | |
33 | onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this) |
|
39 | onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this) | |
34 | }); |
|
40 | }); | |
35 | input.append(input_area); |
|
41 | input.append(input_area); | |
36 | var output = $('<div></div>').addClass('output vbox'); |
|
42 | var output = $('<div></div>').addClass('output vbox'); | |
37 | cell.append(input).append(output); |
|
43 | cell.append(input).append(output); | |
38 | this.element = cell; |
|
44 | this.element = cell; | |
39 | this.collapse() |
|
45 | this.collapse() | |
40 | }; |
|
46 | }; | |
41 |
|
47 | |||
42 |
|
48 | |||
43 | CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) { |
|
49 | CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) { | |
44 | // This method gets called in CodeMirror's onKeyDown/onKeyPress handlers and |
|
50 | // This method gets called in CodeMirror's onKeyDown/onKeyPress handlers and | |
45 | // is used to provide custom key handling. Its return value is used to determine |
|
51 | // is used to provide custom key handling. Its return value is used to determine | |
46 | // if CodeMirror should ignore the event: true = ignore, false = don't ignore. |
|
52 | // if CodeMirror should ignore the event: true = ignore, false = don't ignore. | |
47 | if (event.keyCode === 13 && event.shiftKey) { |
|
53 | if (event.keyCode === 13 && event.shiftKey) { | |
48 | // Always ignore shift-enter in CodeMirror as we handle it. |
|
54 | // Always ignore shift-enter in CodeMirror as we handle it. | |
49 | return true; |
|
55 | return true; | |
50 | } else if (event.keyCode === 9 && event.type == 'keydown') { |
|
56 | } else if (event.keyCode === 9 && event.type == 'keydown') { | |
51 | // Tab completion. |
|
57 | // Tab completion. | |
52 | var cur = editor.getCursor(); |
|
58 | var cur = editor.getCursor(); | |
53 | var pre_cursor = editor.getRange({line:cur.line,ch:0},cur).trim(); |
|
59 | var pre_cursor = editor.getRange({line:cur.line,ch:0},cur).trim(); | |
54 | if (pre_cursor === "") { |
|
60 | if (pre_cursor === "") { | |
55 | // Don't autocomplete if the part of the line before the cursor is empty. |
|
61 | // Don't autocomplete if the part of the line before the cursor is empty. | |
56 | // In this case, let CodeMirror handle indentation. |
|
62 | // In this case, let CodeMirror handle indentation. | |
57 | return false; |
|
63 | return false; | |
58 | } else { |
|
64 | } else { | |
59 | // Autocomplete the current line. |
|
65 | // Autocomplete the current line. | |
60 | event.stop(); |
|
66 | event.stop(); | |
61 | var line = editor.getLine(cur.line); |
|
67 | var line = editor.getLine(cur.line); | |
62 | this.is_completing = true; |
|
68 | this.is_completing = true; | |
63 | this.completion_cursor = cur; |
|
69 | this.completion_cursor = cur; | |
64 | IPython.notebook.complete_cell(this, line, cur.ch); |
|
70 | IPython.notebook.complete_cell(this, line, cur.ch); | |
65 | return true; |
|
71 | return true; | |
66 | } |
|
72 | } | |
67 | } else if (event.keyCode === 8 && event.type == 'keydown') { |
|
73 | } else if (event.keyCode === 8 && event.type == 'keydown') { | |
68 | // If backspace and the line ends with 4 spaces, remove them. |
|
74 | // If backspace and the line ends with 4 spaces, remove them. | |
69 | var cur = editor.getCursor(); |
|
75 | var cur = editor.getCursor(); | |
70 | var line = editor.getLine(cur.line); |
|
76 | var line = editor.getLine(cur.line); | |
71 | var ending = line.slice(-4); |
|
77 | var ending = line.slice(-4); | |
72 | if (ending === ' ') { |
|
78 | if (ending === ' ') { | |
73 | editor.replaceRange('', |
|
79 | editor.replaceRange('', | |
74 | {line: cur.line, ch: cur.ch-4}, |
|
80 | {line: cur.line, ch: cur.ch-4}, | |
75 | {line: cur.line, ch: cur.ch} |
|
81 | {line: cur.line, ch: cur.ch} | |
76 | ); |
|
82 | ); | |
77 | event.stop(); |
|
83 | event.stop(); | |
78 | return true; |
|
84 | return true; | |
79 | } else { |
|
85 | } else { | |
80 | return false; |
|
86 | return false; | |
81 | }; |
|
87 | }; | |
82 | } else { |
|
88 | } else { | |
83 | // keypress/keyup also trigger on TAB press, and we don't want to use those |
|
89 | // keypress/keyup also trigger on TAB press, and we don't want to use those | |
84 | // to disable tab completion. |
|
90 | // to disable tab completion. | |
85 | if (this.is_completing && event.keyCode !== 9) { |
|
91 | if (this.is_completing && event.keyCode !== 9) { | |
86 | var ed_cur = editor.getCursor(); |
|
92 | var ed_cur = editor.getCursor(); | |
87 | var cc_cur = this.completion_cursor; |
|
93 | var cc_cur = this.completion_cursor; | |
88 | if (ed_cur.line !== cc_cur.line || ed_cur.ch !== cc_cur.ch) { |
|
94 | if (ed_cur.line !== cc_cur.line || ed_cur.ch !== cc_cur.ch) { | |
89 | this.is_completing = false; |
|
95 | this.is_completing = false; | |
90 | this.completion_cursor = null; |
|
96 | this.completion_cursor = null; | |
91 | }; |
|
97 | }; | |
92 | }; |
|
98 | }; | |
93 | return false; |
|
99 | return false; | |
94 | }; |
|
100 | }; | |
95 | }; |
|
101 | }; | |
96 |
|
102 | |||
97 |
|
103 | |||
98 | CodeCell.prototype.finish_completing = function (matched_text, matches) { |
|
104 | CodeCell.prototype.finish_completing = function (matched_text, matches) { | |
99 | // console.log("Got matches", matched_text, matches); |
|
105 | // console.log("Got matches", matched_text, matches); | |
100 | if (!this.is_completing || matches.length === 0) {return;} |
|
106 | if (!this.is_completing || matches.length === 0) {return;} | |
101 |
|
107 | |||
102 | var that = this; |
|
108 | var that = this; | |
103 | var cur = this.completion_cursor; |
|
109 | var cur = this.completion_cursor; | |
104 |
|
110 | |||
105 | var insert = function (selected_text) { |
|
111 | var insert = function (selected_text) { | |
106 | that.code_mirror.replaceRange( |
|
112 | that.code_mirror.replaceRange( | |
107 | selected_text, |
|
113 | selected_text, | |
108 | {line: cur.line, ch: (cur.ch-matched_text.length)}, |
|
114 | {line: cur.line, ch: (cur.ch-matched_text.length)}, | |
109 | {line: cur.line, ch: cur.ch} |
|
115 | {line: cur.line, ch: cur.ch} | |
110 | ); |
|
116 | ); | |
111 | }; |
|
117 | }; | |
112 |
|
118 | |||
113 | if (matches.length === 1) { |
|
119 | if (matches.length === 1) { | |
114 | insert(matches[0]); |
|
120 | insert(matches[0]); | |
115 | setTimeout(function(){that.code_mirror.focus();}, 50); |
|
121 | setTimeout(function(){that.code_mirror.focus();}, 50); | |
116 | return; |
|
122 | return; | |
117 | }; |
|
123 | }; | |
118 |
|
124 | |||
119 | var complete = $('<div/>').addClass('completions'); |
|
125 | var complete = $('<div/>').addClass('completions'); | |
120 | var select = $('<select/>').attr('multiple','true'); |
|
126 | var select = $('<select/>').attr('multiple','true'); | |
121 | for (var i=0; i<matches.length; ++i) { |
|
127 | for (var i=0; i<matches.length; ++i) { | |
122 | select.append($('<option/>').text(matches[i])); |
|
128 | select.append($('<option/>').text(matches[i])); | |
123 | } |
|
129 | } | |
124 | select.children().first().attr('selected','true'); |
|
130 | select.children().first().attr('selected','true'); | |
125 | select.attr('size',Math.min(10,matches.length)); |
|
131 | select.attr('size',Math.min(10,matches.length)); | |
126 | var pos = this.code_mirror.cursorCoords(); |
|
132 | var pos = this.code_mirror.cursorCoords(); | |
127 | complete.css('left',pos.x+'px'); |
|
133 | complete.css('left',pos.x+'px'); | |
128 | complete.css('top',pos.yBot+'px'); |
|
134 | complete.css('top',pos.yBot+'px'); | |
129 | complete.append(select); |
|
135 | complete.append(select); | |
130 |
|
136 | |||
131 | $('body').append(complete); |
|
137 | $('body').append(complete); | |
132 | var done = false; |
|
138 | var done = false; | |
133 |
|
139 | |||
134 | var close = function () { |
|
140 | var close = function () { | |
135 | if (done) return; |
|
141 | if (done) return; | |
136 | done = true; |
|
142 | done = true; | |
137 | complete.remove(); |
|
143 | complete.remove(); | |
138 | that.is_completing = false; |
|
144 | that.is_completing = false; | |
139 | that.completion_cursor = null; |
|
145 | that.completion_cursor = null; | |
140 | }; |
|
146 | }; | |
141 |
|
147 | |||
142 | var pick = function () { |
|
148 | var pick = function () { | |
143 | insert(select.val()[0]); |
|
149 | insert(select.val()[0]); | |
144 | close(); |
|
150 | close(); | |
145 | setTimeout(function(){that.code_mirror.focus();}, 50); |
|
151 | setTimeout(function(){that.code_mirror.focus();}, 50); | |
146 | }; |
|
152 | }; | |
147 |
|
153 | |||
148 | select.blur(close); |
|
154 | select.blur(close); | |
149 | select.keydown(function (event) { |
|
155 | select.keydown(function (event) { | |
150 | var code = event.which; |
|
156 | var code = event.which; | |
151 | if (code === 13 || code === 32) { |
|
157 | if (code === 13 || code === 32) { | |
152 | // Pressing SPACE or ENTER will cause a pick |
|
158 | // Pressing SPACE or ENTER will cause a pick | |
153 | event.stopPropagation(); |
|
159 | event.stopPropagation(); | |
154 | event.preventDefault(); |
|
160 | event.preventDefault(); | |
155 | pick(); |
|
161 | pick(); | |
156 | } else if (code === 38 || code === 40) { |
|
162 | } else if (code === 38 || code === 40) { | |
157 | // We don't want the document keydown handler to handle UP/DOWN, |
|
163 | // We don't want the document keydown handler to handle UP/DOWN, | |
158 | // but we want the default action. |
|
164 | // but we want the default action. | |
159 | event.stopPropagation(); |
|
165 | event.stopPropagation(); | |
160 | } else { |
|
166 | } else { | |
161 | // All other key presses exit completion. |
|
167 | // All other key presses exit completion. | |
162 | event.stopPropagation(); |
|
168 | event.stopPropagation(); | |
163 | event.preventDefault(); |
|
169 | event.preventDefault(); | |
164 | close(); |
|
170 | close(); | |
165 | that.code_mirror.focus(); |
|
171 | that.code_mirror.focus(); | |
166 | } |
|
172 | } | |
167 | }); |
|
173 | }); | |
168 | // Double click also causes a pick. |
|
174 | // Double click also causes a pick. | |
169 | select.dblclick(pick); |
|
175 | select.dblclick(pick); | |
170 | select.focus(); |
|
176 | select.focus(); | |
171 | }; |
|
177 | }; | |
172 |
|
178 | |||
173 |
|
179 | |||
174 | CodeCell.prototype.select = function () { |
|
180 | CodeCell.prototype.select = function () { | |
175 | IPython.Cell.prototype.select.apply(this); |
|
181 | IPython.Cell.prototype.select.apply(this); | |
176 | // Todo: this dance is needed because as of CodeMirror 2.12, focus is |
|
182 | // Todo: this dance is needed because as of CodeMirror 2.12, focus is | |
177 | // not causing the cursor to blink if the editor is empty initially. |
|
183 | // not causing the cursor to blink if the editor is empty initially. | |
178 | // While this seems to fix the issue, this should be fixed |
|
184 | // While this seems to fix the issue, this should be fixed | |
179 | // in CodeMirror proper. |
|
185 | // in CodeMirror proper. | |
180 | var s = this.code_mirror.getValue(); |
|
186 | var s = this.code_mirror.getValue(); | |
181 | if (s === '') this.code_mirror.setValue('.'); |
|
187 | if (s === '') this.code_mirror.setValue('.'); | |
182 | this.code_mirror.focus(); |
|
188 | this.code_mirror.focus(); | |
183 | if (s === '') this.code_mirror.setValue(''); |
|
189 | if (s === '') this.code_mirror.setValue(''); | |
184 | }; |
|
190 | }; | |
185 |
|
191 | |||
186 |
|
192 | |||
187 | CodeCell.prototype.append_output = function (json) { |
|
193 | CodeCell.prototype.append_output = function (json) { | |
188 | this.expand(); |
|
194 | this.expand(); | |
189 | if (json.output_type === 'pyout') { |
|
195 | if (json.output_type === 'pyout') { | |
190 | this.append_pyout(json); |
|
196 | this.append_pyout(json); | |
191 | } else if (json.output_type === 'pyerr') { |
|
197 | } else if (json.output_type === 'pyerr') { | |
192 | this.append_pyerr(json); |
|
198 | this.append_pyerr(json); | |
193 | } else if (json.output_type === 'display_data') { |
|
199 | } else if (json.output_type === 'display_data') { | |
194 | this.append_display_data(json); |
|
200 | this.append_display_data(json); | |
195 | } else if (json.output_type === 'stream') { |
|
201 | } else if (json.output_type === 'stream') { | |
196 | this.append_stream(json); |
|
202 | this.append_stream(json); | |
197 | }; |
|
203 | }; | |
198 | this.outputs.push(json); |
|
204 | this.outputs.push(json); | |
199 | }; |
|
205 | }; | |
200 |
|
206 | |||
201 |
|
207 | |||
202 | CodeCell.prototype.append_pyout = function (json) { |
|
208 | CodeCell.prototype.append_pyout = function (json) { | |
203 | n = json.prompt_number || ' '; |
|
209 | n = json.prompt_number || ' '; | |
204 | var toinsert = $("<div/>").addClass("output_pyout hbox"); |
|
210 | var toinsert = $("<div/>").addClass("output_pyout hbox"); | |
205 | toinsert.append($('<div/>'). |
|
211 | toinsert.append($('<div/>'). | |
206 | addClass('prompt output_prompt'). |
|
212 | addClass('prompt output_prompt'). | |
207 | html('Out[' + n + ']:') |
|
213 | html('Out[' + n + ']:') | |
208 | ); |
|
214 | ); | |
209 | this.append_mime_type(json, toinsert).addClass('output_area'); |
|
215 | this.append_mime_type(json, toinsert).addClass('output_area'); | |
210 | toinsert.children().last().addClass("box_flex1 pyout_area"); |
|
216 | toinsert.children().last().addClass("box_flex1 pyout_area"); | |
211 | this.element.find("div.output").append(toinsert); |
|
217 | this.element.find("div.output").append(toinsert); | |
212 | // If we just output latex, typeset it. |
|
218 | // If we just output latex, typeset it. | |
213 | if (json.latex !== undefined) { |
|
219 | if (json.latex !== undefined) { | |
214 | MathJax.Hub.Queue(["Typeset",MathJax.Hub]); |
|
220 | MathJax.Hub.Queue(["Typeset",MathJax.Hub]); | |
215 | }; |
|
221 | }; | |
216 | }; |
|
222 | }; | |
217 |
|
223 | |||
218 |
|
224 | |||
219 | CodeCell.prototype.append_pyerr = function (json) { |
|
225 | CodeCell.prototype.append_pyerr = function (json) { | |
220 | var tb = json.traceback; |
|
226 | var tb = json.traceback; | |
221 | if (tb !== undefined && tb.length > 0) { |
|
227 | if (tb !== undefined && tb.length > 0) { | |
222 | var s = ''; |
|
228 | var s = ''; | |
223 | var len = tb.length; |
|
229 | var len = tb.length; | |
224 | for (var i=0; i<len; i++) { |
|
230 | for (var i=0; i<len; i++) { | |
225 | s = s + tb[i] + '\n'; |
|
231 | s = s + tb[i] + '\n'; | |
226 | } |
|
232 | } | |
227 | s = s + '\n'; |
|
233 | s = s + '\n'; | |
228 | this.append_text(s).addClass('output_area'); |
|
234 | this.append_text(s).addClass('output_area'); | |
229 | }; |
|
235 | }; | |
230 | }; |
|
236 | }; | |
231 |
|
237 | |||
232 |
|
238 | |||
233 | CodeCell.prototype.append_stream = function (json) { |
|
239 | CodeCell.prototype.append_stream = function (json) { | |
234 | this.append_text(json.text).addClass('output_area'); |
|
240 | this.append_text(json.text).addClass('output_area'); | |
235 | }; |
|
241 | }; | |
236 |
|
242 | |||
237 |
|
243 | |||
238 | CodeCell.prototype.append_display_data = function (json) { |
|
244 | CodeCell.prototype.append_display_data = function (json) { | |
239 | this.append_mime_type(json).addClass('output_area'); |
|
245 | this.append_mime_type(json).addClass('output_area'); | |
240 | // If we just output latex, typeset it. |
|
246 | // If we just output latex, typeset it. | |
241 | if (json.latex !== undefined) { |
|
247 | if (json.latex !== undefined) { | |
242 | MathJax.Hub.Queue(["Typeset",MathJax.Hub]); |
|
248 | MathJax.Hub.Queue(["Typeset",MathJax.Hub]); | |
243 | }; |
|
249 | }; | |
244 | }; |
|
250 | }; | |
245 |
|
251 | |||
246 |
|
252 | |||
247 | CodeCell.prototype.append_mime_type = function (json, element) { |
|
253 | CodeCell.prototype.append_mime_type = function (json, element) { | |
248 | element = element || this.element.find("div.output"); |
|
254 | element = element || this.element.find("div.output"); | |
249 | if (json.html !== undefined) { |
|
255 | if (json.html !== undefined) { | |
250 | this.append_html(json.html, element); |
|
256 | this.append_html(json.html, element); | |
251 | } else if (json.latex !== undefined) { |
|
257 | } else if (json.latex !== undefined) { | |
252 | this.append_latex(json.latex, element); |
|
258 | this.append_latex(json.latex, element); | |
253 | } else if (json.svg !== undefined) { |
|
259 | } else if (json.svg !== undefined) { | |
254 | this.append_svg(json.svg, element); |
|
260 | this.append_svg(json.svg, element); | |
255 | } else if (json.png !== undefined) { |
|
261 | } else if (json.png !== undefined) { | |
256 | this.append_png(json.png, element); |
|
262 | this.append_png(json.png, element); | |
257 | } else if (json.jpeg !== undefined) { |
|
263 | } else if (json.jpeg !== undefined) { | |
258 | this.append_jpeg(json.jpeg, element); |
|
264 | this.append_jpeg(json.jpeg, element); | |
259 | } else if (json.text !== undefined) { |
|
265 | } else if (json.text !== undefined) { | |
260 | this.append_text(json.text, element); |
|
266 | this.append_text(json.text, element); | |
261 | }; |
|
267 | }; | |
262 | return element; |
|
268 | return element; | |
263 | }; |
|
269 | }; | |
264 |
|
270 | |||
265 |
|
271 | |||
266 | CodeCell.prototype.append_html = function (html, element) { |
|
272 | CodeCell.prototype.append_html = function (html, element) { | |
267 | element = element || this.element.find("div.output"); |
|
273 | element = element || this.element.find("div.output"); | |
268 | var toinsert = $("<div/>").addClass("output_html rendered_html"); |
|
274 | var toinsert = $("<div/>").addClass("output_html rendered_html"); | |
269 | toinsert.append(html); |
|
275 | toinsert.append(html); | |
270 | element.append(toinsert); |
|
276 | element.append(toinsert); | |
271 | return element; |
|
277 | return element; | |
272 | } |
|
278 | } | |
273 |
|
279 | |||
274 |
|
280 | |||
275 | CodeCell.prototype.append_text = function (data, element) { |
|
281 | CodeCell.prototype.append_text = function (data, element) { | |
276 | element = element || this.element.find("div.output"); |
|
282 | element = element || this.element.find("div.output"); | |
277 | var toinsert = $("<div/>").addClass("output_stream"); |
|
283 | var toinsert = $("<div/>").addClass("output_stream"); | |
278 | toinsert.append($("<pre/>").html(data)); |
|
284 | toinsert.append($("<pre/>").html(data)); | |
279 | element.append(toinsert); |
|
285 | element.append(toinsert); | |
280 | return element; |
|
286 | return element; | |
281 | }; |
|
287 | }; | |
282 |
|
288 | |||
283 |
|
289 | |||
284 | CodeCell.prototype.append_svg = function (svg, element) { |
|
290 | CodeCell.prototype.append_svg = function (svg, element) { | |
285 | element = element || this.element.find("div.output"); |
|
291 | element = element || this.element.find("div.output"); | |
286 | var toinsert = $("<div/>").addClass("output_svg"); |
|
292 | var toinsert = $("<div/>").addClass("output_svg"); | |
287 | toinsert.append(svg); |
|
293 | toinsert.append(svg); | |
288 | element.append(toinsert); |
|
294 | element.append(toinsert); | |
289 | return element; |
|
295 | return element; | |
290 | }; |
|
296 | }; | |
291 |
|
297 | |||
292 |
|
298 | |||
293 | CodeCell.prototype.append_png = function (png, element) { |
|
299 | CodeCell.prototype.append_png = function (png, element) { | |
294 | element = element || this.element.find("div.output"); |
|
300 | element = element || this.element.find("div.output"); | |
295 | var toinsert = $("<div/>").addClass("output_png"); |
|
301 | var toinsert = $("<div/>").addClass("output_png"); | |
296 | toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png)); |
|
302 | toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png)); | |
297 | element.append(toinsert); |
|
303 | element.append(toinsert); | |
298 | return element; |
|
304 | return element; | |
299 | }; |
|
305 | }; | |
300 |
|
306 | |||
301 |
|
307 | |||
302 | CodeCell.prototype.append_jpeg = function (jpeg, element) { |
|
308 | CodeCell.prototype.append_jpeg = function (jpeg, element) { | |
303 | element = element || this.element.find("div.output"); |
|
309 | element = element || this.element.find("div.output"); | |
304 | var toinsert = $("<div/>").addClass("output_jpeg"); |
|
310 | var toinsert = $("<div/>").addClass("output_jpeg"); | |
305 | toinsert.append($("<img/>").attr('src','data:image/jpeg;base64,'+jpeg)); |
|
311 | toinsert.append($("<img/>").attr('src','data:image/jpeg;base64,'+jpeg)); | |
306 | element.append(toinsert); |
|
312 | element.append(toinsert); | |
307 | return element; |
|
313 | return element; | |
308 | }; |
|
314 | }; | |
309 |
|
315 | |||
310 |
|
316 | |||
311 | CodeCell.prototype.append_latex = function (latex, element) { |
|
317 | CodeCell.prototype.append_latex = function (latex, element) { | |
312 | // This method cannot do the typesetting because the latex first has to |
|
318 | // This method cannot do the typesetting because the latex first has to | |
313 | // be on the page. |
|
319 | // be on the page. | |
314 | element = element || this.element.find("div.output"); |
|
320 | element = element || this.element.find("div.output"); | |
315 | var toinsert = $("<div/>").addClass("output_latex"); |
|
321 | var toinsert = $("<div/>").addClass("output_latex"); | |
316 | toinsert.append(latex); |
|
322 | toinsert.append(latex); | |
317 | element.append(toinsert); |
|
323 | element.append(toinsert); | |
318 | return element; |
|
324 | return element; | |
319 | } |
|
325 | } | |
320 |
|
326 | |||
321 |
|
327 | |||
322 | CodeCell.prototype.clear_output = function () { |
|
328 | CodeCell.prototype.clear_output = function () { | |
323 | this.element.find("div.output").html(""); |
|
329 | this.element.find("div.output").html(""); | |
324 | this.outputs = []; |
|
330 | this.outputs = []; | |
325 | }; |
|
331 | }; | |
326 |
|
332 | |||
327 |
|
333 | |||
328 | CodeCell.prototype.clear_input = function () { |
|
334 | CodeCell.prototype.clear_input = function () { | |
329 | this.code_mirror.setValue(''); |
|
335 | this.code_mirror.setValue(''); | |
330 | }; |
|
336 | }; | |
331 |
|
337 | |||
332 |
|
338 | |||
333 | CodeCell.prototype.collapse = function () { |
|
339 | CodeCell.prototype.collapse = function () { | |
334 | if (!this.collapsed) { |
|
340 | if (!this.collapsed) { | |
335 | this.element.find('div.output').hide(); |
|
341 | this.element.find('div.output').hide(); | |
336 | this.collapsed = true; |
|
342 | this.collapsed = true; | |
337 | }; |
|
343 | }; | |
338 | }; |
|
344 | }; | |
339 |
|
345 | |||
340 |
|
346 | |||
341 | CodeCell.prototype.expand = function () { |
|
347 | CodeCell.prototype.expand = function () { | |
342 | if (this.collapsed) { |
|
348 | if (this.collapsed) { | |
343 | this.element.find('div.output').show(); |
|
349 | this.element.find('div.output').show(); | |
344 | this.collapsed = false; |
|
350 | this.collapsed = false; | |
345 | }; |
|
351 | }; | |
346 | }; |
|
352 | }; | |
347 |
|
353 | |||
348 |
|
354 | |||
349 | CodeCell.prototype.set_input_prompt = function (number) { |
|
355 | CodeCell.prototype.set_input_prompt = function (number) { | |
350 | var n = number || ' '; |
|
356 | var n = number || ' '; | |
351 | this.input_prompt_number = n |
|
357 | this.input_prompt_number = n | |
352 | this.element.find('div.input_prompt').html('In [' + n + ']:'); |
|
358 | this.element.find('div.input_prompt').html('In [' + n + ']:'); | |
353 | }; |
|
359 | }; | |
354 |
|
360 | |||
355 |
|
361 | |||
356 | CodeCell.prototype.get_code = function () { |
|
362 | CodeCell.prototype.get_code = function () { | |
357 | return this.code_mirror.getValue(); |
|
363 | return this.code_mirror.getValue(); | |
358 | }; |
|
364 | }; | |
359 |
|
365 | |||
360 |
|
366 | |||
361 | CodeCell.prototype.set_code = function (code) { |
|
367 | CodeCell.prototype.set_code = function (code) { | |
362 | return this.code_mirror.setValue(code); |
|
368 | return this.code_mirror.setValue(code); | |
363 | }; |
|
369 | }; | |
364 |
|
370 | |||
365 |
|
371 | |||
366 | CodeCell.prototype.at_top = function () { |
|
372 | CodeCell.prototype.at_top = function () { | |
367 | var cursor = this.code_mirror.getCursor(); |
|
373 | var cursor = this.code_mirror.getCursor(); | |
368 | if (cursor.line === 0) { |
|
374 | if (cursor.line === 0) { | |
369 | return true; |
|
375 | return true; | |
370 | } else { |
|
376 | } else { | |
371 | return false; |
|
377 | return false; | |
372 | } |
|
378 | } | |
373 | }; |
|
379 | }; | |
374 |
|
380 | |||
375 |
|
381 | |||
376 | CodeCell.prototype.at_bottom = function () { |
|
382 | CodeCell.prototype.at_bottom = function () { | |
377 | var cursor = this.code_mirror.getCursor(); |
|
383 | var cursor = this.code_mirror.getCursor(); | |
378 | if (cursor.line === (this.code_mirror.lineCount()-1)) { |
|
384 | if (cursor.line === (this.code_mirror.lineCount()-1)) { | |
379 | return true; |
|
385 | return true; | |
380 | } else { |
|
386 | } else { | |
381 | return false; |
|
387 | return false; | |
382 | } |
|
388 | } | |
383 | }; |
|
389 | }; | |
384 |
|
390 | |||
385 |
|
391 | |||
386 | CodeCell.prototype.fromJSON = function (data) { |
|
392 | CodeCell.prototype.fromJSON = function (data) { | |
387 | // console.log('Import from JSON:', data); |
|
393 | // console.log('Import from JSON:', data); | |
388 | if (data.cell_type === 'code') { |
|
394 | if (data.cell_type === 'code') { | |
389 | if (data.input !== undefined) { |
|
395 | if (data.input !== undefined) { | |
390 | this.set_code(data.input); |
|
396 | this.set_code(data.input); | |
391 | } |
|
397 | } | |
392 | if (data.prompt_number !== undefined) { |
|
398 | if (data.prompt_number !== undefined) { | |
393 | this.set_input_prompt(data.prompt_number); |
|
399 | this.set_input_prompt(data.prompt_number); | |
394 | } else { |
|
400 | } else { | |
395 | this.set_input_prompt(); |
|
401 | this.set_input_prompt(); | |
396 | }; |
|
402 | }; | |
397 | var len = data.outputs.length; |
|
403 | var len = data.outputs.length; | |
398 | for (var i=0; i<len; i++) { |
|
404 | for (var i=0; i<len; i++) { | |
399 | this.append_output(data.outputs[i]); |
|
405 | this.append_output(data.outputs[i]); | |
400 | }; |
|
406 | }; | |
401 | if (data.collapsed !== undefined) { |
|
407 | if (data.collapsed !== undefined) { | |
402 | if (data.collapsed) { |
|
408 | if (data.collapsed) { | |
403 | this.collapse(); |
|
409 | this.collapse(); | |
404 | }; |
|
410 | }; | |
405 | }; |
|
411 | }; | |
406 | }; |
|
412 | }; | |
407 | }; |
|
413 | }; | |
408 |
|
414 | |||
409 |
|
415 | |||
410 | CodeCell.prototype.toJSON = function () { |
|
416 | CodeCell.prototype.toJSON = function () { | |
411 | var data = {}; |
|
417 | var data = {}; | |
412 | data.input = this.get_code(); |
|
418 | data.input = this.get_code(); | |
413 | data.cell_type = 'code'; |
|
419 | data.cell_type = 'code'; | |
414 | if (this.input_prompt_number !== ' ') { |
|
420 | if (this.input_prompt_number !== ' ') { | |
415 | data.prompt_number = this.input_prompt_number |
|
421 | data.prompt_number = this.input_prompt_number | |
416 | }; |
|
422 | }; | |
417 | var outputs = []; |
|
423 | var outputs = []; | |
418 | var len = this.outputs.length; |
|
424 | var len = this.outputs.length; | |
419 | for (var i=0; i<len; i++) { |
|
425 | for (var i=0; i<len; i++) { | |
420 | outputs[i] = this.outputs[i]; |
|
426 | outputs[i] = this.outputs[i]; | |
421 | }; |
|
427 | }; | |
422 | data.outputs = outputs; |
|
428 | data.outputs = outputs; | |
423 | data.language = 'python'; |
|
429 | data.language = 'python'; | |
424 | data.collapsed = this.collapsed; |
|
430 | data.collapsed = this.collapsed; | |
425 | // console.log('Export to JSON:',data); |
|
431 | // console.log('Export to JSON:',data); | |
426 | return data; |
|
432 | return data; | |
427 | }; |
|
433 | }; | |
428 |
|
434 | |||
429 |
|
435 | |||
430 | IPython.CodeCell = CodeCell; |
|
436 | IPython.CodeCell = CodeCell; | |
431 |
|
437 | |||
432 | return IPython; |
|
438 | return IPython; | |
433 | }(IPython)); |
|
439 | }(IPython)); | |
434 |
|
440 |
@@ -1,143 +1,149 b'' | |||||
|
1 | //---------------------------------------------------------------------------- | |||
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |||
|
3 | // | |||
|
4 | // Distributed under the terms of the BSD License. The full license is in | |||
|
5 | // the file COPYING, distributed as part of this software. | |||
|
6 | //---------------------------------------------------------------------------- | |||
1 |
|
|
7 | ||
2 | //============================================================================ |
|
8 | //============================================================================ | |
3 | // Kernel |
|
9 | // Kernel | |
4 | //============================================================================ |
|
10 | //============================================================================ | |
5 |
|
11 | |||
6 | var IPython = (function (IPython) { |
|
12 | var IPython = (function (IPython) { | |
7 |
|
13 | |||
8 | var utils = IPython.utils; |
|
14 | var utils = IPython.utils; | |
9 |
|
15 | |||
10 | var Kernel = function () { |
|
16 | var Kernel = function () { | |
11 | this.kernel_id = null; |
|
17 | this.kernel_id = null; | |
12 | this.base_url = "/kernels"; |
|
18 | this.base_url = "/kernels"; | |
13 | this.kernel_url = null; |
|
19 | this.kernel_url = null; | |
14 | this.shell_channel = null; |
|
20 | this.shell_channel = null; | |
15 | this.iopub_channel = null; |
|
21 | this.iopub_channel = null; | |
16 | this.running = false; |
|
22 | this.running = false; | |
17 | }; |
|
23 | }; | |
18 |
|
24 | |||
19 |
|
25 | |||
20 | Kernel.prototype.get_msg = function (msg_type, content) { |
|
26 | Kernel.prototype.get_msg = function (msg_type, content) { | |
21 | var msg = { |
|
27 | var msg = { | |
22 | header : { |
|
28 | header : { | |
23 | msg_id : utils.uuid(), |
|
29 | msg_id : utils.uuid(), | |
24 | username : "username", |
|
30 | username : "username", | |
25 | session: this.session_id, |
|
31 | session: this.session_id, | |
26 | msg_type : msg_type |
|
32 | msg_type : msg_type | |
27 | }, |
|
33 | }, | |
28 | content : content, |
|
34 | content : content, | |
29 | parent_header : {} |
|
35 | parent_header : {} | |
30 | }; |
|
36 | }; | |
31 | return msg; |
|
37 | return msg; | |
32 | } |
|
38 | } | |
33 |
|
39 | |||
34 | Kernel.prototype.start = function (notebook_id, callback) { |
|
40 | Kernel.prototype.start = function (notebook_id, callback) { | |
35 | var that = this; |
|
41 | var that = this; | |
36 | if (!this.running) { |
|
42 | if (!this.running) { | |
37 | var qs = $.param({notebook:notebook_id}); |
|
43 | var qs = $.param({notebook:notebook_id}); | |
38 | $.post(this.base_url + '?' + qs, |
|
44 | $.post(this.base_url + '?' + qs, | |
39 | function (kernel_id) { |
|
45 | function (kernel_id) { | |
40 | that._handle_start_kernel(kernel_id, callback); |
|
46 | that._handle_start_kernel(kernel_id, callback); | |
41 | }, |
|
47 | }, | |
42 | 'json' |
|
48 | 'json' | |
43 | ); |
|
49 | ); | |
44 | }; |
|
50 | }; | |
45 | }; |
|
51 | }; | |
46 |
|
52 | |||
47 |
|
53 | |||
48 | Kernel.prototype.restart = function (callback) { |
|
54 | Kernel.prototype.restart = function (callback) { | |
49 | IPython.kernel_status_widget.status_restarting(); |
|
55 | IPython.kernel_status_widget.status_restarting(); | |
50 | var url = this.kernel_url + "/restart"; |
|
56 | var url = this.kernel_url + "/restart"; | |
51 | var that = this; |
|
57 | var that = this; | |
52 | if (this.running) { |
|
58 | if (this.running) { | |
53 | this.stop_channels(); |
|
59 | this.stop_channels(); | |
54 | $.post(url, |
|
60 | $.post(url, | |
55 | function (kernel_id) { |
|
61 | function (kernel_id) { | |
56 | that._handle_start_kernel(kernel_id, callback); |
|
62 | that._handle_start_kernel(kernel_id, callback); | |
57 | }, |
|
63 | }, | |
58 | 'json' |
|
64 | 'json' | |
59 | ); |
|
65 | ); | |
60 | }; |
|
66 | }; | |
61 | }; |
|
67 | }; | |
62 |
|
68 | |||
63 |
|
69 | |||
64 | Kernel.prototype._handle_start_kernel = function (json, callback) { |
|
70 | Kernel.prototype._handle_start_kernel = function (json, callback) { | |
65 | this.running = true; |
|
71 | this.running = true; | |
66 | this.kernel_id = json.kernel_id; |
|
72 | this.kernel_id = json.kernel_id; | |
67 | this.ws_url = json.ws_url; |
|
73 | this.ws_url = json.ws_url; | |
68 | this.kernel_url = this.base_url + "/" + this.kernel_id; |
|
74 | this.kernel_url = this.base_url + "/" + this.kernel_id; | |
69 | this.start_channels(); |
|
75 | this.start_channels(); | |
70 | callback(); |
|
76 | callback(); | |
71 | IPython.kernel_status_widget.status_idle(); |
|
77 | IPython.kernel_status_widget.status_idle(); | |
72 | }; |
|
78 | }; | |
73 |
|
79 | |||
74 |
|
80 | |||
75 | Kernel.prototype.start_channels = function () { |
|
81 | Kernel.prototype.start_channels = function () { | |
76 | this.stop_channels(); |
|
82 | this.stop_channels(); | |
77 | var ws_url = this.ws_url + this.kernel_url; |
|
83 | var ws_url = this.ws_url + this.kernel_url; | |
78 | console.log("Starting WS:", ws_url); |
|
84 | console.log("Starting WS:", ws_url); | |
79 | this.shell_channel = new WebSocket(ws_url + "/shell"); |
|
85 | this.shell_channel = new WebSocket(ws_url + "/shell"); | |
80 | this.iopub_channel = new WebSocket(ws_url + "/iopub"); |
|
86 | this.iopub_channel = new WebSocket(ws_url + "/iopub"); | |
81 | }; |
|
87 | }; | |
82 |
|
88 | |||
83 |
|
89 | |||
84 | Kernel.prototype.stop_channels = function () { |
|
90 | Kernel.prototype.stop_channels = function () { | |
85 | if (this.shell_channel !== null) { |
|
91 | if (this.shell_channel !== null) { | |
86 | this.shell_channel.close(); |
|
92 | this.shell_channel.close(); | |
87 | this.shell_channel = null; |
|
93 | this.shell_channel = null; | |
88 | }; |
|
94 | }; | |
89 | if (this.iopub_channel !== null) { |
|
95 | if (this.iopub_channel !== null) { | |
90 | this.iopub_channel.close(); |
|
96 | this.iopub_channel.close(); | |
91 | this.iopub_channel = null; |
|
97 | this.iopub_channel = null; | |
92 | }; |
|
98 | }; | |
93 | }; |
|
99 | }; | |
94 |
|
100 | |||
95 | Kernel.prototype.execute = function (code) { |
|
101 | Kernel.prototype.execute = function (code) { | |
96 | var content = { |
|
102 | var content = { | |
97 | code : code, |
|
103 | code : code, | |
98 | silent : false, |
|
104 | silent : false, | |
99 | user_variables : [], |
|
105 | user_variables : [], | |
100 | user_expressions : {} |
|
106 | user_expressions : {} | |
101 | }; |
|
107 | }; | |
102 | var msg = this.get_msg("execute_request", content); |
|
108 | var msg = this.get_msg("execute_request", content); | |
103 | this.shell_channel.send(JSON.stringify(msg)); |
|
109 | this.shell_channel.send(JSON.stringify(msg)); | |
104 | return msg.header.msg_id; |
|
110 | return msg.header.msg_id; | |
105 | } |
|
111 | } | |
106 |
|
112 | |||
107 |
|
113 | |||
108 | Kernel.prototype.complete = function (line, cursor_pos) { |
|
114 | Kernel.prototype.complete = function (line, cursor_pos) { | |
109 | var content = { |
|
115 | var content = { | |
110 | text : '', |
|
116 | text : '', | |
111 | line : line, |
|
117 | line : line, | |
112 | cursor_pos : cursor_pos |
|
118 | cursor_pos : cursor_pos | |
113 | }; |
|
119 | }; | |
114 | var msg = this.get_msg("complete_request", content); |
|
120 | var msg = this.get_msg("complete_request", content); | |
115 | this.shell_channel.send(JSON.stringify(msg)); |
|
121 | this.shell_channel.send(JSON.stringify(msg)); | |
116 | return msg.header.msg_id; |
|
122 | return msg.header.msg_id; | |
117 | } |
|
123 | } | |
118 |
|
124 | |||
119 |
|
125 | |||
120 | Kernel.prototype.interrupt = function () { |
|
126 | Kernel.prototype.interrupt = function () { | |
121 | if (this.running) { |
|
127 | if (this.running) { | |
122 | $.post(this.kernel_url + "/interrupt"); |
|
128 | $.post(this.kernel_url + "/interrupt"); | |
123 | }; |
|
129 | }; | |
124 | }; |
|
130 | }; | |
125 |
|
131 | |||
126 |
|
132 | |||
127 | Kernel.prototype.kill = function () { |
|
133 | Kernel.prototype.kill = function () { | |
128 | if (this.running) { |
|
134 | if (this.running) { | |
129 | this.running = false; |
|
135 | this.running = false; | |
130 | var settings = { |
|
136 | var settings = { | |
131 | cache : false, |
|
137 | cache : false, | |
132 | type : "DELETE", |
|
138 | type : "DELETE", | |
133 | }; |
|
139 | }; | |
134 | $.ajax(this.kernel_url, settings); |
|
140 | $.ajax(this.kernel_url, settings); | |
135 | }; |
|
141 | }; | |
136 | }; |
|
142 | }; | |
137 |
|
143 | |||
138 | IPython.Kernel = Kernel; |
|
144 | IPython.Kernel = Kernel; | |
139 |
|
145 | |||
140 | return IPython; |
|
146 | return IPython; | |
141 |
|
147 | |||
142 | }(IPython)); |
|
148 | }(IPython)); | |
143 |
|
149 |
@@ -1,54 +1,60 b'' | |||||
|
1 | //---------------------------------------------------------------------------- | |||
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |||
|
3 | // | |||
|
4 | // Distributed under the terms of the BSD License. The full license is in | |||
|
5 | // the file COPYING, distributed as part of this software. | |||
|
6 | //---------------------------------------------------------------------------- | |||
1 |
|
|
7 | ||
2 | //============================================================================ |
|
8 | //============================================================================ | |
3 | // Kernel Status widget |
|
9 | // Kernel Status widget | |
4 | //============================================================================ |
|
10 | //============================================================================ | |
5 |
|
11 | |||
6 | var IPython = (function (IPython) { |
|
12 | var IPython = (function (IPython) { | |
7 |
|
13 | |||
8 | var utils = IPython.utils; |
|
14 | var utils = IPython.utils; | |
9 |
|
15 | |||
10 | var KernelStatusWidget = function (selector) { |
|
16 | var KernelStatusWidget = function (selector) { | |
11 | this.selector = selector; |
|
17 | this.selector = selector; | |
12 | if (this.selector !== undefined) { |
|
18 | if (this.selector !== undefined) { | |
13 | this.element = $(selector); |
|
19 | this.element = $(selector); | |
14 | this.style(); |
|
20 | this.style(); | |
15 | } |
|
21 | } | |
16 | }; |
|
22 | }; | |
17 |
|
23 | |||
18 |
|
24 | |||
19 | KernelStatusWidget.prototype.style = function () { |
|
25 | KernelStatusWidget.prototype.style = function () { | |
20 | this.element.addClass('ui-widget'); |
|
26 | this.element.addClass('ui-widget'); | |
21 | }; |
|
27 | }; | |
22 |
|
28 | |||
23 |
|
29 | |||
24 | KernelStatusWidget.prototype.status_busy = function () { |
|
30 | KernelStatusWidget.prototype.status_busy = function () { | |
25 | this.element.removeClass("status_idle"); |
|
31 | this.element.removeClass("status_idle"); | |
26 | this.element.removeClass("status_restarting"); |
|
32 | this.element.removeClass("status_restarting"); | |
27 | this.element.addClass("status_busy"); |
|
33 | this.element.addClass("status_busy"); | |
28 | this.element.text("Busy"); |
|
34 | this.element.text("Busy"); | |
29 | }; |
|
35 | }; | |
30 |
|
36 | |||
31 |
|
37 | |||
32 | KernelStatusWidget.prototype.status_idle = function () { |
|
38 | KernelStatusWidget.prototype.status_idle = function () { | |
33 | this.element.removeClass("status_busy"); |
|
39 | this.element.removeClass("status_busy"); | |
34 | this.element.removeClass("status_restarting"); |
|
40 | this.element.removeClass("status_restarting"); | |
35 | this.element.addClass("status_idle"); |
|
41 | this.element.addClass("status_idle"); | |
36 | this.element.text("Idle"); |
|
42 | this.element.text("Idle"); | |
37 | }; |
|
43 | }; | |
38 |
|
44 | |||
39 | KernelStatusWidget.prototype.status_restarting = function () { |
|
45 | KernelStatusWidget.prototype.status_restarting = function () { | |
40 | this.element.removeClass("status_busy"); |
|
46 | this.element.removeClass("status_busy"); | |
41 | this.element.removeClass("status_idle"); |
|
47 | this.element.removeClass("status_idle"); | |
42 | this.element.addClass("status_restarting"); |
|
48 | this.element.addClass("status_restarting"); | |
43 | this.element.text("Restarting"); |
|
49 | this.element.text("Restarting"); | |
44 | }; |
|
50 | }; | |
45 |
|
51 | |||
46 |
|
52 | |||
47 |
|
53 | |||
48 |
|
54 | |||
49 | IPython.KernelStatusWidget = KernelStatusWidget; |
|
55 | IPython.KernelStatusWidget = KernelStatusWidget; | |
50 |
|
56 | |||
51 | return IPython; |
|
57 | return IPython; | |
52 |
|
58 | |||
53 | }(IPython)); |
|
59 | }(IPython)); | |
54 |
|
60 |
@@ -1,55 +1,61 b'' | |||||
|
1 | //---------------------------------------------------------------------------- | |||
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |||
|
3 | // | |||
|
4 | // Distributed under the terms of the BSD License. The full license is in | |||
|
5 | // the file COPYING, distributed as part of this software. | |||
|
6 | //---------------------------------------------------------------------------- | |||
1 |
|
|
7 | ||
2 | //============================================================================ |
|
8 | //============================================================================ | |
3 | // Layout |
|
9 | // Layout | |
4 | //============================================================================ |
|
10 | //============================================================================ | |
5 |
|
11 | |||
6 | var IPython = (function (IPython) { |
|
12 | var IPython = (function (IPython) { | |
7 |
|
13 | |||
8 | var LayoutManager = function () { |
|
14 | var LayoutManager = function () { | |
9 | this.bind_events(); |
|
15 | this.bind_events(); | |
10 | }; |
|
16 | }; | |
11 |
|
17 | |||
12 |
|
18 | |||
13 | LayoutManager.prototype.bind_events = function () { |
|
19 | LayoutManager.prototype.bind_events = function () { | |
14 | $(window).resize($.proxy(this.do_resize,this)); |
|
20 | $(window).resize($.proxy(this.do_resize,this)); | |
15 | }; |
|
21 | }; | |
16 |
|
22 | |||
17 |
|
23 | |||
18 | LayoutManager.prototype.do_resize = function () { |
|
24 | LayoutManager.prototype.do_resize = function () { | |
19 | var win = $(window); |
|
25 | var win = $(window); | |
20 | var w = win.width(); |
|
26 | var w = win.width(); | |
21 | var h = win.height(); |
|
27 | var h = win.height(); | |
22 | var header_height = $('div#header').outerHeight(true); |
|
28 | var header_height = $('div#header').outerHeight(true); | |
23 | var app_height = h - header_height - 2; // content height |
|
29 | var app_height = h - header_height - 2; // content height | |
24 |
|
30 | |||
25 | $('div#main_app').height(app_height + 2); // content+padding+border height |
|
31 | $('div#main_app').height(app_height + 2); // content+padding+border height | |
26 |
|
32 | |||
27 | $('div#left_panel').height(app_height); |
|
33 | $('div#left_panel').height(app_height); | |
28 |
|
34 | |||
29 | $('div#left_panel_splitter').height(app_height); |
|
35 | $('div#left_panel_splitter').height(app_height); | |
30 |
|
36 | |||
31 | $('div#notebook_panel').height(app_height); |
|
37 | $('div#notebook_panel').height(app_height); | |
32 | var left_panel_width = $('div#left_panel').outerWidth(); |
|
38 | var left_panel_width = $('div#left_panel').outerWidth(); | |
33 | var left_panel_splitter_width = $('div#left_panel_splitter').outerWidth(); |
|
39 | var left_panel_splitter_width = $('div#left_panel_splitter').outerWidth(); | |
34 | if (IPython.left_panel.expanded) { |
|
40 | if (IPython.left_panel.expanded) { | |
35 | $('div#notebook_panel').css({marginLeft : left_panel_width+left_panel_splitter_width}); |
|
41 | $('div#notebook_panel').css({marginLeft : left_panel_width+left_panel_splitter_width}); | |
36 | } else { |
|
42 | } else { | |
37 | $('div#notebook_panel').css({marginLeft : left_panel_splitter_width}); |
|
43 | $('div#notebook_panel').css({marginLeft : left_panel_splitter_width}); | |
38 | } |
|
44 | } | |
39 |
|
45 | |||
40 |
|
46 | |||
41 | var pager_height = IPython.pager.percentage_height*app_height; |
|
47 | var pager_height = IPython.pager.percentage_height*app_height; | |
42 | var pager_splitter_height = $('div#pager_splitter').outerHeight(true); |
|
48 | var pager_splitter_height = $('div#pager_splitter').outerHeight(true); | |
43 | $('div#pager').height(pager_height); |
|
49 | $('div#pager').height(pager_height); | |
44 | if (IPython.pager.expanded) { |
|
50 | if (IPython.pager.expanded) { | |
45 | $('div#notebook').height(app_height-pager_height-pager_splitter_height); |
|
51 | $('div#notebook').height(app_height-pager_height-pager_splitter_height); | |
46 | } else { |
|
52 | } else { | |
47 | $('div#notebook').height(app_height-pager_splitter_height); |
|
53 | $('div#notebook').height(app_height-pager_splitter_height); | |
48 | } |
|
54 | } | |
49 | }; |
|
55 | }; | |
50 |
|
56 | |||
51 | IPython.LayoutManager = LayoutManager |
|
57 | IPython.LayoutManager = LayoutManager | |
52 |
|
58 | |||
53 | return IPython; |
|
59 | return IPython; | |
54 |
|
60 | |||
55 | }(IPython)); |
|
61 | }(IPython)); |
@@ -1,95 +1,101 b'' | |||||
|
1 | //---------------------------------------------------------------------------- | |||
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |||
|
3 | // | |||
|
4 | // Distributed under the terms of the BSD License. The full license is in | |||
|
5 | // the file COPYING, distributed as part of this software. | |||
|
6 | //---------------------------------------------------------------------------- | |||
1 |
|
|
7 | ||
2 | //============================================================================ |
|
8 | //============================================================================ | |
3 | // LeftPanel |
|
9 | // LeftPanel | |
4 | //============================================================================ |
|
10 | //============================================================================ | |
5 |
|
11 | |||
6 |
|
12 | |||
7 | var IPython = (function (IPython) { |
|
13 | var IPython = (function (IPython) { | |
8 |
|
14 | |||
9 | var utils = IPython.utils; |
|
15 | var utils = IPython.utils; | |
10 |
|
16 | |||
11 | var LeftPanel = function (left_panel_selector, left_panel_splitter_selector) { |
|
17 | var LeftPanel = function (left_panel_selector, left_panel_splitter_selector) { | |
12 | this.left_panel_element = $(left_panel_selector); |
|
18 | this.left_panel_element = $(left_panel_selector); | |
13 | this.left_panel_splitter_element = $(left_panel_splitter_selector); |
|
19 | this.left_panel_splitter_element = $(left_panel_splitter_selector); | |
14 | this.expanded = true; |
|
20 | this.expanded = true; | |
15 | this.width = 300; |
|
21 | this.width = 300; | |
16 | this.style(); |
|
22 | this.style(); | |
17 | this.bind_events(); |
|
23 | this.bind_events(); | |
18 | this.create_children(); |
|
24 | this.create_children(); | |
19 | }; |
|
25 | }; | |
20 |
|
26 | |||
21 |
|
27 | |||
22 | LeftPanel.prototype.style = function () { |
|
28 | LeftPanel.prototype.style = function () { | |
23 | this.left_panel_splitter_element.addClass('border-box-sizing ui-widget ui-state-default'); |
|
29 | this.left_panel_splitter_element.addClass('border-box-sizing ui-widget ui-state-default'); | |
24 | this.left_panel_element.addClass('border-box-sizing ui-widget'); |
|
30 | this.left_panel_element.addClass('border-box-sizing ui-widget'); | |
25 | this.left_panel_element.width(this.width); |
|
31 | this.left_panel_element.width(this.width); | |
26 | this.left_panel_splitter_element.css({left : this.width}); |
|
32 | this.left_panel_splitter_element.css({left : this.width}); | |
27 | }; |
|
33 | }; | |
28 |
|
34 | |||
29 |
|
35 | |||
30 | LeftPanel.prototype.bind_events = function () { |
|
36 | LeftPanel.prototype.bind_events = function () { | |
31 | var that = this; |
|
37 | var that = this; | |
32 |
|
38 | |||
33 | this.left_panel_element.bind('collapse_left_panel', function () { |
|
39 | this.left_panel_element.bind('collapse_left_panel', function () { | |
34 | that.left_panel_element.hide('fast'); |
|
40 | that.left_panel_element.hide('fast'); | |
35 | that.left_panel_splitter_element.animate({left : 0}, 'fast'); |
|
41 | that.left_panel_splitter_element.animate({left : 0}, 'fast'); | |
36 | }); |
|
42 | }); | |
37 |
|
43 | |||
38 | this.left_panel_element.bind('expand_left_panel', function () { |
|
44 | this.left_panel_element.bind('expand_left_panel', function () { | |
39 | that.left_panel_element.show('fast'); |
|
45 | that.left_panel_element.show('fast'); | |
40 | that.left_panel_splitter_element.animate({left : that.width}, 'fast'); |
|
46 | that.left_panel_splitter_element.animate({left : that.width}, 'fast'); | |
41 | }); |
|
47 | }); | |
42 |
|
48 | |||
43 | this.left_panel_splitter_element.hover( |
|
49 | this.left_panel_splitter_element.hover( | |
44 | function () { |
|
50 | function () { | |
45 | that.left_panel_splitter_element.addClass('ui-state-hover'); |
|
51 | that.left_panel_splitter_element.addClass('ui-state-hover'); | |
46 | }, |
|
52 | }, | |
47 | function () { |
|
53 | function () { | |
48 | that.left_panel_splitter_element.removeClass('ui-state-hover'); |
|
54 | that.left_panel_splitter_element.removeClass('ui-state-hover'); | |
49 | } |
|
55 | } | |
50 | ); |
|
56 | ); | |
51 |
|
57 | |||
52 | this.left_panel_splitter_element.click(function () { |
|
58 | this.left_panel_splitter_element.click(function () { | |
53 | that.toggle(); |
|
59 | that.toggle(); | |
54 | }); |
|
60 | }); | |
55 |
|
61 | |||
56 | }; |
|
62 | }; | |
57 |
|
63 | |||
58 |
|
64 | |||
59 | LeftPanel.prototype.create_children = function () { |
|
65 | LeftPanel.prototype.create_children = function () { | |
60 | this.notebook_section = new IPython.NotebookSection('div#notebook_section'); |
|
66 | this.notebook_section = new IPython.NotebookSection('div#notebook_section'); | |
61 | this.cell_section = new IPython.CellSection('div#cell_section'); |
|
67 | this.cell_section = new IPython.CellSection('div#cell_section'); | |
62 | this.kernel_section = new IPython.KernelSection('div#kernel_section'); |
|
68 | this.kernel_section = new IPython.KernelSection('div#kernel_section'); | |
63 | this.help_section = new IPython.HelpSection('div#help_section'); |
|
69 | this.help_section = new IPython.HelpSection('div#help_section'); | |
64 | } |
|
70 | } | |
65 |
|
71 | |||
66 | LeftPanel.prototype.collapse = function () { |
|
72 | LeftPanel.prototype.collapse = function () { | |
67 | if (this.expanded === true) { |
|
73 | if (this.expanded === true) { | |
68 | this.left_panel_element.add($('div#notebook')).trigger('collapse_left_panel'); |
|
74 | this.left_panel_element.add($('div#notebook')).trigger('collapse_left_panel'); | |
69 | this.expanded = false; |
|
75 | this.expanded = false; | |
70 | }; |
|
76 | }; | |
71 | }; |
|
77 | }; | |
72 |
|
78 | |||
73 |
|
79 | |||
74 | LeftPanel.prototype.expand = function () { |
|
80 | LeftPanel.prototype.expand = function () { | |
75 | if (this.expanded !== true) { |
|
81 | if (this.expanded !== true) { | |
76 | this.left_panel_element.add($('div#notebook')).trigger('expand_left_panel'); |
|
82 | this.left_panel_element.add($('div#notebook')).trigger('expand_left_panel'); | |
77 | this.expanded = true; |
|
83 | this.expanded = true; | |
78 | }; |
|
84 | }; | |
79 | }; |
|
85 | }; | |
80 |
|
86 | |||
81 |
|
87 | |||
82 | LeftPanel.prototype.toggle = function () { |
|
88 | LeftPanel.prototype.toggle = function () { | |
83 | if (this.expanded === true) { |
|
89 | if (this.expanded === true) { | |
84 | this.collapse(); |
|
90 | this.collapse(); | |
85 | } else { |
|
91 | } else { | |
86 | this.expand(); |
|
92 | this.expand(); | |
87 | }; |
|
93 | }; | |
88 | }; |
|
94 | }; | |
89 |
|
95 | |||
90 | IPython.LeftPanel = LeftPanel; |
|
96 | IPython.LeftPanel = LeftPanel; | |
91 |
|
97 | |||
92 | return IPython; |
|
98 | return IPython; | |
93 |
|
99 | |||
94 | }(IPython)); |
|
100 | }(IPython)); | |
95 |
|
101 |
@@ -1,23 +1,30 b'' | |||||
|
1 | //---------------------------------------------------------------------------- | |||
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |||
|
3 | // | |||
|
4 | // Distributed under the terms of the BSD License. The full license is in | |||
|
5 | // the file COPYING, distributed as part of this software. | |||
|
6 | //---------------------------------------------------------------------------- | |||
|
7 | ||||
1 | var IPython = IPython || {}; |
|
8 | var IPython = IPython || {}; | |
2 |
|
9 | |||
3 | IPython.namespace = function (ns_string) { |
|
10 | IPython.namespace = function (ns_string) { | |
4 | var parts = ns_string.split('.'), |
|
11 | var parts = ns_string.split('.'), | |
5 | parent = IPython, |
|
12 | parent = IPython, | |
6 | i; |
|
13 | i; | |
7 |
|
14 | |||
8 | // String redundant leading global |
|
15 | // String redundant leading global | |
9 | if (parts[0] === "IPython") { |
|
16 | if (parts[0] === "IPython") { | |
10 | parts = parts.slice(1); |
|
17 | parts = parts.slice(1); | |
11 | } |
|
18 | } | |
12 |
|
19 | |||
13 | for (i=0; i<parts.length; i+=1) { |
|
20 | for (i=0; i<parts.length; i+=1) { | |
14 | // Create property if it doesn't exist |
|
21 | // Create property if it doesn't exist | |
15 | if (typeof parent[parts[i]] === "undefined") { |
|
22 | if (typeof parent[parts[i]] === "undefined") { | |
16 | parent[parts[i]] == {}; |
|
23 | parent[parts[i]] == {}; | |
17 | } |
|
24 | } | |
18 | } |
|
25 | } | |
19 | return parent; |
|
26 | return parent; | |
20 | }; |
|
27 | }; | |
21 |
|
28 | |||
22 |
|
29 | |||
23 |
|
30 |
@@ -1,33 +1,39 b'' | |||||
|
1 | //---------------------------------------------------------------------------- | |||
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |||
|
3 | // | |||
|
4 | // Distributed under the terms of the BSD License. The full license is in | |||
|
5 | // the file COPYING, distributed as part of this software. | |||
|
6 | //---------------------------------------------------------------------------- | |||
1 |
|
|
7 | ||
2 | //============================================================================ |
|
8 | //============================================================================ | |
3 | // On document ready |
|
9 | // On document ready | |
4 | //============================================================================ |
|
10 | //============================================================================ | |
5 |
|
11 | |||
6 |
|
12 | |||
7 | $(document).ready(function () { |
|
13 | $(document).ready(function () { | |
8 |
|
14 | |||
9 | $('div#header').addClass('border-box-sizing'); |
|
15 | $('div#header').addClass('border-box-sizing'); | |
10 | $('div#header_border').addClass('border-box-sizing ui-widget ui-widget-content'); |
|
16 | $('div#header_border').addClass('border-box-sizing ui-widget ui-widget-content'); | |
11 |
|
17 | |||
12 | $('div#main_app').addClass('border-box-sizing ui-widget'); |
|
18 | $('div#main_app').addClass('border-box-sizing ui-widget'); | |
13 | $('div#app_hbox').addClass('hbox'); |
|
19 | $('div#app_hbox').addClass('hbox'); | |
14 |
|
20 | |||
15 | $('div#content_toolbar').addClass('ui-widget ui-helper-clearfix'); |
|
21 | $('div#content_toolbar').addClass('ui-widget ui-helper-clearfix'); | |
16 |
|
22 | |||
17 | $('#new_notebook').button().click(function (e) { |
|
23 | $('#new_notebook').button().click(function (e) { | |
18 | window.open('/new'); |
|
24 | window.open('/new'); | |
19 | }); |
|
25 | }); | |
20 |
|
26 | |||
21 | $('div#left_panel').addClass('box-flex'); |
|
27 | $('div#left_panel').addClass('box-flex'); | |
22 | $('div#right_panel').addClass('box-flex'); |
|
28 | $('div#right_panel').addClass('box-flex'); | |
23 |
|
29 | |||
24 | IPython.notebook_list = new IPython.NotebookList('div#notebook_list'); |
|
30 | IPython.notebook_list = new IPython.NotebookList('div#notebook_list'); | |
25 | IPython.notebook_list.load_list(); |
|
31 | IPython.notebook_list.load_list(); | |
26 |
|
32 | |||
27 | // These have display: none in the css file and are made visible here to prevent FLOUC. |
|
33 | // These have display: none in the css file and are made visible here to prevent FLOUC. | |
28 | $('div#header').css('display','block'); |
|
34 | $('div#header').css('display','block'); | |
29 | $('div#main_app').css('display','block'); |
|
35 | $('div#main_app').css('display','block'); | |
30 |
|
36 | |||
31 |
|
37 | |||
32 | }); |
|
38 | }); | |
33 |
|
39 |
@@ -1,813 +1,819 b'' | |||||
|
1 | //---------------------------------------------------------------------------- | |||
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |||
|
3 | // | |||
|
4 | // Distributed under the terms of the BSD License. The full license is in | |||
|
5 | // the file COPYING, distributed as part of this software. | |||
|
6 | //---------------------------------------------------------------------------- | |||
1 |
|
|
7 | ||
2 | //============================================================================ |
|
8 | //============================================================================ | |
3 | // Notebook |
|
9 | // Notebook | |
4 | //============================================================================ |
|
10 | //============================================================================ | |
5 |
|
11 | |||
6 | var IPython = (function (IPython) { |
|
12 | var IPython = (function (IPython) { | |
7 |
|
13 | |||
8 | var utils = IPython.utils; |
|
14 | var utils = IPython.utils; | |
9 |
|
15 | |||
10 | var Notebook = function (selector) { |
|
16 | var Notebook = function (selector) { | |
11 | this.element = $(selector); |
|
17 | this.element = $(selector); | |
12 | this.element.scroll(); |
|
18 | this.element.scroll(); | |
13 | this.element.data("notebook", this); |
|
19 | this.element.data("notebook", this); | |
14 | this.next_prompt_number = 1; |
|
20 | this.next_prompt_number = 1; | |
15 | this.kernel = null; |
|
21 | this.kernel = null; | |
16 | this.dirty = false; |
|
22 | this.dirty = false; | |
17 | this.msg_cell_map = {}; |
|
23 | this.msg_cell_map = {}; | |
18 | this.style(); |
|
24 | this.style(); | |
19 | this.create_elements(); |
|
25 | this.create_elements(); | |
20 | this.bind_events(); |
|
26 | this.bind_events(); | |
21 | }; |
|
27 | }; | |
22 |
|
28 | |||
23 |
|
29 | |||
24 | Notebook.prototype.style = function () { |
|
30 | Notebook.prototype.style = function () { | |
25 | $('div#notebook').addClass('border-box-sizing'); |
|
31 | $('div#notebook').addClass('border-box-sizing'); | |
26 | }; |
|
32 | }; | |
27 |
|
33 | |||
28 |
|
34 | |||
29 | Notebook.prototype.create_elements = function () { |
|
35 | Notebook.prototype.create_elements = function () { | |
30 | // We add this end_space div to the end of the notebook div to: |
|
36 | // We add this end_space div to the end of the notebook div to: | |
31 | // i) provide a margin between the last cell and the end of the notebook |
|
37 | // i) provide a margin between the last cell and the end of the notebook | |
32 | // ii) to prevent the div from scrolling up when the last cell is being |
|
38 | // ii) to prevent the div from scrolling up when the last cell is being | |
33 | // edited, but is too low on the page, which browsers will do automatically. |
|
39 | // edited, but is too low on the page, which browsers will do automatically. | |
34 | var end_space = $('<div class="end_space"></div>').height(150); |
|
40 | var end_space = $('<div class="end_space"></div>').height(150); | |
35 | this.element.append(end_space); |
|
41 | this.element.append(end_space); | |
36 | $('div#notebook').addClass('border-box-sizing'); |
|
42 | $('div#notebook').addClass('border-box-sizing'); | |
37 | }; |
|
43 | }; | |
38 |
|
44 | |||
39 |
|
45 | |||
40 | Notebook.prototype.bind_events = function () { |
|
46 | Notebook.prototype.bind_events = function () { | |
41 | var that = this; |
|
47 | var that = this; | |
42 | $(document).keydown(function (event) { |
|
48 | $(document).keydown(function (event) { | |
43 | // console.log(event); |
|
49 | // console.log(event); | |
44 | if (event.which === 38) { |
|
50 | if (event.which === 38) { | |
45 | var cell = that.selected_cell(); |
|
51 | var cell = that.selected_cell(); | |
46 | if (cell.at_top()) { |
|
52 | if (cell.at_top()) { | |
47 | event.preventDefault(); |
|
53 | event.preventDefault(); | |
48 | that.select_prev(); |
|
54 | that.select_prev(); | |
49 | }; |
|
55 | }; | |
50 | } else if (event.which === 40) { |
|
56 | } else if (event.which === 40) { | |
51 | var cell = that.selected_cell(); |
|
57 | var cell = that.selected_cell(); | |
52 | if (cell.at_bottom()) { |
|
58 | if (cell.at_bottom()) { | |
53 | event.preventDefault(); |
|
59 | event.preventDefault(); | |
54 | that.select_next(); |
|
60 | that.select_next(); | |
55 | }; |
|
61 | }; | |
56 | } else if (event.which === 13 && event.shiftKey) { |
|
62 | } else if (event.which === 13 && event.shiftKey) { | |
57 | that.execute_selected_cell(); |
|
63 | that.execute_selected_cell(); | |
58 | return false; |
|
64 | return false; | |
59 | } else if (event.which === 13 && event.ctrlKey) { |
|
65 | } else if (event.which === 13 && event.ctrlKey) { | |
60 | that.execute_selected_cell({terminal:true}); |
|
66 | that.execute_selected_cell({terminal:true}); | |
61 | return false; |
|
67 | return false; | |
62 | }; |
|
68 | }; | |
63 | }); |
|
69 | }); | |
64 |
|
70 | |||
65 | this.element.bind('collapse_pager', function () { |
|
71 | this.element.bind('collapse_pager', function () { | |
66 | var app_height = $('div#main_app').height(); // content height |
|
72 | var app_height = $('div#main_app').height(); // content height | |
67 | var splitter_height = $('div#pager_splitter').outerHeight(true); |
|
73 | var splitter_height = $('div#pager_splitter').outerHeight(true); | |
68 | var new_height = app_height - splitter_height; |
|
74 | var new_height = app_height - splitter_height; | |
69 | that.element.animate({height : new_height + 'px'}, 'fast'); |
|
75 | that.element.animate({height : new_height + 'px'}, 'fast'); | |
70 | }); |
|
76 | }); | |
71 |
|
77 | |||
72 | this.element.bind('expand_pager', function () { |
|
78 | this.element.bind('expand_pager', function () { | |
73 | var app_height = $('div#main_app').height(); // content height |
|
79 | var app_height = $('div#main_app').height(); // content height | |
74 | var splitter_height = $('div#pager_splitter').outerHeight(true); |
|
80 | var splitter_height = $('div#pager_splitter').outerHeight(true); | |
75 | var pager_height = $('div#pager').outerHeight(true); |
|
81 | var pager_height = $('div#pager').outerHeight(true); | |
76 | var new_height = app_height - pager_height - splitter_height; |
|
82 | var new_height = app_height - pager_height - splitter_height; | |
77 | that.element.animate({height : new_height + 'px'}, 'fast'); |
|
83 | that.element.animate({height : new_height + 'px'}, 'fast'); | |
78 | }); |
|
84 | }); | |
79 |
|
85 | |||
80 | this.element.bind('collapse_left_panel', function () { |
|
86 | this.element.bind('collapse_left_panel', function () { | |
81 | var splitter_width = $('div#left_panel_splitter').outerWidth(true); |
|
87 | var splitter_width = $('div#left_panel_splitter').outerWidth(true); | |
82 | var new_margin = splitter_width; |
|
88 | var new_margin = splitter_width; | |
83 | $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast'); |
|
89 | $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast'); | |
84 | }); |
|
90 | }); | |
85 |
|
91 | |||
86 | this.element.bind('expand_left_panel', function () { |
|
92 | this.element.bind('expand_left_panel', function () { | |
87 | var splitter_width = $('div#left_panel_splitter').outerWidth(true); |
|
93 | var splitter_width = $('div#left_panel_splitter').outerWidth(true); | |
88 | var left_panel_width = IPython.left_panel.width; |
|
94 | var left_panel_width = IPython.left_panel.width; | |
89 | var new_margin = splitter_width + left_panel_width; |
|
95 | var new_margin = splitter_width + left_panel_width; | |
90 | $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast'); |
|
96 | $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast'); | |
91 | }); |
|
97 | }); | |
92 |
|
98 | |||
93 | $(window).bind('beforeunload', function () { |
|
99 | $(window).bind('beforeunload', function () { | |
94 | var kill_kernel = $('#kill_kernel').prop('checked'); |
|
100 | var kill_kernel = $('#kill_kernel').prop('checked'); | |
95 | if (kill_kernel) { |
|
101 | if (kill_kernel) { | |
96 | that.kernel.kill(); |
|
102 | that.kernel.kill(); | |
97 | } |
|
103 | } | |
98 | if (that.dirty) { |
|
104 | if (that.dirty) { | |
99 | return "You have unsaved changes that will be lost if you leave this page."; |
|
105 | return "You have unsaved changes that will be lost if you leave this page."; | |
100 | }; |
|
106 | }; | |
101 | }); |
|
107 | }); | |
102 | }; |
|
108 | }; | |
103 |
|
109 | |||
104 |
|
110 | |||
105 | Notebook.prototype.scroll_to_bottom = function () { |
|
111 | Notebook.prototype.scroll_to_bottom = function () { | |
106 | this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0); |
|
112 | this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0); | |
107 | }; |
|
113 | }; | |
108 |
|
114 | |||
109 |
|
115 | |||
110 | Notebook.prototype.scroll_to_top = function () { |
|
116 | Notebook.prototype.scroll_to_top = function () { | |
111 | this.element.animate({scrollTop:0}, 0); |
|
117 | this.element.animate({scrollTop:0}, 0); | |
112 | }; |
|
118 | }; | |
113 |
|
119 | |||
114 |
|
120 | |||
115 | // Cell indexing, retrieval, etc. |
|
121 | // Cell indexing, retrieval, etc. | |
116 |
|
122 | |||
117 |
|
123 | |||
118 | Notebook.prototype.cell_elements = function () { |
|
124 | Notebook.prototype.cell_elements = function () { | |
119 | return this.element.children("div.cell"); |
|
125 | return this.element.children("div.cell"); | |
120 | } |
|
126 | } | |
121 |
|
127 | |||
122 |
|
128 | |||
123 | Notebook.prototype.ncells = function (cell) { |
|
129 | Notebook.prototype.ncells = function (cell) { | |
124 | return this.cell_elements().length; |
|
130 | return this.cell_elements().length; | |
125 | } |
|
131 | } | |
126 |
|
132 | |||
127 |
|
133 | |||
128 | // TODO: we are often calling cells as cells()[i], which we should optimize |
|
134 | // TODO: we are often calling cells as cells()[i], which we should optimize | |
129 | // to cells(i) or a new method. |
|
135 | // to cells(i) or a new method. | |
130 | Notebook.prototype.cells = function () { |
|
136 | Notebook.prototype.cells = function () { | |
131 | return this.cell_elements().toArray().map(function (e) { |
|
137 | return this.cell_elements().toArray().map(function (e) { | |
132 | return $(e).data("cell"); |
|
138 | return $(e).data("cell"); | |
133 | }); |
|
139 | }); | |
134 | } |
|
140 | } | |
135 |
|
141 | |||
136 |
|
142 | |||
137 | Notebook.prototype.find_cell_index = function (cell) { |
|
143 | Notebook.prototype.find_cell_index = function (cell) { | |
138 | var result = null; |
|
144 | var result = null; | |
139 | this.cell_elements().filter(function (index) { |
|
145 | this.cell_elements().filter(function (index) { | |
140 | if ($(this).data("cell") === cell) { |
|
146 | if ($(this).data("cell") === cell) { | |
141 | result = index; |
|
147 | result = index; | |
142 | }; |
|
148 | }; | |
143 | }); |
|
149 | }); | |
144 | return result; |
|
150 | return result; | |
145 | }; |
|
151 | }; | |
146 |
|
152 | |||
147 |
|
153 | |||
148 | Notebook.prototype.index_or_selected = function (index) { |
|
154 | Notebook.prototype.index_or_selected = function (index) { | |
149 | return index || this.selected_index() || 0; |
|
155 | return index || this.selected_index() || 0; | |
150 | } |
|
156 | } | |
151 |
|
157 | |||
152 |
|
158 | |||
153 | Notebook.prototype.select = function (index) { |
|
159 | Notebook.prototype.select = function (index) { | |
154 | if (index !== undefined && index >= 0 && index < this.ncells()) { |
|
160 | if (index !== undefined && index >= 0 && index < this.ncells()) { | |
155 | if (this.selected_index() !== null) { |
|
161 | if (this.selected_index() !== null) { | |
156 | this.selected_cell().unselect(); |
|
162 | this.selected_cell().unselect(); | |
157 | }; |
|
163 | }; | |
158 | this.cells()[index].select(); |
|
164 | this.cells()[index].select(); | |
159 | }; |
|
165 | }; | |
160 | return this; |
|
166 | return this; | |
161 | }; |
|
167 | }; | |
162 |
|
168 | |||
163 |
|
169 | |||
164 | Notebook.prototype.select_next = function () { |
|
170 | Notebook.prototype.select_next = function () { | |
165 | var index = this.selected_index(); |
|
171 | var index = this.selected_index(); | |
166 | if (index !== null && index >= 0 && (index+1) < this.ncells()) { |
|
172 | if (index !== null && index >= 0 && (index+1) < this.ncells()) { | |
167 | this.select(index+1); |
|
173 | this.select(index+1); | |
168 | }; |
|
174 | }; | |
169 | return this; |
|
175 | return this; | |
170 | }; |
|
176 | }; | |
171 |
|
177 | |||
172 |
|
178 | |||
173 | Notebook.prototype.select_prev = function () { |
|
179 | Notebook.prototype.select_prev = function () { | |
174 | var index = this.selected_index(); |
|
180 | var index = this.selected_index(); | |
175 | if (index !== null && index >= 0 && (index-1) < this.ncells()) { |
|
181 | if (index !== null && index >= 0 && (index-1) < this.ncells()) { | |
176 | this.select(index-1); |
|
182 | this.select(index-1); | |
177 | }; |
|
183 | }; | |
178 | return this; |
|
184 | return this; | |
179 | }; |
|
185 | }; | |
180 |
|
186 | |||
181 |
|
187 | |||
182 | Notebook.prototype.selected_index = function () { |
|
188 | Notebook.prototype.selected_index = function () { | |
183 | var result = null; |
|
189 | var result = null; | |
184 | this.cell_elements().filter(function (index) { |
|
190 | this.cell_elements().filter(function (index) { | |
185 | if ($(this).data("cell").selected === true) { |
|
191 | if ($(this).data("cell").selected === true) { | |
186 | result = index; |
|
192 | result = index; | |
187 | }; |
|
193 | }; | |
188 | }); |
|
194 | }); | |
189 | return result; |
|
195 | return result; | |
190 | }; |
|
196 | }; | |
191 |
|
197 | |||
192 |
|
198 | |||
193 | Notebook.prototype.cell_for_msg = function (msg_id) { |
|
199 | Notebook.prototype.cell_for_msg = function (msg_id) { | |
194 | var cell_id = this.msg_cell_map[msg_id]; |
|
200 | var cell_id = this.msg_cell_map[msg_id]; | |
195 | var result = null; |
|
201 | var result = null; | |
196 | this.cell_elements().filter(function (index) { |
|
202 | this.cell_elements().filter(function (index) { | |
197 | cell = $(this).data("cell"); |
|
203 | cell = $(this).data("cell"); | |
198 | if (cell.cell_id === cell_id) { |
|
204 | if (cell.cell_id === cell_id) { | |
199 | result = cell; |
|
205 | result = cell; | |
200 | }; |
|
206 | }; | |
201 | }); |
|
207 | }); | |
202 | return result; |
|
208 | return result; | |
203 | }; |
|
209 | }; | |
204 |
|
210 | |||
205 |
|
211 | |||
206 | Notebook.prototype.selected_cell = function () { |
|
212 | Notebook.prototype.selected_cell = function () { | |
207 | return this.cell_elements().eq(this.selected_index()).data("cell"); |
|
213 | return this.cell_elements().eq(this.selected_index()).data("cell"); | |
208 | } |
|
214 | } | |
209 |
|
215 | |||
210 |
|
216 | |||
211 | // Cell insertion, deletion and moving. |
|
217 | // Cell insertion, deletion and moving. | |
212 |
|
218 | |||
213 |
|
219 | |||
214 | Notebook.prototype.delete_cell = function (index) { |
|
220 | Notebook.prototype.delete_cell = function (index) { | |
215 | var i = index || this.selected_index(); |
|
221 | var i = index || this.selected_index(); | |
216 | if (i !== null && i >= 0 && i < this.ncells()) { |
|
222 | if (i !== null && i >= 0 && i < this.ncells()) { | |
217 | this.cell_elements().eq(i).remove(); |
|
223 | this.cell_elements().eq(i).remove(); | |
218 | if (i === (this.ncells())) { |
|
224 | if (i === (this.ncells())) { | |
219 | this.select(i-1); |
|
225 | this.select(i-1); | |
220 | } else { |
|
226 | } else { | |
221 | this.select(i); |
|
227 | this.select(i); | |
222 | }; |
|
228 | }; | |
223 | }; |
|
229 | }; | |
224 | this.dirty = true; |
|
230 | this.dirty = true; | |
225 | return this; |
|
231 | return this; | |
226 | }; |
|
232 | }; | |
227 |
|
233 | |||
228 |
|
234 | |||
229 | Notebook.prototype.append_cell = function (cell) { |
|
235 | Notebook.prototype.append_cell = function (cell) { | |
230 | this.element.find('div.end_space').before(cell.element); |
|
236 | this.element.find('div.end_space').before(cell.element); | |
231 | this.dirty = true; |
|
237 | this.dirty = true; | |
232 | return this; |
|
238 | return this; | |
233 | }; |
|
239 | }; | |
234 |
|
240 | |||
235 |
|
241 | |||
236 | Notebook.prototype.insert_cell_after = function (cell, index) { |
|
242 | Notebook.prototype.insert_cell_after = function (cell, index) { | |
237 | var ncells = this.ncells(); |
|
243 | var ncells = this.ncells(); | |
238 | if (ncells === 0) { |
|
244 | if (ncells === 0) { | |
239 | this.append_cell(cell); |
|
245 | this.append_cell(cell); | |
240 | return this; |
|
246 | return this; | |
241 | }; |
|
247 | }; | |
242 | if (index >= 0 && index < ncells) { |
|
248 | if (index >= 0 && index < ncells) { | |
243 | this.cell_elements().eq(index).after(cell.element); |
|
249 | this.cell_elements().eq(index).after(cell.element); | |
244 | }; |
|
250 | }; | |
245 | this.dirty = true; |
|
251 | this.dirty = true; | |
246 | return this |
|
252 | return this | |
247 | }; |
|
253 | }; | |
248 |
|
254 | |||
249 |
|
255 | |||
250 | Notebook.prototype.insert_cell_before = function (cell, index) { |
|
256 | Notebook.prototype.insert_cell_before = function (cell, index) { | |
251 | var ncells = this.ncells(); |
|
257 | var ncells = this.ncells(); | |
252 | if (ncells === 0) { |
|
258 | if (ncells === 0) { | |
253 | this.append_cell(cell); |
|
259 | this.append_cell(cell); | |
254 | return this; |
|
260 | return this; | |
255 | }; |
|
261 | }; | |
256 | if (index >= 0 && index < ncells) { |
|
262 | if (index >= 0 && index < ncells) { | |
257 | this.cell_elements().eq(index).before(cell.element); |
|
263 | this.cell_elements().eq(index).before(cell.element); | |
258 | }; |
|
264 | }; | |
259 | this.dirty = true; |
|
265 | this.dirty = true; | |
260 | return this; |
|
266 | return this; | |
261 | }; |
|
267 | }; | |
262 |
|
268 | |||
263 |
|
269 | |||
264 | Notebook.prototype.move_cell_up = function (index) { |
|
270 | Notebook.prototype.move_cell_up = function (index) { | |
265 | var i = index || this.selected_index(); |
|
271 | var i = index || this.selected_index(); | |
266 | if (i !== null && i < this.ncells() && i > 0) { |
|
272 | if (i !== null && i < this.ncells() && i > 0) { | |
267 | var pivot = this.cell_elements().eq(i-1); |
|
273 | var pivot = this.cell_elements().eq(i-1); | |
268 | var tomove = this.cell_elements().eq(i); |
|
274 | var tomove = this.cell_elements().eq(i); | |
269 | if (pivot !== null && tomove !== null) { |
|
275 | if (pivot !== null && tomove !== null) { | |
270 | tomove.detach(); |
|
276 | tomove.detach(); | |
271 | pivot.before(tomove); |
|
277 | pivot.before(tomove); | |
272 | this.select(i-1); |
|
278 | this.select(i-1); | |
273 | }; |
|
279 | }; | |
274 | }; |
|
280 | }; | |
275 | this.dirty = true; |
|
281 | this.dirty = true; | |
276 | return this; |
|
282 | return this; | |
277 | } |
|
283 | } | |
278 |
|
284 | |||
279 |
|
285 | |||
280 | Notebook.prototype.move_cell_down = function (index) { |
|
286 | Notebook.prototype.move_cell_down = function (index) { | |
281 | var i = index || this.selected_index(); |
|
287 | var i = index || this.selected_index(); | |
282 | if (i !== null && i < (this.ncells()-1) && i >= 0) { |
|
288 | if (i !== null && i < (this.ncells()-1) && i >= 0) { | |
283 | var pivot = this.cell_elements().eq(i+1) |
|
289 | var pivot = this.cell_elements().eq(i+1) | |
284 | var tomove = this.cell_elements().eq(i) |
|
290 | var tomove = this.cell_elements().eq(i) | |
285 | if (pivot !== null && tomove !== null) { |
|
291 | if (pivot !== null && tomove !== null) { | |
286 | tomove.detach(); |
|
292 | tomove.detach(); | |
287 | pivot.after(tomove); |
|
293 | pivot.after(tomove); | |
288 | this.select(i+1); |
|
294 | this.select(i+1); | |
289 | }; |
|
295 | }; | |
290 | }; |
|
296 | }; | |
291 | this.dirty = true; |
|
297 | this.dirty = true; | |
292 | return this; |
|
298 | return this; | |
293 | } |
|
299 | } | |
294 |
|
300 | |||
295 |
|
301 | |||
296 | Notebook.prototype.sort_cells = function () { |
|
302 | Notebook.prototype.sort_cells = function () { | |
297 | var ncells = this.ncells(); |
|
303 | var ncells = this.ncells(); | |
298 | var sindex = this.selected_index(); |
|
304 | var sindex = this.selected_index(); | |
299 | var swapped; |
|
305 | var swapped; | |
300 | do { |
|
306 | do { | |
301 | swapped = false |
|
307 | swapped = false | |
302 | for (var i=1; i<ncells; i++) { |
|
308 | for (var i=1; i<ncells; i++) { | |
303 | current = this.cell_elements().eq(i).data("cell"); |
|
309 | current = this.cell_elements().eq(i).data("cell"); | |
304 | previous = this.cell_elements().eq(i-1).data("cell"); |
|
310 | previous = this.cell_elements().eq(i-1).data("cell"); | |
305 | if (previous.input_prompt_number > current.input_prompt_number) { |
|
311 | if (previous.input_prompt_number > current.input_prompt_number) { | |
306 | this.move_cell_up(i); |
|
312 | this.move_cell_up(i); | |
307 | swapped = true; |
|
313 | swapped = true; | |
308 | }; |
|
314 | }; | |
309 | }; |
|
315 | }; | |
310 | } while (swapped); |
|
316 | } while (swapped); | |
311 | this.select(sindex); |
|
317 | this.select(sindex); | |
312 | return this; |
|
318 | return this; | |
313 | }; |
|
319 | }; | |
314 |
|
320 | |||
315 |
|
321 | |||
316 | Notebook.prototype.insert_code_cell_before = function (index) { |
|
322 | Notebook.prototype.insert_code_cell_before = function (index) { | |
317 | // TODO: Bounds check for i |
|
323 | // TODO: Bounds check for i | |
318 | var i = this.index_or_selected(index); |
|
324 | var i = this.index_or_selected(index); | |
319 | var cell = new IPython.CodeCell(this); |
|
325 | var cell = new IPython.CodeCell(this); | |
320 | cell.set_input_prompt(); |
|
326 | cell.set_input_prompt(); | |
321 | this.insert_cell_before(cell, i); |
|
327 | this.insert_cell_before(cell, i); | |
322 | this.select(this.find_cell_index(cell)); |
|
328 | this.select(this.find_cell_index(cell)); | |
323 | return cell; |
|
329 | return cell; | |
324 | } |
|
330 | } | |
325 |
|
331 | |||
326 |
|
332 | |||
327 | Notebook.prototype.insert_code_cell_after = function (index) { |
|
333 | Notebook.prototype.insert_code_cell_after = function (index) { | |
328 | // TODO: Bounds check for i |
|
334 | // TODO: Bounds check for i | |
329 | var i = this.index_or_selected(index); |
|
335 | var i = this.index_or_selected(index); | |
330 | var cell = new IPython.CodeCell(this); |
|
336 | var cell = new IPython.CodeCell(this); | |
331 | cell.set_input_prompt(); |
|
337 | cell.set_input_prompt(); | |
332 | this.insert_cell_after(cell, i); |
|
338 | this.insert_cell_after(cell, i); | |
333 | this.select(this.find_cell_index(cell)); |
|
339 | this.select(this.find_cell_index(cell)); | |
334 | return cell; |
|
340 | return cell; | |
335 | } |
|
341 | } | |
336 |
|
342 | |||
337 |
|
343 | |||
338 | Notebook.prototype.insert_html_cell_before = function (index) { |
|
344 | Notebook.prototype.insert_html_cell_before = function (index) { | |
339 | // TODO: Bounds check for i |
|
345 | // TODO: Bounds check for i | |
340 | var i = this.index_or_selected(index); |
|
346 | var i = this.index_or_selected(index); | |
341 | var cell = new IPython.HTMLCell(this); |
|
347 | var cell = new IPython.HTMLCell(this); | |
342 | cell.config_mathjax(); |
|
348 | cell.config_mathjax(); | |
343 | this.insert_cell_before(cell, i); |
|
349 | this.insert_cell_before(cell, i); | |
344 | this.select(this.find_cell_index(cell)); |
|
350 | this.select(this.find_cell_index(cell)); | |
345 | return cell; |
|
351 | return cell; | |
346 | } |
|
352 | } | |
347 |
|
353 | |||
348 |
|
354 | |||
349 | Notebook.prototype.insert_html_cell_after = function (index) { |
|
355 | Notebook.prototype.insert_html_cell_after = function (index) { | |
350 | // TODO: Bounds check for i |
|
356 | // TODO: Bounds check for i | |
351 | var i = this.index_or_selected(index); |
|
357 | var i = this.index_or_selected(index); | |
352 | var cell = new IPython.HTMLCell(this); |
|
358 | var cell = new IPython.HTMLCell(this); | |
353 | cell.config_mathjax(); |
|
359 | cell.config_mathjax(); | |
354 | this.insert_cell_after(cell, i); |
|
360 | this.insert_cell_after(cell, i); | |
355 | this.select(this.find_cell_index(cell)); |
|
361 | this.select(this.find_cell_index(cell)); | |
356 | return cell; |
|
362 | return cell; | |
357 | } |
|
363 | } | |
358 |
|
364 | |||
359 |
|
365 | |||
360 | Notebook.prototype.insert_markdown_cell_before = function (index) { |
|
366 | Notebook.prototype.insert_markdown_cell_before = function (index) { | |
361 | // TODO: Bounds check for i |
|
367 | // TODO: Bounds check for i | |
362 | var i = this.index_or_selected(index); |
|
368 | var i = this.index_or_selected(index); | |
363 | var cell = new IPython.MarkdownCell(this); |
|
369 | var cell = new IPython.MarkdownCell(this); | |
364 | cell.config_mathjax(); |
|
370 | cell.config_mathjax(); | |
365 | this.insert_cell_before(cell, i); |
|
371 | this.insert_cell_before(cell, i); | |
366 | this.select(this.find_cell_index(cell)); |
|
372 | this.select(this.find_cell_index(cell)); | |
367 | return cell; |
|
373 | return cell; | |
368 | } |
|
374 | } | |
369 |
|
375 | |||
370 |
|
376 | |||
371 | Notebook.prototype.insert_markdown_cell_after = function (index) { |
|
377 | Notebook.prototype.insert_markdown_cell_after = function (index) { | |
372 | // TODO: Bounds check for i |
|
378 | // TODO: Bounds check for i | |
373 | var i = this.index_or_selected(index); |
|
379 | var i = this.index_or_selected(index); | |
374 | var cell = new IPython.MarkdownCell(this); |
|
380 | var cell = new IPython.MarkdownCell(this); | |
375 | cell.config_mathjax(); |
|
381 | cell.config_mathjax(); | |
376 | this.insert_cell_after(cell, i); |
|
382 | this.insert_cell_after(cell, i); | |
377 | this.select(this.find_cell_index(cell)); |
|
383 | this.select(this.find_cell_index(cell)); | |
378 | return cell; |
|
384 | return cell; | |
379 | } |
|
385 | } | |
380 |
|
386 | |||
381 |
|
387 | |||
382 | Notebook.prototype.to_code = function (index) { |
|
388 | Notebook.prototype.to_code = function (index) { | |
383 | // TODO: Bounds check for i |
|
389 | // TODO: Bounds check for i | |
384 | var i = this.index_or_selected(index); |
|
390 | var i = this.index_or_selected(index); | |
385 | var source_element = this.cell_elements().eq(i); |
|
391 | var source_element = this.cell_elements().eq(i); | |
386 | var source_cell = source_element.data("cell"); |
|
392 | var source_cell = source_element.data("cell"); | |
387 | if (source_cell instanceof IPython.HTMLCell || |
|
393 | if (source_cell instanceof IPython.HTMLCell || | |
388 | source_cell instanceof IPython.MarkdownCell) { |
|
394 | source_cell instanceof IPython.MarkdownCell) { | |
389 | this.insert_code_cell_after(i); |
|
395 | this.insert_code_cell_after(i); | |
390 | var target_cell = this.cells()[i+1]; |
|
396 | var target_cell = this.cells()[i+1]; | |
391 | target_cell.set_code(source_cell.get_source()); |
|
397 | target_cell.set_code(source_cell.get_source()); | |
392 | source_element.remove(); |
|
398 | source_element.remove(); | |
393 | target_cell.select(); |
|
399 | target_cell.select(); | |
394 | }; |
|
400 | }; | |
395 | this.dirty = true; |
|
401 | this.dirty = true; | |
396 | }; |
|
402 | }; | |
397 |
|
403 | |||
398 |
|
404 | |||
399 | Notebook.prototype.to_markdown = function (index) { |
|
405 | Notebook.prototype.to_markdown = function (index) { | |
400 | // TODO: Bounds check for i |
|
406 | // TODO: Bounds check for i | |
401 | var i = this.index_or_selected(index); |
|
407 | var i = this.index_or_selected(index); | |
402 | var source_element = this.cell_elements().eq(i); |
|
408 | var source_element = this.cell_elements().eq(i); | |
403 | var source_cell = source_element.data("cell"); |
|
409 | var source_cell = source_element.data("cell"); | |
404 | var target_cell = null; |
|
410 | var target_cell = null; | |
405 | if (source_cell instanceof IPython.CodeCell) { |
|
411 | if (source_cell instanceof IPython.CodeCell) { | |
406 | this.insert_markdown_cell_after(i); |
|
412 | this.insert_markdown_cell_after(i); | |
407 | var target_cell = this.cells()[i+1]; |
|
413 | var target_cell = this.cells()[i+1]; | |
408 | var text = source_cell.get_code(); |
|
414 | var text = source_cell.get_code(); | |
409 | } else if (source_cell instanceof IPython.HTMLCell) { |
|
415 | } else if (source_cell instanceof IPython.HTMLCell) { | |
410 | this.insert_markdown_cell_after(i); |
|
416 | this.insert_markdown_cell_after(i); | |
411 | var target_cell = this.cells()[i+1]; |
|
417 | var target_cell = this.cells()[i+1]; | |
412 | var text = source_cell.get_source(); |
|
418 | var text = source_cell.get_source(); | |
413 | if (text === source_cell.placeholder) { |
|
419 | if (text === source_cell.placeholder) { | |
414 | text = target_cell.placeholder; |
|
420 | text = target_cell.placeholder; | |
415 | } |
|
421 | } | |
416 | } |
|
422 | } | |
417 | if (target_cell !== null) { |
|
423 | if (target_cell !== null) { | |
418 | if (text === "") {text = target_cell.placeholder;}; |
|
424 | if (text === "") {text = target_cell.placeholder;}; | |
419 | target_cell.set_source(text); |
|
425 | target_cell.set_source(text); | |
420 | source_element.remove(); |
|
426 | source_element.remove(); | |
421 | target_cell.edit(); |
|
427 | target_cell.edit(); | |
422 | } |
|
428 | } | |
423 | this.dirty = true; |
|
429 | this.dirty = true; | |
424 | }; |
|
430 | }; | |
425 |
|
431 | |||
426 |
|
432 | |||
427 | Notebook.prototype.to_html = function (index) { |
|
433 | Notebook.prototype.to_html = function (index) { | |
428 | // TODO: Bounds check for i |
|
434 | // TODO: Bounds check for i | |
429 | var i = this.index_or_selected(index); |
|
435 | var i = this.index_or_selected(index); | |
430 | var source_element = this.cell_elements().eq(i); |
|
436 | var source_element = this.cell_elements().eq(i); | |
431 | var source_cell = source_element.data("cell"); |
|
437 | var source_cell = source_element.data("cell"); | |
432 | var target_cell = null; |
|
438 | var target_cell = null; | |
433 | if (source_cell instanceof IPython.CodeCell) { |
|
439 | if (source_cell instanceof IPython.CodeCell) { | |
434 | this.insert_html_cell_after(i); |
|
440 | this.insert_html_cell_after(i); | |
435 | var target_cell = this.cells()[i+1]; |
|
441 | var target_cell = this.cells()[i+1]; | |
436 | var text = source_cell.get_code(); |
|
442 | var text = source_cell.get_code(); | |
437 | } else if (source_cell instanceof IPython.MarkdownCell) { |
|
443 | } else if (source_cell instanceof IPython.MarkdownCell) { | |
438 | this.insert_html_cell_after(i); |
|
444 | this.insert_html_cell_after(i); | |
439 | var target_cell = this.cells()[i+1]; |
|
445 | var target_cell = this.cells()[i+1]; | |
440 | var text = source_cell.get_source(); |
|
446 | var text = source_cell.get_source(); | |
441 | if (text === source_cell.placeholder) { |
|
447 | if (text === source_cell.placeholder) { | |
442 | text = target_cell.placeholder; |
|
448 | text = target_cell.placeholder; | |
443 | } |
|
449 | } | |
444 | } |
|
450 | } | |
445 | if (target_cell !== null) { |
|
451 | if (target_cell !== null) { | |
446 | if (text === "") {text = target_cell.placeholder;}; |
|
452 | if (text === "") {text = target_cell.placeholder;}; | |
447 | target_cell.set_source(text); |
|
453 | target_cell.set_source(text); | |
448 | source_element.remove(); |
|
454 | source_element.remove(); | |
449 | target_cell.edit(); |
|
455 | target_cell.edit(); | |
450 | } |
|
456 | } | |
451 | this.dirty = true; |
|
457 | this.dirty = true; | |
452 | }; |
|
458 | }; | |
453 |
|
459 | |||
454 |
|
460 | |||
455 | // Cell collapsing and output clearing |
|
461 | // Cell collapsing and output clearing | |
456 |
|
462 | |||
457 | Notebook.prototype.collapse = function (index) { |
|
463 | Notebook.prototype.collapse = function (index) { | |
458 | var i = this.index_or_selected(index); |
|
464 | var i = this.index_or_selected(index); | |
459 | this.cells()[i].collapse(); |
|
465 | this.cells()[i].collapse(); | |
460 | this.dirty = true; |
|
466 | this.dirty = true; | |
461 | }; |
|
467 | }; | |
462 |
|
468 | |||
463 |
|
469 | |||
464 | Notebook.prototype.expand = function (index) { |
|
470 | Notebook.prototype.expand = function (index) { | |
465 | var i = this.index_or_selected(index); |
|
471 | var i = this.index_or_selected(index); | |
466 | this.cells()[i].expand(); |
|
472 | this.cells()[i].expand(); | |
467 | this.dirty = true; |
|
473 | this.dirty = true; | |
468 | }; |
|
474 | }; | |
469 |
|
475 | |||
470 |
|
476 | |||
471 | Notebook.prototype.set_autoindent = function (state) { |
|
477 | Notebook.prototype.set_autoindent = function (state) { | |
472 | var cells = this.cells(); |
|
478 | var cells = this.cells(); | |
473 | len = cells.length; |
|
479 | len = cells.length; | |
474 | for (var i=0; i<len; i++) { |
|
480 | for (var i=0; i<len; i++) { | |
475 | cells[i].set_autoindent(state) |
|
481 | cells[i].set_autoindent(state) | |
476 | }; |
|
482 | }; | |
477 | }; |
|
483 | }; | |
478 |
|
484 | |||
479 |
|
485 | |||
480 | Notebook.prototype.clear_all_output = function () { |
|
486 | Notebook.prototype.clear_all_output = function () { | |
481 | var ncells = this.ncells(); |
|
487 | var ncells = this.ncells(); | |
482 | var cells = this.cells(); |
|
488 | var cells = this.cells(); | |
483 | for (var i=0; i<ncells; i++) { |
|
489 | for (var i=0; i<ncells; i++) { | |
484 | if (cells[i] instanceof IPython.CodeCell) { |
|
490 | if (cells[i] instanceof IPython.CodeCell) { | |
485 | cells[i].clear_output(); |
|
491 | cells[i].clear_output(); | |
486 | } |
|
492 | } | |
487 | }; |
|
493 | }; | |
488 | this.dirty = true; |
|
494 | this.dirty = true; | |
489 | }; |
|
495 | }; | |
490 |
|
496 | |||
491 |
|
497 | |||
492 | // Kernel related things |
|
498 | // Kernel related things | |
493 |
|
499 | |||
494 | Notebook.prototype.start_kernel = function () { |
|
500 | Notebook.prototype.start_kernel = function () { | |
495 | this.kernel = new IPython.Kernel(); |
|
501 | this.kernel = new IPython.Kernel(); | |
496 | var notebook_id = IPython.save_widget.get_notebook_id(); |
|
502 | var notebook_id = IPython.save_widget.get_notebook_id(); | |
497 | this.kernel.start(notebook_id, $.proxy(this.kernel_started, this)); |
|
503 | this.kernel.start(notebook_id, $.proxy(this.kernel_started, this)); | |
498 | }; |
|
504 | }; | |
499 |
|
505 | |||
500 |
|
506 | |||
501 | Notebook.prototype.restart_kernel = function () { |
|
507 | Notebook.prototype.restart_kernel = function () { | |
502 | var notebook_id = IPython.save_widget.get_notebook_id(); |
|
508 | var notebook_id = IPython.save_widget.get_notebook_id(); | |
503 | this.kernel.restart($.proxy(this.kernel_started, this)); |
|
509 | this.kernel.restart($.proxy(this.kernel_started, this)); | |
504 | }; |
|
510 | }; | |
505 |
|
511 | |||
506 |
|
512 | |||
507 | Notebook.prototype.kernel_started = function () { |
|
513 | Notebook.prototype.kernel_started = function () { | |
508 | console.log("Kernel started: ", this.kernel.kernel_id); |
|
514 | console.log("Kernel started: ", this.kernel.kernel_id); | |
509 | this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this); |
|
515 | this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this); | |
510 | this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this); |
|
516 | this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this); | |
511 | }; |
|
517 | }; | |
512 |
|
518 | |||
513 |
|
519 | |||
514 | Notebook.prototype.handle_shell_reply = function (e) { |
|
520 | Notebook.prototype.handle_shell_reply = function (e) { | |
515 | reply = $.parseJSON(e.data); |
|
521 | reply = $.parseJSON(e.data); | |
516 | var header = reply.header; |
|
522 | var header = reply.header; | |
517 | var content = reply.content; |
|
523 | var content = reply.content; | |
518 | var msg_type = header.msg_type; |
|
524 | var msg_type = header.msg_type; | |
519 | // console.log(reply); |
|
525 | // console.log(reply); | |
520 | var cell = this.cell_for_msg(reply.parent_header.msg_id); |
|
526 | var cell = this.cell_for_msg(reply.parent_header.msg_id); | |
521 | if (msg_type === "execute_reply") { |
|
527 | if (msg_type === "execute_reply") { | |
522 | cell.set_input_prompt(content.execution_count); |
|
528 | cell.set_input_prompt(content.execution_count); | |
523 | this.dirty = true; |
|
529 | this.dirty = true; | |
524 | } else if (msg_type === "complete_reply") { |
|
530 | } else if (msg_type === "complete_reply") { | |
525 | cell.finish_completing(content.matched_text, content.matches); |
|
531 | cell.finish_completing(content.matched_text, content.matches); | |
526 | }; |
|
532 | }; | |
527 | var payload = content.payload || []; |
|
533 | var payload = content.payload || []; | |
528 | this.handle_payload(cell, payload); |
|
534 | this.handle_payload(cell, payload); | |
529 | }; |
|
535 | }; | |
530 |
|
536 | |||
531 |
|
537 | |||
532 | Notebook.prototype.handle_payload = function (cell, payload) { |
|
538 | Notebook.prototype.handle_payload = function (cell, payload) { | |
533 | var l = payload.length; |
|
539 | var l = payload.length; | |
534 | for (var i=0; i<l; i++) { |
|
540 | for (var i=0; i<l; i++) { | |
535 | if (payload[i].source === 'IPython.zmq.page.page') { |
|
541 | if (payload[i].source === 'IPython.zmq.page.page') { | |
536 | if (payload[i].text.trim() !== '') { |
|
542 | if (payload[i].text.trim() !== '') { | |
537 | IPython.pager.clear(); |
|
543 | IPython.pager.clear(); | |
538 | IPython.pager.expand(); |
|
544 | IPython.pager.expand(); | |
539 | IPython.pager.append_text(payload[i].text); |
|
545 | IPython.pager.append_text(payload[i].text); | |
540 | } |
|
546 | } | |
541 | } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') { |
|
547 | } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') { | |
542 | var index = this.find_cell_index(cell); |
|
548 | var index = this.find_cell_index(cell); | |
543 | var new_cell = this.insert_code_cell_after(index); |
|
549 | var new_cell = this.insert_code_cell_after(index); | |
544 | new_cell.set_code(payload[i].text); |
|
550 | new_cell.set_code(payload[i].text); | |
545 | this.dirty = true; |
|
551 | this.dirty = true; | |
546 | } |
|
552 | } | |
547 | }; |
|
553 | }; | |
548 | }; |
|
554 | }; | |
549 |
|
555 | |||
550 |
|
556 | |||
551 | Notebook.prototype.handle_iopub_reply = function (e) { |
|
557 | Notebook.prototype.handle_iopub_reply = function (e) { | |
552 | reply = $.parseJSON(e.data); |
|
558 | reply = $.parseJSON(e.data); | |
553 | var content = reply.content; |
|
559 | var content = reply.content; | |
554 | // console.log(reply); |
|
560 | // console.log(reply); | |
555 | var msg_type = reply.header.msg_type; |
|
561 | var msg_type = reply.header.msg_type; | |
556 | var cell = this.cell_for_msg(reply.parent_header.msg_id); |
|
562 | var cell = this.cell_for_msg(reply.parent_header.msg_id); | |
557 | var output_types = ['stream','display_data','pyout','pyerr']; |
|
563 | var output_types = ['stream','display_data','pyout','pyerr']; | |
558 | if (output_types.indexOf(msg_type) >= 0) { |
|
564 | if (output_types.indexOf(msg_type) >= 0) { | |
559 | this.handle_output(cell, msg_type, content); |
|
565 | this.handle_output(cell, msg_type, content); | |
560 | } else if (msg_type === 'status') { |
|
566 | } else if (msg_type === 'status') { | |
561 | if (content.execution_state === 'busy') { |
|
567 | if (content.execution_state === 'busy') { | |
562 | IPython.kernel_status_widget.status_busy(); |
|
568 | IPython.kernel_status_widget.status_busy(); | |
563 | } else if (content.execution_state === 'idle') { |
|
569 | } else if (content.execution_state === 'idle') { | |
564 | IPython.kernel_status_widget.status_idle(); |
|
570 | IPython.kernel_status_widget.status_idle(); | |
565 | } else if (content.execution_state === 'dead') { |
|
571 | } else if (content.execution_state === 'dead') { | |
566 | this.handle_status_dead(); |
|
572 | this.handle_status_dead(); | |
567 | }; |
|
573 | }; | |
568 | } |
|
574 | } | |
569 | }; |
|
575 | }; | |
570 |
|
576 | |||
571 |
|
577 | |||
572 | Notebook.prototype.handle_status_dead = function () { |
|
578 | Notebook.prototype.handle_status_dead = function () { | |
573 | var that = this; |
|
579 | var that = this; | |
574 | this.kernel.stop_channels(); |
|
580 | this.kernel.stop_channels(); | |
575 | var dialog = $('<div/>'); |
|
581 | var dialog = $('<div/>'); | |
576 | dialog.html('The kernel has died, would you like to restart it? If you do not restart the kernel, you will be able to save the notebook, but running code will not work until the notebook is reopened.'); |
|
582 | dialog.html('The kernel has died, would you like to restart it? If you do not restart the kernel, you will be able to save the notebook, but running code will not work until the notebook is reopened.'); | |
577 | $(document).append(dialog); |
|
583 | $(document).append(dialog); | |
578 | dialog.dialog({ |
|
584 | dialog.dialog({ | |
579 | resizable: false, |
|
585 | resizable: false, | |
580 | modal: true, |
|
586 | modal: true, | |
581 | title: "Dead kernel", |
|
587 | title: "Dead kernel", | |
582 | buttons : { |
|
588 | buttons : { | |
583 | "Yes": function () { |
|
589 | "Yes": function () { | |
584 | that.start_kernel(); |
|
590 | that.start_kernel(); | |
585 | $(this).dialog('close'); |
|
591 | $(this).dialog('close'); | |
586 | }, |
|
592 | }, | |
587 | "No": function () { |
|
593 | "No": function () { | |
588 | $(this).dialog('close'); |
|
594 | $(this).dialog('close'); | |
589 | } |
|
595 | } | |
590 | } |
|
596 | } | |
591 | }); |
|
597 | }); | |
592 | }; |
|
598 | }; | |
593 |
|
599 | |||
594 |
|
600 | |||
595 | Notebook.prototype.handle_output = function (cell, msg_type, content) { |
|
601 | Notebook.prototype.handle_output = function (cell, msg_type, content) { | |
596 | var json = {}; |
|
602 | var json = {}; | |
597 | json.output_type = msg_type; |
|
603 | json.output_type = msg_type; | |
598 | if (msg_type === "stream") { |
|
604 | if (msg_type === "stream") { | |
599 | json.text = utils.fixConsole(content.data + '\n'); |
|
605 | json.text = utils.fixConsole(content.data + '\n'); | |
600 | } else if (msg_type === "display_data") { |
|
606 | } else if (msg_type === "display_data") { | |
601 | json = this.convert_mime_types(json, content.data); |
|
607 | json = this.convert_mime_types(json, content.data); | |
602 | } else if (msg_type === "pyout") { |
|
608 | } else if (msg_type === "pyout") { | |
603 | json.prompt_number = content.execution_count; |
|
609 | json.prompt_number = content.execution_count; | |
604 | json = this.convert_mime_types(json, content.data); |
|
610 | json = this.convert_mime_types(json, content.data); | |
605 | } else if (msg_type === "pyerr") { |
|
611 | } else if (msg_type === "pyerr") { | |
606 | json.ename = content.ename; |
|
612 | json.ename = content.ename; | |
607 | json.evalue = content.evalue; |
|
613 | json.evalue = content.evalue; | |
608 | var traceback = []; |
|
614 | var traceback = []; | |
609 | for (var i=0; i<content.traceback.length; i++) { |
|
615 | for (var i=0; i<content.traceback.length; i++) { | |
610 | traceback.push(utils.fixConsole(content.traceback[i])); |
|
616 | traceback.push(utils.fixConsole(content.traceback[i])); | |
611 | } |
|
617 | } | |
612 | json.traceback = traceback; |
|
618 | json.traceback = traceback; | |
613 | }; |
|
619 | }; | |
614 | cell.append_output(json); |
|
620 | cell.append_output(json); | |
615 | this.dirty = true; |
|
621 | this.dirty = true; | |
616 | }; |
|
622 | }; | |
617 |
|
623 | |||
618 |
|
624 | |||
619 | Notebook.prototype.convert_mime_types = function (json, data) { |
|
625 | Notebook.prototype.convert_mime_types = function (json, data) { | |
620 | if (data['text/plain'] !== undefined) { |
|
626 | if (data['text/plain'] !== undefined) { | |
621 | json.text = utils.fixConsole(data['text/plain']); |
|
627 | json.text = utils.fixConsole(data['text/plain']); | |
622 | }; |
|
628 | }; | |
623 | if (data['text/html'] !== undefined) { |
|
629 | if (data['text/html'] !== undefined) { | |
624 | json.html = data['text/html']; |
|
630 | json.html = data['text/html']; | |
625 | }; |
|
631 | }; | |
626 | if (data['image/svg+xml'] !== undefined) { |
|
632 | if (data['image/svg+xml'] !== undefined) { | |
627 | json.svg = data['image/svg+xml']; |
|
633 | json.svg = data['image/svg+xml']; | |
628 | }; |
|
634 | }; | |
629 | if (data['image/png'] !== undefined) { |
|
635 | if (data['image/png'] !== undefined) { | |
630 | json.png = data['image/png']; |
|
636 | json.png = data['image/png']; | |
631 | }; |
|
637 | }; | |
632 | if (data['image/jpeg'] !== undefined) { |
|
638 | if (data['image/jpeg'] !== undefined) { | |
633 | json.jpeg = data['image/jpeg']; |
|
639 | json.jpeg = data['image/jpeg']; | |
634 | }; |
|
640 | }; | |
635 | if (data['text/latex'] !== undefined) { |
|
641 | if (data['text/latex'] !== undefined) { | |
636 | json.latex = data['text/latex']; |
|
642 | json.latex = data['text/latex']; | |
637 | }; |
|
643 | }; | |
638 | if (data['application/json'] !== undefined) { |
|
644 | if (data['application/json'] !== undefined) { | |
639 | json.json = data['application/json']; |
|
645 | json.json = data['application/json']; | |
640 | }; |
|
646 | }; | |
641 | if (data['application/javascript'] !== undefined) { |
|
647 | if (data['application/javascript'] !== undefined) { | |
642 | json.javascript = data['application/javascript']; |
|
648 | json.javascript = data['application/javascript']; | |
643 | } |
|
649 | } | |
644 | return json; |
|
650 | return json; | |
645 | }; |
|
651 | }; | |
646 |
|
652 | |||
647 |
|
653 | |||
648 | Notebook.prototype.execute_selected_cell = function (options) { |
|
654 | Notebook.prototype.execute_selected_cell = function (options) { | |
649 | // add_new: should a new cell be added if we are at the end of the nb |
|
655 | // add_new: should a new cell be added if we are at the end of the nb | |
650 | // terminal: execute in terminal mode, which stays in the current cell |
|
656 | // terminal: execute in terminal mode, which stays in the current cell | |
651 | default_options = {terminal: false, add_new: true} |
|
657 | default_options = {terminal: false, add_new: true} | |
652 | $.extend(default_options, options) |
|
658 | $.extend(default_options, options) | |
653 | var that = this; |
|
659 | var that = this; | |
654 | var cell = that.selected_cell(); |
|
660 | var cell = that.selected_cell(); | |
655 | var cell_index = that.find_cell_index(cell); |
|
661 | var cell_index = that.find_cell_index(cell); | |
656 | if (cell instanceof IPython.CodeCell) { |
|
662 | if (cell instanceof IPython.CodeCell) { | |
657 | cell.clear_output(); |
|
663 | cell.clear_output(); | |
658 | var code = cell.get_code(); |
|
664 | var code = cell.get_code(); | |
659 | var msg_id = that.kernel.execute(cell.get_code()); |
|
665 | var msg_id = that.kernel.execute(cell.get_code()); | |
660 | that.msg_cell_map[msg_id] = cell.cell_id; |
|
666 | that.msg_cell_map[msg_id] = cell.cell_id; | |
661 | } else if (cell instanceof IPython.HTMLCell) { |
|
667 | } else if (cell instanceof IPython.HTMLCell) { | |
662 | cell.render(); |
|
668 | cell.render(); | |
663 | } |
|
669 | } | |
664 | if (default_options.terminal) { |
|
670 | if (default_options.terminal) { | |
665 | cell.clear_input(); |
|
671 | cell.clear_input(); | |
666 | } else { |
|
672 | } else { | |
667 | if ((cell_index === (that.ncells()-1)) && default_options.add_new) { |
|
673 | if ((cell_index === (that.ncells()-1)) && default_options.add_new) { | |
668 | that.insert_code_cell_after(); |
|
674 | that.insert_code_cell_after(); | |
669 | // If we are adding a new cell at the end, scroll down to show it. |
|
675 | // If we are adding a new cell at the end, scroll down to show it. | |
670 | that.scroll_to_bottom(); |
|
676 | that.scroll_to_bottom(); | |
671 | } else { |
|
677 | } else { | |
672 | that.select(cell_index+1); |
|
678 | that.select(cell_index+1); | |
673 | }; |
|
679 | }; | |
674 | }; |
|
680 | }; | |
675 | this.dirty = true; |
|
681 | this.dirty = true; | |
676 | }; |
|
682 | }; | |
677 |
|
683 | |||
678 |
|
684 | |||
679 | Notebook.prototype.execute_all_cells = function () { |
|
685 | Notebook.prototype.execute_all_cells = function () { | |
680 | var ncells = this.ncells(); |
|
686 | var ncells = this.ncells(); | |
681 | for (var i=0; i<ncells; i++) { |
|
687 | for (var i=0; i<ncells; i++) { | |
682 | this.select(i); |
|
688 | this.select(i); | |
683 | this.execute_selected_cell({add_new:false}); |
|
689 | this.execute_selected_cell({add_new:false}); | |
684 | }; |
|
690 | }; | |
685 | this.scroll_to_bottom(); |
|
691 | this.scroll_to_bottom(); | |
686 | }; |
|
692 | }; | |
687 |
|
693 | |||
688 |
|
694 | |||
689 | Notebook.prototype.complete_cell = function (cell, line, cursor_pos) { |
|
695 | Notebook.prototype.complete_cell = function (cell, line, cursor_pos) { | |
690 | var msg_id = this.kernel.complete(line, cursor_pos); |
|
696 | var msg_id = this.kernel.complete(line, cursor_pos); | |
691 | this.msg_cell_map[msg_id] = cell.cell_id; |
|
697 | this.msg_cell_map[msg_id] = cell.cell_id; | |
692 | }; |
|
698 | }; | |
693 |
|
699 | |||
694 | // Persistance and loading |
|
700 | // Persistance and loading | |
695 |
|
701 | |||
696 |
|
702 | |||
697 | Notebook.prototype.fromJSON = function (data) { |
|
703 | Notebook.prototype.fromJSON = function (data) { | |
698 | var ncells = this.ncells(); |
|
704 | var ncells = this.ncells(); | |
699 | for (var i=0; i<ncells; i++) { |
|
705 | for (var i=0; i<ncells; i++) { | |
700 | // Always delete cell 0 as they get renumbered as they are deleted. |
|
706 | // Always delete cell 0 as they get renumbered as they are deleted. | |
701 | this.delete_cell(0); |
|
707 | this.delete_cell(0); | |
702 | }; |
|
708 | }; | |
703 | // Only handle 1 worksheet for now. |
|
709 | // Only handle 1 worksheet for now. | |
704 | var worksheet = data.worksheets[0]; |
|
710 | var worksheet = data.worksheets[0]; | |
705 | if (worksheet !== undefined) { |
|
711 | if (worksheet !== undefined) { | |
706 | var new_cells = worksheet.cells; |
|
712 | var new_cells = worksheet.cells; | |
707 | ncells = new_cells.length; |
|
713 | ncells = new_cells.length; | |
708 | var cell_data = null; |
|
714 | var cell_data = null; | |
709 | var new_cell = null; |
|
715 | var new_cell = null; | |
710 | for (var i=0; i<ncells; i++) { |
|
716 | for (var i=0; i<ncells; i++) { | |
711 | cell_data = new_cells[i]; |
|
717 | cell_data = new_cells[i]; | |
712 | if (cell_data.cell_type == 'code') { |
|
718 | if (cell_data.cell_type == 'code') { | |
713 | new_cell = this.insert_code_cell_after(); |
|
719 | new_cell = this.insert_code_cell_after(); | |
714 | new_cell.fromJSON(cell_data); |
|
720 | new_cell.fromJSON(cell_data); | |
715 | } else if (cell_data.cell_type === 'html') { |
|
721 | } else if (cell_data.cell_type === 'html') { | |
716 | new_cell = this.insert_html_cell_after(); |
|
722 | new_cell = this.insert_html_cell_after(); | |
717 | new_cell.fromJSON(cell_data); |
|
723 | new_cell.fromJSON(cell_data); | |
718 | } else if (cell_data.cell_type === 'markdown') { |
|
724 | } else if (cell_data.cell_type === 'markdown') { | |
719 | new_cell = this.insert_markdown_cell_after(); |
|
725 | new_cell = this.insert_markdown_cell_after(); | |
720 | new_cell.fromJSON(cell_data); |
|
726 | new_cell.fromJSON(cell_data); | |
721 | }; |
|
727 | }; | |
722 | }; |
|
728 | }; | |
723 | }; |
|
729 | }; | |
724 | }; |
|
730 | }; | |
725 |
|
731 | |||
726 |
|
732 | |||
727 | Notebook.prototype.toJSON = function () { |
|
733 | Notebook.prototype.toJSON = function () { | |
728 | var cells = this.cells(); |
|
734 | var cells = this.cells(); | |
729 | var ncells = cells.length; |
|
735 | var ncells = cells.length; | |
730 | cell_array = new Array(ncells); |
|
736 | cell_array = new Array(ncells); | |
731 | for (var i=0; i<ncells; i++) { |
|
737 | for (var i=0; i<ncells; i++) { | |
732 | cell_array[i] = cells[i].toJSON(); |
|
738 | cell_array[i] = cells[i].toJSON(); | |
733 | }; |
|
739 | }; | |
734 | data = { |
|
740 | data = { | |
735 | // Only handle 1 worksheet for now. |
|
741 | // Only handle 1 worksheet for now. | |
736 | worksheets : [{cells:cell_array}] |
|
742 | worksheets : [{cells:cell_array}] | |
737 | } |
|
743 | } | |
738 | return data |
|
744 | return data | |
739 | }; |
|
745 | }; | |
740 |
|
746 | |||
741 | Notebook.prototype.save_notebook = function () { |
|
747 | Notebook.prototype.save_notebook = function () { | |
742 | if (IPython.save_widget.test_notebook_name()) { |
|
748 | if (IPython.save_widget.test_notebook_name()) { | |
743 | var notebook_id = IPython.save_widget.get_notebook_id(); |
|
749 | var notebook_id = IPython.save_widget.get_notebook_id(); | |
744 | var nbname = IPython.save_widget.get_notebook_name(); |
|
750 | var nbname = IPython.save_widget.get_notebook_name(); | |
745 | // We may want to move the name/id/nbformat logic inside toJSON? |
|
751 | // We may want to move the name/id/nbformat logic inside toJSON? | |
746 | var data = this.toJSON(); |
|
752 | var data = this.toJSON(); | |
747 | data.name = nbname; |
|
753 | data.name = nbname; | |
748 | data.nbformat = 2; |
|
754 | data.nbformat = 2; | |
749 | // We do the call with settings so we can set cache to false. |
|
755 | // We do the call with settings so we can set cache to false. | |
750 | var settings = { |
|
756 | var settings = { | |
751 | processData : false, |
|
757 | processData : false, | |
752 | cache : false, |
|
758 | cache : false, | |
753 | type : "PUT", |
|
759 | type : "PUT", | |
754 | data : JSON.stringify(data), |
|
760 | data : JSON.stringify(data), | |
755 | headers : {'Content-Type': 'application/json'}, |
|
761 | headers : {'Content-Type': 'application/json'}, | |
756 | success : $.proxy(this.notebook_saved,this) |
|
762 | success : $.proxy(this.notebook_saved,this) | |
757 | }; |
|
763 | }; | |
758 | IPython.save_widget.status_saving(); |
|
764 | IPython.save_widget.status_saving(); | |
759 | $.ajax("/notebooks/" + notebook_id, settings); |
|
765 | $.ajax("/notebooks/" + notebook_id, settings); | |
760 | }; |
|
766 | }; | |
761 | }; |
|
767 | }; | |
762 |
|
768 | |||
763 |
|
769 | |||
764 | Notebook.prototype.notebook_saved = function (data, status, xhr) { |
|
770 | Notebook.prototype.notebook_saved = function (data, status, xhr) { | |
765 | this.dirty = false; |
|
771 | this.dirty = false; | |
766 | setTimeout($.proxy(IPython.save_widget.status_save,IPython.save_widget),500); |
|
772 | setTimeout($.proxy(IPython.save_widget.status_save,IPython.save_widget),500); | |
767 | } |
|
773 | } | |
768 |
|
774 | |||
769 |
|
775 | |||
770 | Notebook.prototype.load_notebook = function (callback) { |
|
776 | Notebook.prototype.load_notebook = function (callback) { | |
771 | var that = this; |
|
777 | var that = this; | |
772 | var notebook_id = IPython.save_widget.get_notebook_id(); |
|
778 | var notebook_id = IPython.save_widget.get_notebook_id(); | |
773 | // We do the call with settings so we can set cache to false. |
|
779 | // We do the call with settings so we can set cache to false. | |
774 | var settings = { |
|
780 | var settings = { | |
775 | processData : false, |
|
781 | processData : false, | |
776 | cache : false, |
|
782 | cache : false, | |
777 | type : "GET", |
|
783 | type : "GET", | |
778 | dataType : "json", |
|
784 | dataType : "json", | |
779 | success : function (data, status, xhr) { |
|
785 | success : function (data, status, xhr) { | |
780 | that.notebook_loaded(data, status, xhr); |
|
786 | that.notebook_loaded(data, status, xhr); | |
781 | if (callback !== undefined) { |
|
787 | if (callback !== undefined) { | |
782 | callback(); |
|
788 | callback(); | |
783 | }; |
|
789 | }; | |
784 | } |
|
790 | } | |
785 | }; |
|
791 | }; | |
786 | IPython.save_widget.status_loading(); |
|
792 | IPython.save_widget.status_loading(); | |
787 | $.ajax("/notebooks/" + notebook_id, settings); |
|
793 | $.ajax("/notebooks/" + notebook_id, settings); | |
788 | } |
|
794 | } | |
789 |
|
795 | |||
790 |
|
796 | |||
791 | Notebook.prototype.notebook_loaded = function (data, status, xhr) { |
|
797 | Notebook.prototype.notebook_loaded = function (data, status, xhr) { | |
792 | this.fromJSON(data); |
|
798 | this.fromJSON(data); | |
793 | if (this.ncells() === 0) { |
|
799 | if (this.ncells() === 0) { | |
794 | this.insert_code_cell_after(); |
|
800 | this.insert_code_cell_after(); | |
795 | }; |
|
801 | }; | |
796 | IPython.save_widget.status_save(); |
|
802 | IPython.save_widget.status_save(); | |
797 | IPython.save_widget.set_notebook_name(data.name); |
|
803 | IPython.save_widget.set_notebook_name(data.name); | |
798 | this.start_kernel(); |
|
804 | this.start_kernel(); | |
799 | this.dirty = false; |
|
805 | this.dirty = false; | |
800 | // fromJSON always selects the last cell inserted. We need to wait |
|
806 | // fromJSON always selects the last cell inserted. We need to wait | |
801 | // until that is done before scrolling to the top. |
|
807 | // until that is done before scrolling to the top. | |
802 | setTimeout(function () { |
|
808 | setTimeout(function () { | |
803 | IPython.notebook.select(0); |
|
809 | IPython.notebook.select(0); | |
804 | IPython.notebook.scroll_to_top(); |
|
810 | IPython.notebook.scroll_to_top(); | |
805 | }, 50); |
|
811 | }, 50); | |
806 | }; |
|
812 | }; | |
807 |
|
813 | |||
808 | IPython.Notebook = Notebook; |
|
814 | IPython.Notebook = Notebook; | |
809 |
|
815 | |||
810 | return IPython; |
|
816 | return IPython; | |
811 |
|
817 | |||
812 | }(IPython)); |
|
818 | }(IPython)); | |
813 |
|
819 |
@@ -1,51 +1,57 b'' | |||||
|
1 | //---------------------------------------------------------------------------- | |||
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |||
|
3 | // | |||
|
4 | // Distributed under the terms of the BSD License. The full license is in | |||
|
5 | // the file COPYING, distributed as part of this software. | |||
|
6 | //---------------------------------------------------------------------------- | |||
1 |
|
|
7 | ||
2 | //============================================================================ |
|
8 | //============================================================================ | |
3 | // On document ready |
|
9 | // On document ready | |
4 | //============================================================================ |
|
10 | //============================================================================ | |
5 |
|
11 | |||
6 |
|
12 | |||
7 | $(document).ready(function () { |
|
13 | $(document).ready(function () { | |
8 |
|
14 | |||
9 | MathJax.Hub.Config({ |
|
15 | MathJax.Hub.Config({ | |
10 | tex2jax: { |
|
16 | tex2jax: { | |
11 | inlineMath: [ ['$','$'], ["\\(","\\)"] ], |
|
17 | inlineMath: [ ['$','$'], ["\\(","\\)"] ], | |
12 | displayMath: [ ['$$','$$'], ["\\[","\\]"] ], |
|
18 | displayMath: [ ['$$','$$'], ["\\[","\\]"] ], | |
13 | }, |
|
19 | }, | |
14 | displayAlign: 'left', // Change this to 'center' to center equations. |
|
20 | displayAlign: 'left', // Change this to 'center' to center equations. | |
15 | "HTML-CSS": { |
|
21 | "HTML-CSS": { | |
16 | styles: {'.MathJax_Display': {"margin": 0}} |
|
22 | styles: {'.MathJax_Display': {"margin": 0}} | |
17 | } |
|
23 | } | |
18 | }); |
|
24 | }); | |
19 | IPython.markdown_converter = new Markdown.Converter(); |
|
25 | IPython.markdown_converter = new Markdown.Converter(); | |
20 |
|
26 | |||
21 | $('div#header').addClass('border-box-sizing'); |
|
27 | $('div#header').addClass('border-box-sizing'); | |
22 | $('div#main_app').addClass('border-box-sizing ui-widget ui-widget-content'); |
|
28 | $('div#main_app').addClass('border-box-sizing ui-widget ui-widget-content'); | |
23 | $('div#notebook_panel').addClass('border-box-sizing ui-widget'); |
|
29 | $('div#notebook_panel').addClass('border-box-sizing ui-widget'); | |
24 |
|
30 | |||
25 | IPython.layout_manager = new IPython.LayoutManager(); |
|
31 | IPython.layout_manager = new IPython.LayoutManager(); | |
26 | IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter'); |
|
32 | IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter'); | |
27 | IPython.left_panel = new IPython.LeftPanel('div#left_panel', 'div#left_panel_splitter'); |
|
33 | IPython.left_panel = new IPython.LeftPanel('div#left_panel', 'div#left_panel_splitter'); | |
28 | IPython.save_widget = new IPython.SaveWidget('span#save_widget'); |
|
34 | IPython.save_widget = new IPython.SaveWidget('span#save_widget'); | |
29 | IPython.notebook = new IPython.Notebook('div#notebook'); |
|
35 | IPython.notebook = new IPython.Notebook('div#notebook'); | |
30 | IPython.kernel_status_widget = new IPython.KernelStatusWidget('#kernel_status'); |
|
36 | IPython.kernel_status_widget = new IPython.KernelStatusWidget('#kernel_status'); | |
31 | IPython.kernel_status_widget.status_idle(); |
|
37 | IPython.kernel_status_widget.status_idle(); | |
32 |
|
38 | |||
33 | IPython.layout_manager.do_resize(); |
|
39 | IPython.layout_manager.do_resize(); | |
34 |
|
40 | |||
35 | // These have display: none in the css file and are made visible here to prevent FLOUC. |
|
41 | // These have display: none in the css file and are made visible here to prevent FLOUC. | |
36 | $('div#header').css('display','block'); |
|
42 | $('div#header').css('display','block'); | |
37 | $('div#main_app').css('display','block'); |
|
43 | $('div#main_app').css('display','block'); | |
38 |
|
44 | |||
39 | // Perform these actions after the notebook has been loaded. |
|
45 | // Perform these actions after the notebook has been loaded. | |
40 | // We wait 100 milliseconds because the notebook scrolls to the top after a load |
|
46 | // We wait 100 milliseconds because the notebook scrolls to the top after a load | |
41 | // is completed and we need to wait for that to mostly finish. |
|
47 | // is completed and we need to wait for that to mostly finish. | |
42 | IPython.notebook.load_notebook(function () { |
|
48 | IPython.notebook.load_notebook(function () { | |
43 | setTimeout(function () { |
|
49 | setTimeout(function () { | |
44 | IPython.save_widget.update_url(); |
|
50 | IPython.save_widget.update_url(); | |
45 | IPython.layout_manager.do_resize(); |
|
51 | IPython.layout_manager.do_resize(); | |
46 | IPython.pager.collapse(); |
|
52 | IPython.pager.collapse(); | |
47 | },100); |
|
53 | },100); | |
48 | }); |
|
54 | }); | |
49 |
|
55 | |||
50 | }); |
|
56 | }); | |
51 |
|
57 |
@@ -1,238 +1,244 b'' | |||||
|
1 | //---------------------------------------------------------------------------- | |||
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |||
|
3 | // | |||
|
4 | // Distributed under the terms of the BSD License. The full license is in | |||
|
5 | // the file COPYING, distributed as part of this software. | |||
|
6 | //---------------------------------------------------------------------------- | |||
1 |
|
|
7 | ||
2 | //============================================================================ |
|
8 | //============================================================================ | |
3 | // Cell |
|
9 | // NotebookList | |
4 | //============================================================================ |
|
10 | //============================================================================ | |
5 |
|
11 | |||
6 | var IPython = (function (IPython) { |
|
12 | var IPython = (function (IPython) { | |
7 |
|
13 | |||
8 | var NotebookList = function (selector) { |
|
14 | var NotebookList = function (selector) { | |
9 | this.selector = selector; |
|
15 | this.selector = selector; | |
10 | if (this.selector !== undefined) { |
|
16 | if (this.selector !== undefined) { | |
11 | this.element = $(selector); |
|
17 | this.element = $(selector); | |
12 | this.style(); |
|
18 | this.style(); | |
13 | this.bind_events(); |
|
19 | this.bind_events(); | |
14 | } |
|
20 | } | |
15 | }; |
|
21 | }; | |
16 |
|
22 | |||
17 | NotebookList.prototype.style = function () { |
|
23 | NotebookList.prototype.style = function () { | |
18 | this.element.addClass('ui-widget ui-widget-content'); |
|
24 | this.element.addClass('ui-widget ui-widget-content'); | |
19 | $('div#project_name').addClass('ui-widget ui-widget-header'); |
|
25 | $('div#project_name').addClass('ui-widget ui-widget-header'); | |
20 | }; |
|
26 | }; | |
21 |
|
27 | |||
22 |
|
28 | |||
23 | NotebookList.prototype.bind_events = function () { |
|
29 | NotebookList.prototype.bind_events = function () { | |
24 | var that = this; |
|
30 | var that = this; | |
25 | this.element.bind('dragover', function () { |
|
31 | this.element.bind('dragover', function () { | |
26 | return false; |
|
32 | return false; | |
27 | }); |
|
33 | }); | |
28 | this.element.bind('drop', function (event) { |
|
34 | this.element.bind('drop', function (event) { | |
29 | var files = event.originalEvent.dataTransfer.files; |
|
35 | var files = event.originalEvent.dataTransfer.files; | |
30 | for (var i = 0, f; f = files[i]; i++) { |
|
36 | for (var i = 0, f; f = files[i]; i++) { | |
31 | var reader = new FileReader(); |
|
37 | var reader = new FileReader(); | |
32 | reader.readAsText(f); |
|
38 | reader.readAsText(f); | |
33 | var fname = f.name.split('.'); |
|
39 | var fname = f.name.split('.'); | |
34 | var nbname = fname[0]; |
|
40 | var nbname = fname[0]; | |
35 | var nbformat = fname[1]; |
|
41 | var nbformat = fname[1]; | |
36 | if (nbformat === 'ipynb') {nbformat = 'xml';}; |
|
42 | if (nbformat === 'ipynb') {nbformat = 'xml';}; | |
37 | if (nbformat === 'xml' || nbformat === 'py' || nbformat === 'json') { |
|
43 | if (nbformat === 'xml' || nbformat === 'py' || nbformat === 'json') { | |
38 | var item = that.new_notebook_item(0); |
|
44 | var item = that.new_notebook_item(0); | |
39 | that.add_name_input(nbname, item); |
|
45 | that.add_name_input(nbname, item); | |
40 | item.data('nbformat', nbformat); |
|
46 | item.data('nbformat', nbformat); | |
41 | // Store the notebook item in the reader so we can use it later |
|
47 | // Store the notebook item in the reader so we can use it later | |
42 | // to know which item it belongs to. |
|
48 | // to know which item it belongs to. | |
43 | $(reader).data('item', item); |
|
49 | $(reader).data('item', item); | |
44 | reader.onload = function (event) { |
|
50 | reader.onload = function (event) { | |
45 | var nbitem = $(event.target).data('item'); |
|
51 | var nbitem = $(event.target).data('item'); | |
46 | that.add_notebook_data(event.target.result, nbitem); |
|
52 | that.add_notebook_data(event.target.result, nbitem); | |
47 | that.add_upload_button(nbitem); |
|
53 | that.add_upload_button(nbitem); | |
48 | }; |
|
54 | }; | |
49 | }; |
|
55 | }; | |
50 | } |
|
56 | } | |
51 | return false; |
|
57 | return false; | |
52 | }); |
|
58 | }); | |
53 | }; |
|
59 | }; | |
54 |
|
60 | |||
55 |
|
61 | |||
56 | NotebookList.prototype.load_list = function () { |
|
62 | NotebookList.prototype.load_list = function () { | |
57 | var settings = { |
|
63 | var settings = { | |
58 | processData : false, |
|
64 | processData : false, | |
59 | cache : false, |
|
65 | cache : false, | |
60 | type : "GET", |
|
66 | type : "GET", | |
61 | dataType : "json", |
|
67 | dataType : "json", | |
62 | success : $.proxy(this.list_loaded, this) |
|
68 | success : $.proxy(this.list_loaded, this) | |
63 | }; |
|
69 | }; | |
64 | $.ajax("/notebooks", settings); |
|
70 | $.ajax("/notebooks", settings); | |
65 | }; |
|
71 | }; | |
66 |
|
72 | |||
67 |
|
73 | |||
68 | NotebookList.prototype.list_loaded = function (data, status, xhr) { |
|
74 | NotebookList.prototype.list_loaded = function (data, status, xhr) { | |
69 | var len = data.length; |
|
75 | var len = data.length; | |
70 | // Todo: remove old children |
|
76 | // Todo: remove old children | |
71 | for (var i=0; i<len; i++) { |
|
77 | for (var i=0; i<len; i++) { | |
72 | var notebook_id = data[i].notebook_id; |
|
78 | var notebook_id = data[i].notebook_id; | |
73 | var nbname = data[i].name; |
|
79 | var nbname = data[i].name; | |
74 | var item = this.new_notebook_item(i); |
|
80 | var item = this.new_notebook_item(i); | |
75 | this.add_link(notebook_id, nbname, item); |
|
81 | this.add_link(notebook_id, nbname, item); | |
76 | this.add_delete_button(item); |
|
82 | this.add_delete_button(item); | |
77 | }; |
|
83 | }; | |
78 | }; |
|
84 | }; | |
79 |
|
85 | |||
80 |
|
86 | |||
81 | NotebookList.prototype.new_notebook_item = function (index) { |
|
87 | NotebookList.prototype.new_notebook_item = function (index) { | |
82 | var item = $('<div/>'); |
|
88 | var item = $('<div/>'); | |
83 | item.addClass('notebook_item ui-widget ui-widget-content ui-helper-clearfix'); |
|
89 | item.addClass('notebook_item ui-widget ui-widget-content ui-helper-clearfix'); | |
84 | var item_name = $('<span/>').addClass('item_name'); |
|
90 | var item_name = $('<span/>').addClass('item_name'); | |
85 |
|
91 | |||
86 | item.append(item_name); |
|
92 | item.append(item_name); | |
87 | if (index === -1) { |
|
93 | if (index === -1) { | |
88 | this.element.append(item); |
|
94 | this.element.append(item); | |
89 | } else { |
|
95 | } else { | |
90 | this.element.children().eq(index).after(item); |
|
96 | this.element.children().eq(index).after(item); | |
91 | } |
|
97 | } | |
92 | return item; |
|
98 | return item; | |
93 | }; |
|
99 | }; | |
94 |
|
100 | |||
95 |
|
101 | |||
96 | NotebookList.prototype.add_link = function (notebook_id, nbname, item) { |
|
102 | NotebookList.prototype.add_link = function (notebook_id, nbname, item) { | |
97 | item.data('nbname', nbname); |
|
103 | item.data('nbname', nbname); | |
98 | item.data('notebook_id', notebook_id); |
|
104 | item.data('notebook_id', notebook_id); | |
99 | var new_item_name = $('<span/>').addClass('item_name'); |
|
105 | var new_item_name = $('<span/>').addClass('item_name'); | |
100 | new_item_name.append( |
|
106 | new_item_name.append( | |
101 | $('<a/>'). |
|
107 | $('<a/>'). | |
102 | attr('href','/'+notebook_id). |
|
108 | attr('href','/'+notebook_id). | |
103 | attr('target','_blank'). |
|
109 | attr('target','_blank'). | |
104 | text(nbname) |
|
110 | text(nbname) | |
105 | ); |
|
111 | ); | |
106 | var e = item.find('.item_name'); |
|
112 | var e = item.find('.item_name'); | |
107 | if (e.length === 0) { |
|
113 | if (e.length === 0) { | |
108 | item.append(new_item_name); |
|
114 | item.append(new_item_name); | |
109 | } else { |
|
115 | } else { | |
110 | e.replaceWith(new_item_name); |
|
116 | e.replaceWith(new_item_name); | |
111 | }; |
|
117 | }; | |
112 | }; |
|
118 | }; | |
113 |
|
119 | |||
114 |
|
120 | |||
115 | NotebookList.prototype.add_name_input = function (nbname, item) { |
|
121 | NotebookList.prototype.add_name_input = function (nbname, item) { | |
116 | item.data('nbname', nbname); |
|
122 | item.data('nbname', nbname); | |
117 | var new_item_name = $('<span/>').addClass('item_name'); |
|
123 | var new_item_name = $('<span/>').addClass('item_name'); | |
118 | new_item_name.append( |
|
124 | new_item_name.append( | |
119 | $('<input/>').addClass('ui-widget ui-widget-content'). |
|
125 | $('<input/>').addClass('ui-widget ui-widget-content'). | |
120 | attr('value', nbname). |
|
126 | attr('value', nbname). | |
121 | attr('size', '30'). |
|
127 | attr('size', '30'). | |
122 | attr('type', 'text') |
|
128 | attr('type', 'text') | |
123 | ); |
|
129 | ); | |
124 | var e = item.find('.item_name'); |
|
130 | var e = item.find('.item_name'); | |
125 | if (e.length === 0) { |
|
131 | if (e.length === 0) { | |
126 | item.append(new_item_name); |
|
132 | item.append(new_item_name); | |
127 | } else { |
|
133 | } else { | |
128 | e.replaceWith(new_item_name); |
|
134 | e.replaceWith(new_item_name); | |
129 | }; |
|
135 | }; | |
130 | }; |
|
136 | }; | |
131 |
|
137 | |||
132 |
|
138 | |||
133 | NotebookList.prototype.add_notebook_data = function (data, item) { |
|
139 | NotebookList.prototype.add_notebook_data = function (data, item) { | |
134 | item.data('nbdata',data); |
|
140 | item.data('nbdata',data); | |
135 | }; |
|
141 | }; | |
136 |
|
142 | |||
137 |
|
143 | |||
138 | NotebookList.prototype.add_delete_button = function (item) { |
|
144 | NotebookList.prototype.add_delete_button = function (item) { | |
139 | var new_buttons = $('<span/>').addClass('item_buttons'); |
|
145 | var new_buttons = $('<span/>').addClass('item_buttons'); | |
140 | var delete_button = $('<button>Delete</button>').button(). |
|
146 | var delete_button = $('<button>Delete</button>').button(). | |
141 | click(function (e) { |
|
147 | click(function (e) { | |
142 | // $(this) is the button that was clicked. |
|
148 | // $(this) is the button that was clicked. | |
143 | var that = $(this); |
|
149 | var that = $(this); | |
144 | // We use the nbname and notebook_id from the parent notebook_item element's |
|
150 | // We use the nbname and notebook_id from the parent notebook_item element's | |
145 | // data because the outer scopes values change as we iterate through the loop. |
|
151 | // data because the outer scopes values change as we iterate through the loop. | |
146 | var parent_item = that.parents('div.notebook_item'); |
|
152 | var parent_item = that.parents('div.notebook_item'); | |
147 | var nbname = parent_item.data('nbname'); |
|
153 | var nbname = parent_item.data('nbname'); | |
148 | var notebook_id = parent_item.data('notebook_id'); |
|
154 | var notebook_id = parent_item.data('notebook_id'); | |
149 | var dialog = $('<div/>'); |
|
155 | var dialog = $('<div/>'); | |
150 | dialog.html('Are you sure you want to permanently delete the notebook: ' + nbname + '?'); |
|
156 | dialog.html('Are you sure you want to permanently delete the notebook: ' + nbname + '?'); | |
151 | parent_item.append(dialog); |
|
157 | parent_item.append(dialog); | |
152 | dialog.dialog({ |
|
158 | dialog.dialog({ | |
153 | resizable: false, |
|
159 | resizable: false, | |
154 | modal: true, |
|
160 | modal: true, | |
155 | title: "Delete notebook", |
|
161 | title: "Delete notebook", | |
156 | buttons : { |
|
162 | buttons : { | |
157 | "Delete": function () { |
|
163 | "Delete": function () { | |
158 | var settings = { |
|
164 | var settings = { | |
159 | processData : false, |
|
165 | processData : false, | |
160 | cache : false, |
|
166 | cache : false, | |
161 | type : "DELETE", |
|
167 | type : "DELETE", | |
162 | dataType : "json", |
|
168 | dataType : "json", | |
163 | success : function (data, status, xhr) { |
|
169 | success : function (data, status, xhr) { | |
164 | parent_item.remove(); |
|
170 | parent_item.remove(); | |
165 | } |
|
171 | } | |
166 | }; |
|
172 | }; | |
167 | $.ajax("/notebooks/" + notebook_id, settings); |
|
173 | $.ajax("/notebooks/" + notebook_id, settings); | |
168 | $(this).dialog('close'); |
|
174 | $(this).dialog('close'); | |
169 | }, |
|
175 | }, | |
170 | "Cancel": function () { |
|
176 | "Cancel": function () { | |
171 | $(this).dialog('close'); |
|
177 | $(this).dialog('close'); | |
172 | } |
|
178 | } | |
173 | } |
|
179 | } | |
174 | }); |
|
180 | }); | |
175 | }); |
|
181 | }); | |
176 | new_buttons.append(delete_button); |
|
182 | new_buttons.append(delete_button); | |
177 | var e = item.find('.item_buttons'); |
|
183 | var e = item.find('.item_buttons'); | |
178 | if (e.length === 0) { |
|
184 | if (e.length === 0) { | |
179 | item.append(new_buttons); |
|
185 | item.append(new_buttons); | |
180 | } else { |
|
186 | } else { | |
181 | e.replaceWith(new_buttons); |
|
187 | e.replaceWith(new_buttons); | |
182 | }; |
|
188 | }; | |
183 | }; |
|
189 | }; | |
184 |
|
190 | |||
185 |
|
191 | |||
186 | NotebookList.prototype.add_upload_button = function (item) { |
|
192 | NotebookList.prototype.add_upload_button = function (item) { | |
187 | var that = this; |
|
193 | var that = this; | |
188 | var new_buttons = $('<span/>').addClass('item_buttons'); |
|
194 | var new_buttons = $('<span/>').addClass('item_buttons'); | |
189 | var upload_button = $('<button>Upload</button>').button(). |
|
195 | var upload_button = $('<button>Upload</button>').button(). | |
190 | click(function (e) { |
|
196 | click(function (e) { | |
191 | var nbname = item.find('.item_name > input').attr('value'); |
|
197 | var nbname = item.find('.item_name > input').attr('value'); | |
192 | var nbformat = item.data('nbformat'); |
|
198 | var nbformat = item.data('nbformat'); | |
193 | var nbdata = item.data('nbdata'); |
|
199 | var nbdata = item.data('nbdata'); | |
194 | var content_type = 'text/plain'; |
|
200 | var content_type = 'text/plain'; | |
195 | if (nbformat === 'xml') { |
|
201 | if (nbformat === 'xml') { | |
196 | content_type = 'application/xml'; |
|
202 | content_type = 'application/xml'; | |
197 | } else if (nbformat === 'json') { |
|
203 | } else if (nbformat === 'json') { | |
198 | content_type = 'application/json'; |
|
204 | content_type = 'application/json'; | |
199 | } else if (nbformat === 'py') { |
|
205 | } else if (nbformat === 'py') { | |
200 | content_type = 'application/x-python'; |
|
206 | content_type = 'application/x-python'; | |
201 | }; |
|
207 | }; | |
202 | var settings = { |
|
208 | var settings = { | |
203 | processData : false, |
|
209 | processData : false, | |
204 | cache : false, |
|
210 | cache : false, | |
205 | type : 'POST', |
|
211 | type : 'POST', | |
206 | dataType : 'json', |
|
212 | dataType : 'json', | |
207 | data : nbdata, |
|
213 | data : nbdata, | |
208 | headers : {'Content-Type': content_type}, |
|
214 | headers : {'Content-Type': content_type}, | |
209 | success : function (data, status, xhr) { |
|
215 | success : function (data, status, xhr) { | |
210 | that.add_link(data, nbname, item); |
|
216 | that.add_link(data, nbname, item); | |
211 | that.add_delete_button(item); |
|
217 | that.add_delete_button(item); | |
212 | } |
|
218 | } | |
213 | }; |
|
219 | }; | |
214 |
|
220 | |||
215 | var qs = $.param({name:nbname, format:nbformat}); |
|
221 | var qs = $.param({name:nbname, format:nbformat}); | |
216 | $.ajax('/notebooks?' + qs, settings); |
|
222 | $.ajax('/notebooks?' + qs, settings); | |
217 | }); |
|
223 | }); | |
218 | var cancel_button = $('<button>Cancel</button>').button(). |
|
224 | var cancel_button = $('<button>Cancel</button>').button(). | |
219 | click(function (e) { |
|
225 | click(function (e) { | |
220 | item.remove(); |
|
226 | item.remove(); | |
221 | }); |
|
227 | }); | |
222 | upload_button.addClass('upload_button'); |
|
228 | upload_button.addClass('upload_button'); | |
223 | new_buttons.append(upload_button).append(cancel_button); |
|
229 | new_buttons.append(upload_button).append(cancel_button); | |
224 | var e = item.find('.item_buttons'); |
|
230 | var e = item.find('.item_buttons'); | |
225 | if (e.length === 0) { |
|
231 | if (e.length === 0) { | |
226 | item.append(new_buttons); |
|
232 | item.append(new_buttons); | |
227 | } else { |
|
233 | } else { | |
228 | e.replaceWith(new_buttons); |
|
234 | e.replaceWith(new_buttons); | |
229 | }; |
|
235 | }; | |
230 | }; |
|
236 | }; | |
231 |
|
237 | |||
232 |
|
238 | |||
233 | IPython.NotebookList = NotebookList; |
|
239 | IPython.NotebookList = NotebookList; | |
234 |
|
240 | |||
235 | return IPython; |
|
241 | return IPython; | |
236 |
|
242 | |||
237 | }(IPython)); |
|
243 | }(IPython)); | |
238 |
|
244 |
@@ -1,95 +1,101 b'' | |||||
|
1 | //---------------------------------------------------------------------------- | |||
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |||
|
3 | // | |||
|
4 | // Distributed under the terms of the BSD License. The full license is in | |||
|
5 | // the file COPYING, distributed as part of this software. | |||
|
6 | //---------------------------------------------------------------------------- | |||
1 |
|
|
7 | ||
2 | //============================================================================ |
|
8 | //============================================================================ | |
3 | // Pager |
|
9 | // Pager | |
4 | //============================================================================ |
|
10 | //============================================================================ | |
5 |
|
11 | |||
6 | var IPython = (function (IPython) { |
|
12 | var IPython = (function (IPython) { | |
7 |
|
13 | |||
8 | var utils = IPython.utils; |
|
14 | var utils = IPython.utils; | |
9 |
|
15 | |||
10 | var Pager = function (pager_selector, pager_splitter_selector) { |
|
16 | var Pager = function (pager_selector, pager_splitter_selector) { | |
11 | this.pager_element = $(pager_selector); |
|
17 | this.pager_element = $(pager_selector); | |
12 | this.pager_splitter_element = $(pager_splitter_selector); |
|
18 | this.pager_splitter_element = $(pager_splitter_selector); | |
13 | this.expanded = true; |
|
19 | this.expanded = true; | |
14 | this.percentage_height = 0.40; |
|
20 | this.percentage_height = 0.40; | |
15 | this.style(); |
|
21 | this.style(); | |
16 | this.bind_events(); |
|
22 | this.bind_events(); | |
17 | }; |
|
23 | }; | |
18 |
|
24 | |||
19 |
|
25 | |||
20 | Pager.prototype.style = function () { |
|
26 | Pager.prototype.style = function () { | |
21 | this.pager_splitter_element.addClass('border-box-sizing ui-widget ui-state-default'); |
|
27 | this.pager_splitter_element.addClass('border-box-sizing ui-widget ui-state-default'); | |
22 | this.pager_element.addClass('border-box-sizing ui-widget'); |
|
28 | this.pager_element.addClass('border-box-sizing ui-widget'); | |
23 | }; |
|
29 | }; | |
24 |
|
30 | |||
25 |
|
31 | |||
26 | Pager.prototype.bind_events = function () { |
|
32 | Pager.prototype.bind_events = function () { | |
27 | var that = this; |
|
33 | var that = this; | |
28 |
|
34 | |||
29 | this.pager_element.bind('collapse_pager', function () { |
|
35 | this.pager_element.bind('collapse_pager', function () { | |
30 | that.pager_element.hide('fast'); |
|
36 | that.pager_element.hide('fast'); | |
31 | }); |
|
37 | }); | |
32 |
|
38 | |||
33 | this.pager_element.bind('expand_pager', function () { |
|
39 | this.pager_element.bind('expand_pager', function () { | |
34 | that.pager_element.show('fast'); |
|
40 | that.pager_element.show('fast'); | |
35 | }); |
|
41 | }); | |
36 |
|
42 | |||
37 | this.pager_splitter_element.hover( |
|
43 | this.pager_splitter_element.hover( | |
38 | function () { |
|
44 | function () { | |
39 | that.pager_splitter_element.addClass('ui-state-hover'); |
|
45 | that.pager_splitter_element.addClass('ui-state-hover'); | |
40 | }, |
|
46 | }, | |
41 | function () { |
|
47 | function () { | |
42 | that.pager_splitter_element.removeClass('ui-state-hover'); |
|
48 | that.pager_splitter_element.removeClass('ui-state-hover'); | |
43 | } |
|
49 | } | |
44 | ); |
|
50 | ); | |
45 |
|
51 | |||
46 | this.pager_splitter_element.click(function () { |
|
52 | this.pager_splitter_element.click(function () { | |
47 | that.toggle(); |
|
53 | that.toggle(); | |
48 | }); |
|
54 | }); | |
49 |
|
55 | |||
50 | }; |
|
56 | }; | |
51 |
|
57 | |||
52 |
|
58 | |||
53 | Pager.prototype.collapse = function () { |
|
59 | Pager.prototype.collapse = function () { | |
54 | if (this.expanded === true) { |
|
60 | if (this.expanded === true) { | |
55 | this.pager_element.add($('div#notebook')).trigger('collapse_pager'); |
|
61 | this.pager_element.add($('div#notebook')).trigger('collapse_pager'); | |
56 | this.expanded = false; |
|
62 | this.expanded = false; | |
57 | }; |
|
63 | }; | |
58 | }; |
|
64 | }; | |
59 |
|
65 | |||
60 |
|
66 | |||
61 | Pager.prototype.expand = function () { |
|
67 | Pager.prototype.expand = function () { | |
62 | if (this.expanded !== true) { |
|
68 | if (this.expanded !== true) { | |
63 | this.pager_element.add($('div#notebook')).trigger('expand_pager'); |
|
69 | this.pager_element.add($('div#notebook')).trigger('expand_pager'); | |
64 | this.expanded = true; |
|
70 | this.expanded = true; | |
65 | }; |
|
71 | }; | |
66 | }; |
|
72 | }; | |
67 |
|
73 | |||
68 |
|
74 | |||
69 | Pager.prototype.toggle = function () { |
|
75 | Pager.prototype.toggle = function () { | |
70 | if (this.expanded === true) { |
|
76 | if (this.expanded === true) { | |
71 | this.collapse(); |
|
77 | this.collapse(); | |
72 | } else { |
|
78 | } else { | |
73 | this.expand(); |
|
79 | this.expand(); | |
74 | }; |
|
80 | }; | |
75 | }; |
|
81 | }; | |
76 |
|
82 | |||
77 |
|
83 | |||
78 | Pager.prototype.clear = function (text) { |
|
84 | Pager.prototype.clear = function (text) { | |
79 | this.pager_element.empty(); |
|
85 | this.pager_element.empty(); | |
80 | }; |
|
86 | }; | |
81 |
|
87 | |||
82 |
|
88 | |||
83 | Pager.prototype.append_text = function (text) { |
|
89 | Pager.prototype.append_text = function (text) { | |
84 | var toinsert = $("<div/>").addClass("output_area output_stream"); |
|
90 | var toinsert = $("<div/>").addClass("output_area output_stream"); | |
85 | toinsert.append($('<pre/>').html(utils.fixConsole(text))); |
|
91 | toinsert.append($('<pre/>').html(utils.fixConsole(text))); | |
86 | this.pager_element.append(toinsert); |
|
92 | this.pager_element.append(toinsert); | |
87 | }; |
|
93 | }; | |
88 |
|
94 | |||
89 |
|
95 | |||
90 | IPython.Pager = Pager; |
|
96 | IPython.Pager = Pager; | |
91 |
|
97 | |||
92 | return IPython; |
|
98 | return IPython; | |
93 |
|
99 | |||
94 | }(IPython)); |
|
100 | }(IPython)); | |
95 |
|
101 |
@@ -1,245 +1,251 b'' | |||||
|
1 | //---------------------------------------------------------------------------- | |||
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |||
|
3 | // | |||
|
4 | // Distributed under the terms of the BSD License. The full license is in | |||
|
5 | // the file COPYING, distributed as part of this software. | |||
|
6 | //---------------------------------------------------------------------------- | |||
1 |
|
|
7 | ||
2 | //============================================================================ |
|
8 | //============================================================================ | |
3 | // Cell |
|
9 | // PanelSection | |
4 | //============================================================================ |
|
10 | //============================================================================ | |
5 |
|
11 | |||
6 | var IPython = (function (IPython) { |
|
12 | var IPython = (function (IPython) { | |
7 |
|
13 | |||
8 | var utils = IPython.utils; |
|
14 | var utils = IPython.utils; | |
9 |
|
15 | |||
10 | // Base PanelSection class |
|
16 | // Base PanelSection class | |
11 |
|
17 | |||
12 | var PanelSection = function (selector) { |
|
18 | var PanelSection = function (selector) { | |
13 | this.selector = selector; |
|
19 | this.selector = selector; | |
14 | if (this.selector !== undefined) { |
|
20 | if (this.selector !== undefined) { | |
15 | this.element = $(selector); |
|
21 | this.element = $(selector); | |
16 | this.header = this.element.find('h3.section_header'); |
|
22 | this.header = this.element.find('h3.section_header'); | |
17 | this.content = this.element.find('div.section_content'); |
|
23 | this.content = this.element.find('div.section_content'); | |
18 | this.style(); |
|
24 | this.style(); | |
19 | this.bind_events(); |
|
25 | this.bind_events(); | |
20 | } |
|
26 | } | |
21 | this.expanded = true; |
|
27 | this.expanded = true; | |
22 | }; |
|
28 | }; | |
23 |
|
29 | |||
24 |
|
30 | |||
25 | PanelSection.prototype.style = function () { |
|
31 | PanelSection.prototype.style = function () { | |
26 | this.header.addClass('ui-widget ui-state-default'); |
|
32 | this.header.addClass('ui-widget ui-state-default'); | |
27 | this.content.addClass('ui-widget section_content'); |
|
33 | this.content.addClass('ui-widget section_content'); | |
28 | }; |
|
34 | }; | |
29 |
|
35 | |||
30 |
|
36 | |||
31 | PanelSection.prototype.bind_events = function () { |
|
37 | PanelSection.prototype.bind_events = function () { | |
32 | var that = this; |
|
38 | var that = this; | |
33 | this.header.click(function () { |
|
39 | this.header.click(function () { | |
34 | that.toggle(); |
|
40 | that.toggle(); | |
35 | }); |
|
41 | }); | |
36 | this.header.hover(function () { |
|
42 | this.header.hover(function () { | |
37 | that.header.toggleClass('ui-state-hover'); |
|
43 | that.header.toggleClass('ui-state-hover'); | |
38 | }); |
|
44 | }); | |
39 | }; |
|
45 | }; | |
40 |
|
46 | |||
41 |
|
47 | |||
42 | PanelSection.prototype.expand = function () { |
|
48 | PanelSection.prototype.expand = function () { | |
43 | if (!this.expanded) { |
|
49 | if (!this.expanded) { | |
44 | this.content.slideDown('fast'); |
|
50 | this.content.slideDown('fast'); | |
45 | this.expanded = true; |
|
51 | this.expanded = true; | |
46 | }; |
|
52 | }; | |
47 | }; |
|
53 | }; | |
48 |
|
54 | |||
49 |
|
55 | |||
50 | PanelSection.prototype.collapse = function () { |
|
56 | PanelSection.prototype.collapse = function () { | |
51 | if (this.expanded) { |
|
57 | if (this.expanded) { | |
52 | this.content.slideUp('fast'); |
|
58 | this.content.slideUp('fast'); | |
53 | this.expanded = false; |
|
59 | this.expanded = false; | |
54 | }; |
|
60 | }; | |
55 | }; |
|
61 | }; | |
56 |
|
62 | |||
57 |
|
63 | |||
58 | PanelSection.prototype.toggle = function () { |
|
64 | PanelSection.prototype.toggle = function () { | |
59 | if (this.expanded === true) { |
|
65 | if (this.expanded === true) { | |
60 | this.collapse(); |
|
66 | this.collapse(); | |
61 | } else { |
|
67 | } else { | |
62 | this.expand(); |
|
68 | this.expand(); | |
63 | }; |
|
69 | }; | |
64 | }; |
|
70 | }; | |
65 |
|
71 | |||
66 |
|
72 | |||
67 | PanelSection.prototype.create_children = function () {}; |
|
73 | PanelSection.prototype.create_children = function () {}; | |
68 |
|
74 | |||
69 |
|
75 | |||
70 | // NotebookSection |
|
76 | // NotebookSection | |
71 |
|
77 | |||
72 | var NotebookSection = function () { |
|
78 | var NotebookSection = function () { | |
73 | PanelSection.apply(this, arguments); |
|
79 | PanelSection.apply(this, arguments); | |
74 | }; |
|
80 | }; | |
75 |
|
81 | |||
76 |
|
82 | |||
77 | NotebookSection.prototype = new PanelSection(); |
|
83 | NotebookSection.prototype = new PanelSection(); | |
78 |
|
84 | |||
79 |
|
85 | |||
80 | NotebookSection.prototype.style = function () { |
|
86 | NotebookSection.prototype.style = function () { | |
81 | PanelSection.prototype.style.apply(this); |
|
87 | PanelSection.prototype.style.apply(this); | |
82 | this.content.addClass('ui-helper-clearfix'); |
|
88 | this.content.addClass('ui-helper-clearfix'); | |
83 | this.content.find('div.section_row').addClass('ui-helper-clearfix'); |
|
89 | this.content.find('div.section_row').addClass('ui-helper-clearfix'); | |
84 | this.content.find('#new_open').buttonset(); |
|
90 | this.content.find('#new_open').buttonset(); | |
85 | this.content.find('#download_notebook').button(); |
|
91 | this.content.find('#download_notebook').button(); | |
86 | this.content.find('#upload_notebook').button(); |
|
92 | this.content.find('#upload_notebook').button(); | |
87 | this.content.find('#download_format').addClass('ui-widget ui-widget-content'); |
|
93 | this.content.find('#download_format').addClass('ui-widget ui-widget-content'); | |
88 | this.content.find('#download_format option').addClass('ui-widget ui-widget-content'); |
|
94 | this.content.find('#download_format option').addClass('ui-widget ui-widget-content'); | |
89 | }; |
|
95 | }; | |
90 |
|
96 | |||
91 |
|
97 | |||
92 | NotebookSection.prototype.bind_events = function () { |
|
98 | NotebookSection.prototype.bind_events = function () { | |
93 | PanelSection.prototype.bind_events.apply(this); |
|
99 | PanelSection.prototype.bind_events.apply(this); | |
94 | var that = this; |
|
100 | var that = this; | |
95 | this.content.find('#new_notebook').click(function () { |
|
101 | this.content.find('#new_notebook').click(function () { | |
96 | window.open('/new'); |
|
102 | window.open('/new'); | |
97 | }); |
|
103 | }); | |
98 | this.content.find('#open_notebook').click(function () { |
|
104 | this.content.find('#open_notebook').click(function () { | |
99 | window.open('/'); |
|
105 | window.open('/'); | |
100 | }); |
|
106 | }); | |
101 | this.content.find('#download_notebook').click(function () { |
|
107 | this.content.find('#download_notebook').click(function () { | |
102 | var format = that.content.find('#download_format').val(); |
|
108 | var format = that.content.find('#download_format').val(); | |
103 | var notebook_id = IPython.save_widget.get_notebook_id(); |
|
109 | var notebook_id = IPython.save_widget.get_notebook_id(); | |
104 | var url = '/notebooks/' + notebook_id + '?format=' + format; |
|
110 | var url = '/notebooks/' + notebook_id + '?format=' + format; | |
105 | window.open(url,'_newtab'); |
|
111 | window.open(url,'_newtab'); | |
106 | }); |
|
112 | }); | |
107 | }; |
|
113 | }; | |
108 |
|
114 | |||
109 | // CellSection |
|
115 | // CellSection | |
110 |
|
116 | |||
111 | var CellSection = function () { |
|
117 | var CellSection = function () { | |
112 | PanelSection.apply(this, arguments); |
|
118 | PanelSection.apply(this, arguments); | |
113 | }; |
|
119 | }; | |
114 |
|
120 | |||
115 |
|
121 | |||
116 | CellSection.prototype = new PanelSection(); |
|
122 | CellSection.prototype = new PanelSection(); | |
117 |
|
123 | |||
118 |
|
124 | |||
119 | CellSection.prototype.style = function () { |
|
125 | CellSection.prototype.style = function () { | |
120 | PanelSection.prototype.style.apply(this); |
|
126 | PanelSection.prototype.style.apply(this); | |
121 | this.content.addClass('ui-helper-clearfix'); |
|
127 | this.content.addClass('ui-helper-clearfix'); | |
122 | this.content.find('div.section_row').addClass('ui-helper-clearfix'); |
|
128 | this.content.find('div.section_row').addClass('ui-helper-clearfix'); | |
123 | this.content.find('#delete_cell').button(); |
|
129 | this.content.find('#delete_cell').button(); | |
124 | this.content.find('#insert').buttonset(); |
|
130 | this.content.find('#insert').buttonset(); | |
125 | this.content.find('#move').buttonset(); |
|
131 | this.content.find('#move').buttonset(); | |
126 | this.content.find('#cell_type').buttonset(); |
|
132 | this.content.find('#cell_type').buttonset(); | |
127 | this.content.find('#toggle_output').buttonset(); |
|
133 | this.content.find('#toggle_output').buttonset(); | |
128 | this.content.find('#run_cells').buttonset(); |
|
134 | this.content.find('#run_cells').buttonset(); | |
129 | }; |
|
135 | }; | |
130 |
|
136 | |||
131 |
|
137 | |||
132 | CellSection.prototype.bind_events = function () { |
|
138 | CellSection.prototype.bind_events = function () { | |
133 | PanelSection.prototype.bind_events.apply(this); |
|
139 | PanelSection.prototype.bind_events.apply(this); | |
134 | this.content.find('#collapse_cell').click(function () { |
|
140 | this.content.find('#collapse_cell').click(function () { | |
135 | IPython.notebook.collapse(); |
|
141 | IPython.notebook.collapse(); | |
136 | }); |
|
142 | }); | |
137 | this.content.find('#expand_cell').click(function () { |
|
143 | this.content.find('#expand_cell').click(function () { | |
138 | IPython.notebook.expand(); |
|
144 | IPython.notebook.expand(); | |
139 | }); |
|
145 | }); | |
140 | this.content.find('#clear_all_output').click(function () { |
|
146 | this.content.find('#clear_all_output').click(function () { | |
141 | IPython.notebook.clear_all_output(); |
|
147 | IPython.notebook.clear_all_output(); | |
142 | }); |
|
148 | }); | |
143 | this.content.find('#delete_cell').click(function () { |
|
149 | this.content.find('#delete_cell').click(function () { | |
144 | IPython.notebook.delete_cell(); |
|
150 | IPython.notebook.delete_cell(); | |
145 | }); |
|
151 | }); | |
146 | this.content.find('#insert_cell_above').click(function () { |
|
152 | this.content.find('#insert_cell_above').click(function () { | |
147 | IPython.notebook.insert_code_cell_before(); |
|
153 | IPython.notebook.insert_code_cell_before(); | |
148 | }); |
|
154 | }); | |
149 | this.content.find('#insert_cell_below').click(function () { |
|
155 | this.content.find('#insert_cell_below').click(function () { | |
150 | IPython.notebook.insert_code_cell_after(); |
|
156 | IPython.notebook.insert_code_cell_after(); | |
151 | }); |
|
157 | }); | |
152 | this.content.find('#move_cell_up').click(function () { |
|
158 | this.content.find('#move_cell_up').click(function () { | |
153 | IPython.notebook.move_cell_up(); |
|
159 | IPython.notebook.move_cell_up(); | |
154 | }); |
|
160 | }); | |
155 | this.content.find('#move_cell_down').click(function () { |
|
161 | this.content.find('#move_cell_down').click(function () { | |
156 | IPython.notebook.move_cell_down(); |
|
162 | IPython.notebook.move_cell_down(); | |
157 | }); |
|
163 | }); | |
158 | this.content.find('#to_code').click(function () { |
|
164 | this.content.find('#to_code').click(function () { | |
159 | IPython.notebook.to_code(); |
|
165 | IPython.notebook.to_code(); | |
160 | }); |
|
166 | }); | |
161 | this.content.find('#to_html').click(function () { |
|
167 | this.content.find('#to_html').click(function () { | |
162 | IPython.notebook.to_html(); |
|
168 | IPython.notebook.to_html(); | |
163 | }); |
|
169 | }); | |
164 | this.content.find('#to_markdown').click(function () { |
|
170 | this.content.find('#to_markdown').click(function () { | |
165 | IPython.notebook.to_markdown(); |
|
171 | IPython.notebook.to_markdown(); | |
166 | }); |
|
172 | }); | |
167 | this.content.find('#run_selected_cell').click(function () { |
|
173 | this.content.find('#run_selected_cell').click(function () { | |
168 | IPython.notebook.execute_selected_cell(); |
|
174 | IPython.notebook.execute_selected_cell(); | |
169 | }); |
|
175 | }); | |
170 | this.content.find('#run_all_cells').click(function () { |
|
176 | this.content.find('#run_all_cells').click(function () { | |
171 | IPython.notebook.execute_all_cells(); |
|
177 | IPython.notebook.execute_all_cells(); | |
172 | }); |
|
178 | }); | |
173 | this.content.find('#autoindent').change(function () { |
|
179 | this.content.find('#autoindent').change(function () { | |
174 | var state = $('#autoindent').prop('checked'); |
|
180 | var state = $('#autoindent').prop('checked'); | |
175 | IPython.notebook.set_autoindent(state); |
|
181 | IPython.notebook.set_autoindent(state); | |
176 | }); |
|
182 | }); | |
177 | }; |
|
183 | }; | |
178 |
|
184 | |||
179 |
|
185 | |||
180 | // KernelSection |
|
186 | // KernelSection | |
181 |
|
187 | |||
182 | var KernelSection = function () { |
|
188 | var KernelSection = function () { | |
183 | PanelSection.apply(this, arguments); |
|
189 | PanelSection.apply(this, arguments); | |
184 | }; |
|
190 | }; | |
185 |
|
191 | |||
186 |
|
192 | |||
187 | KernelSection.prototype = new PanelSection(); |
|
193 | KernelSection.prototype = new PanelSection(); | |
188 |
|
194 | |||
189 |
|
195 | |||
190 | KernelSection.prototype.style = function () { |
|
196 | KernelSection.prototype.style = function () { | |
191 | PanelSection.prototype.style.apply(this); |
|
197 | PanelSection.prototype.style.apply(this); | |
192 | this.content.addClass('ui-helper-clearfix'); |
|
198 | this.content.addClass('ui-helper-clearfix'); | |
193 | this.content.find('div.section_row').addClass('ui-helper-clearfix'); |
|
199 | this.content.find('div.section_row').addClass('ui-helper-clearfix'); | |
194 | this.content.find('#int_restart').buttonset(); |
|
200 | this.content.find('#int_restart').buttonset(); | |
195 | }; |
|
201 | }; | |
196 |
|
202 | |||
197 |
|
203 | |||
198 | KernelSection.prototype.bind_events = function () { |
|
204 | KernelSection.prototype.bind_events = function () { | |
199 | PanelSection.prototype.bind_events.apply(this); |
|
205 | PanelSection.prototype.bind_events.apply(this); | |
200 | this.content.find('#restart_kernel').click(function () { |
|
206 | this.content.find('#restart_kernel').click(function () { | |
201 | IPython.notebook.restart_kernel(); |
|
207 | IPython.notebook.restart_kernel(); | |
202 | }); |
|
208 | }); | |
203 | this.content.find('#int_kernel').click(function () { |
|
209 | this.content.find('#int_kernel').click(function () { | |
204 | IPython.notebook.kernel.interrupt(); |
|
210 | IPython.notebook.kernel.interrupt(); | |
205 | }); |
|
211 | }); | |
206 | }; |
|
212 | }; | |
207 |
|
213 | |||
208 |
|
214 | |||
209 | // HelpSection |
|
215 | // HelpSection | |
210 |
|
216 | |||
211 | var HelpSection = function () { |
|
217 | var HelpSection = function () { | |
212 | PanelSection.apply(this, arguments); |
|
218 | PanelSection.apply(this, arguments); | |
213 | }; |
|
219 | }; | |
214 |
|
220 | |||
215 |
|
221 | |||
216 | HelpSection.prototype = new PanelSection(); |
|
222 | HelpSection.prototype = new PanelSection(); | |
217 |
|
223 | |||
218 |
|
224 | |||
219 | HelpSection.prototype.style = function () { |
|
225 | HelpSection.prototype.style = function () { | |
220 | PanelSection.prototype.style.apply(this); |
|
226 | PanelSection.prototype.style.apply(this); | |
221 | PanelSection.prototype.style.apply(this); |
|
227 | PanelSection.prototype.style.apply(this); | |
222 | this.content.addClass('ui-helper-clearfix'); |
|
228 | this.content.addClass('ui-helper-clearfix'); | |
223 | this.content.find('div.section_row').addClass('ui-helper-clearfix'); |
|
229 | this.content.find('div.section_row').addClass('ui-helper-clearfix'); | |
224 | this.content.find('#help_buttons0').buttonset(); |
|
230 | this.content.find('#help_buttons0').buttonset(); | |
225 | this.content.find('#help_buttons1').buttonset(); |
|
231 | this.content.find('#help_buttons1').buttonset(); | |
226 | }; |
|
232 | }; | |
227 |
|
233 | |||
228 |
|
234 | |||
229 | HelpSection.prototype.bind_events = function () { |
|
235 | HelpSection.prototype.bind_events = function () { | |
230 | PanelSection.prototype.bind_events.apply(this); |
|
236 | PanelSection.prototype.bind_events.apply(this); | |
231 | }; |
|
237 | }; | |
232 |
|
238 | |||
233 |
|
239 | |||
234 | // Set module variables |
|
240 | // Set module variables | |
235 |
|
241 | |||
236 | IPython.PanelSection = PanelSection; |
|
242 | IPython.PanelSection = PanelSection; | |
237 | IPython.NotebookSection = NotebookSection; |
|
243 | IPython.NotebookSection = NotebookSection; | |
238 | IPython.CellSection = CellSection; |
|
244 | IPython.CellSection = CellSection; | |
239 | IPython.KernelSection = KernelSection; |
|
245 | IPython.KernelSection = KernelSection; | |
240 | IPython.HelpSection = HelpSection; |
|
246 | IPython.HelpSection = HelpSection; | |
241 |
|
247 | |||
242 | return IPython; |
|
248 | return IPython; | |
243 |
|
249 | |||
244 | }(IPython)); |
|
250 | }(IPython)); | |
245 |
|
251 |
@@ -1,109 +1,115 b'' | |||||
|
1 | //---------------------------------------------------------------------------- | |||
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |||
|
3 | // | |||
|
4 | // Distributed under the terms of the BSD License. The full license is in | |||
|
5 | // the file COPYING, distributed as part of this software. | |||
|
6 | //---------------------------------------------------------------------------- | |||
1 |
|
|
7 | ||
2 | //============================================================================ |
|
8 | //============================================================================ | |
3 | // Cell |
|
9 | // SaveWidget | |
4 | //============================================================================ |
|
10 | //============================================================================ | |
5 |
|
11 | |||
6 | var IPython = (function (IPython) { |
|
12 | var IPython = (function (IPython) { | |
7 |
|
13 | |||
8 | var utils = IPython.utils; |
|
14 | var utils = IPython.utils; | |
9 |
|
15 | |||
10 | var SaveWidget = function (selector) { |
|
16 | var SaveWidget = function (selector) { | |
11 | this.selector = selector; |
|
17 | this.selector = selector; | |
12 | this.notebook_name_re = /[^/\\]+/ |
|
18 | this.notebook_name_re = /[^/\\]+/ | |
13 | if (this.selector !== undefined) { |
|
19 | if (this.selector !== undefined) { | |
14 | this.element = $(selector); |
|
20 | this.element = $(selector); | |
15 | this.style(); |
|
21 | this.style(); | |
16 | this.bind_events(); |
|
22 | this.bind_events(); | |
17 | } |
|
23 | } | |
18 | }; |
|
24 | }; | |
19 |
|
25 | |||
20 |
|
26 | |||
21 | SaveWidget.prototype.style = function () { |
|
27 | SaveWidget.prototype.style = function () { | |
22 | this.element.find('input#notebook_name').addClass('ui-widget ui-widget-content'); |
|
28 | this.element.find('input#notebook_name').addClass('ui-widget ui-widget-content'); | |
23 | this.element.find('button#save_notebook').button(); |
|
29 | this.element.find('button#save_notebook').button(); | |
24 | var left_panel_width = $('div#left_panel').outerWidth(); |
|
30 | var left_panel_width = $('div#left_panel').outerWidth(); | |
25 | var left_panel_splitter_width = $('div#left_panel_splitter').outerWidth(); |
|
31 | var left_panel_splitter_width = $('div#left_panel_splitter').outerWidth(); | |
26 | $('span#save_widget').css({marginLeft:left_panel_width+left_panel_splitter_width}); |
|
32 | $('span#save_widget').css({marginLeft:left_panel_width+left_panel_splitter_width}); | |
27 | }; |
|
33 | }; | |
28 |
|
34 | |||
29 |
|
35 | |||
30 | SaveWidget.prototype.bind_events = function () { |
|
36 | SaveWidget.prototype.bind_events = function () { | |
31 | var that = this; |
|
37 | var that = this; | |
32 | this.element.find('button#save_notebook').click(function () { |
|
38 | this.element.find('button#save_notebook').click(function () { | |
33 | IPython.notebook.save_notebook(); |
|
39 | IPython.notebook.save_notebook(); | |
34 | that.set_document_title(); |
|
40 | that.set_document_title(); | |
35 | }); |
|
41 | }); | |
36 | }; |
|
42 | }; | |
37 |
|
43 | |||
38 |
|
44 | |||
39 | SaveWidget.prototype.get_notebook_name = function () { |
|
45 | SaveWidget.prototype.get_notebook_name = function () { | |
40 | return this.element.find('input#notebook_name').attr('value'); |
|
46 | return this.element.find('input#notebook_name').attr('value'); | |
41 | } |
|
47 | } | |
42 |
|
48 | |||
43 |
|
49 | |||
44 | SaveWidget.prototype.set_notebook_name = function (nbname) { |
|
50 | SaveWidget.prototype.set_notebook_name = function (nbname) { | |
45 | this.element.find('input#notebook_name').attr('value',nbname); |
|
51 | this.element.find('input#notebook_name').attr('value',nbname); | |
46 | this.set_document_title(); |
|
52 | this.set_document_title(); | |
47 | } |
|
53 | } | |
48 |
|
54 | |||
49 |
|
55 | |||
50 | SaveWidget.prototype.set_document_title = function () { |
|
56 | SaveWidget.prototype.set_document_title = function () { | |
51 | nbname = this.get_notebook_name(); |
|
57 | nbname = this.get_notebook_name(); | |
52 | document.title = 'IPy: ' + nbname; |
|
58 | document.title = 'IPy: ' + nbname; | |
53 | }; |
|
59 | }; | |
54 |
|
60 | |||
55 |
|
61 | |||
56 | SaveWidget.prototype.get_notebook_id = function () { |
|
62 | SaveWidget.prototype.get_notebook_id = function () { | |
57 | return this.element.find('span#notebook_id').text() |
|
63 | return this.element.find('span#notebook_id').text() | |
58 | }; |
|
64 | }; | |
59 |
|
65 | |||
60 |
|
66 | |||
61 | SaveWidget.prototype.update_url = function () { |
|
67 | SaveWidget.prototype.update_url = function () { | |
62 | var notebook_id = this.get_notebook_id(); |
|
68 | var notebook_id = this.get_notebook_id(); | |
63 | if (notebook_id !== '') { |
|
69 | if (notebook_id !== '') { | |
64 | window.history.replaceState({}, '', notebook_id); |
|
70 | window.history.replaceState({}, '', notebook_id); | |
65 | }; |
|
71 | }; | |
66 | }; |
|
72 | }; | |
67 |
|
73 | |||
68 |
|
74 | |||
69 | SaveWidget.prototype.test_notebook_name = function () { |
|
75 | SaveWidget.prototype.test_notebook_name = function () { | |
70 | var nbname = this.get_notebook_name(); |
|
76 | var nbname = this.get_notebook_name(); | |
71 | if (this.notebook_name_re.test(nbname)) { |
|
77 | if (this.notebook_name_re.test(nbname)) { | |
72 | return true; |
|
78 | return true; | |
73 | } else { |
|
79 | } else { | |
74 | var bad_name = $('<div/>'); |
|
80 | var bad_name = $('<div/>'); | |
75 | bad_name.html( |
|
81 | bad_name.html( | |
76 | "The notebook name you entered (" + |
|
82 | "The notebook name you entered (" + | |
77 | nbname + |
|
83 | nbname + | |
78 | ") is not valid. Notebook names can contain any characters except / and \\" |
|
84 | ") is not valid. Notebook names can contain any characters except / and \\" | |
79 | ); |
|
85 | ); | |
80 | bad_name.dialog({title: 'Invalid name', modal: true}); |
|
86 | bad_name.dialog({title: 'Invalid name', modal: true}); | |
81 | return false; |
|
87 | return false; | |
82 | }; |
|
88 | }; | |
83 | }; |
|
89 | }; | |
84 |
|
90 | |||
85 |
|
91 | |||
86 | SaveWidget.prototype.status_save = function () { |
|
92 | SaveWidget.prototype.status_save = function () { | |
87 | this.element.find('span.ui-button-text').text('Save'); |
|
93 | this.element.find('span.ui-button-text').text('Save'); | |
88 | this.element.find('button#save_notebook').button('enable'); |
|
94 | this.element.find('button#save_notebook').button('enable'); | |
89 | }; |
|
95 | }; | |
90 |
|
96 | |||
91 |
|
97 | |||
92 | SaveWidget.prototype.status_saving = function () { |
|
98 | SaveWidget.prototype.status_saving = function () { | |
93 | this.element.find('span.ui-button-text').text('Saving'); |
|
99 | this.element.find('span.ui-button-text').text('Saving'); | |
94 | this.element.find('button#save_notebook').button('disable'); |
|
100 | this.element.find('button#save_notebook').button('disable'); | |
95 | }; |
|
101 | }; | |
96 |
|
102 | |||
97 |
|
103 | |||
98 | SaveWidget.prototype.status_loading = function () { |
|
104 | SaveWidget.prototype.status_loading = function () { | |
99 | this.element.find('span.ui-button-text').text('Loading'); |
|
105 | this.element.find('span.ui-button-text').text('Loading'); | |
100 | this.element.find('button#save_notebook').button('disable'); |
|
106 | this.element.find('button#save_notebook').button('disable'); | |
101 | }; |
|
107 | }; | |
102 |
|
108 | |||
103 |
|
109 | |||
104 | IPython.SaveWidget = SaveWidget; |
|
110 | IPython.SaveWidget = SaveWidget; | |
105 |
|
111 | |||
106 | return IPython; |
|
112 | return IPython; | |
107 |
|
113 | |||
108 | }(IPython)); |
|
114 | }(IPython)); | |
109 |
|
115 |
@@ -1,248 +1,254 b'' | |||||
|
1 | //---------------------------------------------------------------------------- | |||
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |||
|
3 | // | |||
|
4 | // Distributed under the terms of the BSD License. The full license is in | |||
|
5 | // the file COPYING, distributed as part of this software. | |||
|
6 | //---------------------------------------------------------------------------- | |||
1 |
|
|
7 | ||
2 | //============================================================================ |
|
8 | //============================================================================ | |
3 | // TextCell |
|
9 | // TextCell | |
4 | //============================================================================ |
|
10 | //============================================================================ | |
5 |
|
11 | |||
6 | var IPython = (function (IPython) { |
|
12 | var IPython = (function (IPython) { | |
7 |
|
13 | |||
8 | // TextCell base class |
|
14 | // TextCell base class | |
9 |
|
15 | |||
10 | var TextCell = function (notebook) { |
|
16 | var TextCell = function (notebook) { | |
11 | this.code_mirror_mode = this.code_mirror_mode || 'htmlmixed'; |
|
17 | this.code_mirror_mode = this.code_mirror_mode || 'htmlmixed'; | |
12 | this.placeholder = this.placeholder || ''; |
|
18 | this.placeholder = this.placeholder || ''; | |
13 | IPython.Cell.apply(this, arguments); |
|
19 | IPython.Cell.apply(this, arguments); | |
14 | this.rendered = false; |
|
20 | this.rendered = false; | |
15 | this.cell_type = this.cell_type || 'text'; |
|
21 | this.cell_type = this.cell_type || 'text'; | |
16 | }; |
|
22 | }; | |
17 |
|
23 | |||
18 |
|
24 | |||
19 | TextCell.prototype = new IPython.Cell(); |
|
25 | TextCell.prototype = new IPython.Cell(); | |
20 |
|
26 | |||
21 |
|
27 | |||
22 | TextCell.prototype.create_element = function () { |
|
28 | TextCell.prototype.create_element = function () { | |
23 | var cell = $("<div>").addClass('cell text_cell border-box-sizing'); |
|
29 | var cell = $("<div>").addClass('cell text_cell border-box-sizing'); | |
24 | var input_area = $('<div/>').addClass('text_cell_input'); |
|
30 | var input_area = $('<div/>').addClass('text_cell_input'); | |
25 | this.code_mirror = CodeMirror(input_area.get(0), { |
|
31 | this.code_mirror = CodeMirror(input_area.get(0), { | |
26 | indentUnit : 4, |
|
32 | indentUnit : 4, | |
27 | mode: this.code_mirror_mode, |
|
33 | mode: this.code_mirror_mode, | |
28 | theme: 'default', |
|
34 | theme: 'default', | |
29 | value: this.placeholder |
|
35 | value: this.placeholder | |
30 | }); |
|
36 | }); | |
31 | // The tabindex=-1 makes this div focusable. |
|
37 | // The tabindex=-1 makes this div focusable. | |
32 | var render_area = $('<div/>').addClass('text_cell_render'). |
|
38 | var render_area = $('<div/>').addClass('text_cell_render'). | |
33 | addClass('rendered_html').attr('tabindex','-1'); |
|
39 | addClass('rendered_html').attr('tabindex','-1'); | |
34 | cell.append(input_area).append(render_area); |
|
40 | cell.append(input_area).append(render_area); | |
35 | this.element = cell; |
|
41 | this.element = cell; | |
36 | }; |
|
42 | }; | |
37 |
|
43 | |||
38 |
|
44 | |||
39 | TextCell.prototype.bind_events = function () { |
|
45 | TextCell.prototype.bind_events = function () { | |
40 | IPython.Cell.prototype.bind_events.apply(this); |
|
46 | IPython.Cell.prototype.bind_events.apply(this); | |
41 | var that = this; |
|
47 | var that = this; | |
42 | this.element.keydown(function (event) { |
|
48 | this.element.keydown(function (event) { | |
43 | if (event.which === 13) { |
|
49 | if (event.which === 13) { | |
44 | if (that.rendered) { |
|
50 | if (that.rendered) { | |
45 | that.edit(); |
|
51 | that.edit(); | |
46 | event.preventDefault(); |
|
52 | event.preventDefault(); | |
47 | }; |
|
53 | }; | |
48 | }; |
|
54 | }; | |
49 | }); |
|
55 | }); | |
50 | }; |
|
56 | }; | |
51 |
|
57 | |||
52 |
|
58 | |||
53 | TextCell.prototype.select = function () { |
|
59 | TextCell.prototype.select = function () { | |
54 | IPython.Cell.prototype.select.apply(this); |
|
60 | IPython.Cell.prototype.select.apply(this); | |
55 | var output = this.element.find("div.text_cell_render"); |
|
61 | var output = this.element.find("div.text_cell_render"); | |
56 | output.trigger('focus'); |
|
62 | output.trigger('focus'); | |
57 | }; |
|
63 | }; | |
58 |
|
64 | |||
59 |
|
65 | |||
60 | TextCell.prototype.edit = function () { |
|
66 | TextCell.prototype.edit = function () { | |
61 | if (this.rendered === true) { |
|
67 | if (this.rendered === true) { | |
62 | var text_cell = this.element; |
|
68 | var text_cell = this.element; | |
63 | var output = text_cell.find("div.text_cell_render"); |
|
69 | var output = text_cell.find("div.text_cell_render"); | |
64 | output.hide(); |
|
70 | output.hide(); | |
65 | text_cell.find('div.text_cell_input').show(); |
|
71 | text_cell.find('div.text_cell_input').show(); | |
66 | this.code_mirror.focus(); |
|
72 | this.code_mirror.focus(); | |
67 | this.code_mirror.refresh(); |
|
73 | this.code_mirror.refresh(); | |
68 | this.rendered = false; |
|
74 | this.rendered = false; | |
69 | }; |
|
75 | }; | |
70 | }; |
|
76 | }; | |
71 |
|
77 | |||
72 |
|
78 | |||
73 | // Subclasses must define render. |
|
79 | // Subclasses must define render. | |
74 | TextCell.prototype.render = function () {}; |
|
80 | TextCell.prototype.render = function () {}; | |
75 |
|
81 | |||
76 |
|
82 | |||
77 | TextCell.prototype.config_mathjax = function () { |
|
83 | TextCell.prototype.config_mathjax = function () { | |
78 | var text_cell = this.element; |
|
84 | var text_cell = this.element; | |
79 | var that = this; |
|
85 | var that = this; | |
80 | text_cell.click(function () { |
|
86 | text_cell.click(function () { | |
81 | that.edit(); |
|
87 | that.edit(); | |
82 | }).focusout(function () { |
|
88 | }).focusout(function () { | |
83 | that.render(); |
|
89 | that.render(); | |
84 | }); |
|
90 | }); | |
85 |
|
91 | |||
86 | text_cell.trigger("focusout"); |
|
92 | text_cell.trigger("focusout"); | |
87 | }; |
|
93 | }; | |
88 |
|
94 | |||
89 |
|
95 | |||
90 | TextCell.prototype.get_source = function() { |
|
96 | TextCell.prototype.get_source = function() { | |
91 | return this.code_mirror.getValue(); |
|
97 | return this.code_mirror.getValue(); | |
92 | }; |
|
98 | }; | |
93 |
|
99 | |||
94 |
|
100 | |||
95 | TextCell.prototype.set_source = function(text) { |
|
101 | TextCell.prototype.set_source = function(text) { | |
96 | this.code_mirror.setValue(text); |
|
102 | this.code_mirror.setValue(text); | |
97 | this.code_mirror.refresh(); |
|
103 | this.code_mirror.refresh(); | |
98 | }; |
|
104 | }; | |
99 |
|
105 | |||
100 |
|
106 | |||
101 | TextCell.prototype.get_rendered = function() { |
|
107 | TextCell.prototype.get_rendered = function() { | |
102 | return this.element.find('div.text_cell_render').html(); |
|
108 | return this.element.find('div.text_cell_render').html(); | |
103 | }; |
|
109 | }; | |
104 |
|
110 | |||
105 |
|
111 | |||
106 | TextCell.prototype.set_rendered = function(text) { |
|
112 | TextCell.prototype.set_rendered = function(text) { | |
107 | this.element.find('div.text_cell_render').html(text); |
|
113 | this.element.find('div.text_cell_render').html(text); | |
108 | }; |
|
114 | }; | |
109 |
|
115 | |||
110 |
|
116 | |||
111 | TextCell.prototype.at_top = function () { |
|
117 | TextCell.prototype.at_top = function () { | |
112 | if (this.rendered) { |
|
118 | if (this.rendered) { | |
113 | return true; |
|
119 | return true; | |
114 | } else { |
|
120 | } else { | |
115 | return false; |
|
121 | return false; | |
116 | } |
|
122 | } | |
117 | }; |
|
123 | }; | |
118 |
|
124 | |||
119 |
|
125 | |||
120 | TextCell.prototype.at_bottom = function () { |
|
126 | TextCell.prototype.at_bottom = function () { | |
121 | if (this.rendered) { |
|
127 | if (this.rendered) { | |
122 | return true; |
|
128 | return true; | |
123 | } else { |
|
129 | } else { | |
124 | return false; |
|
130 | return false; | |
125 | } |
|
131 | } | |
126 | }; |
|
132 | }; | |
127 |
|
133 | |||
128 |
|
134 | |||
129 | TextCell.prototype.fromJSON = function (data) { |
|
135 | TextCell.prototype.fromJSON = function (data) { | |
130 | if (data.cell_type === this.cell_type) { |
|
136 | if (data.cell_type === this.cell_type) { | |
131 | if (data.source !== undefined) { |
|
137 | if (data.source !== undefined) { | |
132 | this.set_source(data.source); |
|
138 | this.set_source(data.source); | |
133 | this.set_rendered(data.rendered || ''); |
|
139 | this.set_rendered(data.rendered || ''); | |
134 | this.rendered = false; |
|
140 | this.rendered = false; | |
135 | this.render(); |
|
141 | this.render(); | |
136 | }; |
|
142 | }; | |
137 | }; |
|
143 | }; | |
138 | }; |
|
144 | }; | |
139 |
|
145 | |||
140 |
|
146 | |||
141 | TextCell.prototype.toJSON = function () { |
|
147 | TextCell.prototype.toJSON = function () { | |
142 | var data = {} |
|
148 | var data = {} | |
143 | data.cell_type = this.cell_type; |
|
149 | data.cell_type = this.cell_type; | |
144 | data.source = this.get_source(); |
|
150 | data.source = this.get_source(); | |
145 | return data; |
|
151 | return data; | |
146 | }; |
|
152 | }; | |
147 |
|
153 | |||
148 |
|
154 | |||
149 | // HTMLCell |
|
155 | // HTMLCell | |
150 |
|
156 | |||
151 | var HTMLCell = function (notebook) { |
|
157 | var HTMLCell = function (notebook) { | |
152 | this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$"; |
|
158 | this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$"; | |
153 | IPython.TextCell.apply(this, arguments); |
|
159 | IPython.TextCell.apply(this, arguments); | |
154 | this.cell_type = 'html'; |
|
160 | this.cell_type = 'html'; | |
155 | }; |
|
161 | }; | |
156 |
|
162 | |||
157 |
|
163 | |||
158 | HTMLCell.prototype = new TextCell(); |
|
164 | HTMLCell.prototype = new TextCell(); | |
159 |
|
165 | |||
160 |
|
166 | |||
161 | HTMLCell.prototype.render = function () { |
|
167 | HTMLCell.prototype.render = function () { | |
162 | if (this.rendered === false) { |
|
168 | if (this.rendered === false) { | |
163 | var text = this.get_source(); |
|
169 | var text = this.get_source(); | |
164 | if (text === "") {text = this.placeholder;}; |
|
170 | if (text === "") {text = this.placeholder;}; | |
165 | this.set_rendered(text); |
|
171 | this.set_rendered(text); | |
166 | MathJax.Hub.Queue(["Typeset",MathJax.Hub]); |
|
172 | MathJax.Hub.Queue(["Typeset",MathJax.Hub]); | |
167 | this.element.find('div.text_cell_input').hide(); |
|
173 | this.element.find('div.text_cell_input').hide(); | |
168 | this.element.find("div.text_cell_render").show(); |
|
174 | this.element.find("div.text_cell_render").show(); | |
169 | this.rendered = true; |
|
175 | this.rendered = true; | |
170 | }; |
|
176 | }; | |
171 | }; |
|
177 | }; | |
172 |
|
178 | |||
173 |
|
179 | |||
174 | // MarkdownCell |
|
180 | // MarkdownCell | |
175 |
|
181 | |||
176 | var MarkdownCell = function (notebook) { |
|
182 | var MarkdownCell = function (notebook) { | |
177 | this.placeholder = "Type *Markdown* and LaTeX: $\\alpha^2$"; |
|
183 | this.placeholder = "Type *Markdown* and LaTeX: $\\alpha^2$"; | |
178 | IPython.TextCell.apply(this, arguments); |
|
184 | IPython.TextCell.apply(this, arguments); | |
179 | this.cell_type = 'markdown'; |
|
185 | this.cell_type = 'markdown'; | |
180 | }; |
|
186 | }; | |
181 |
|
187 | |||
182 |
|
188 | |||
183 | MarkdownCell.prototype = new TextCell(); |
|
189 | MarkdownCell.prototype = new TextCell(); | |
184 |
|
190 | |||
185 |
|
191 | |||
186 | MarkdownCell.prototype.render = function () { |
|
192 | MarkdownCell.prototype.render = function () { | |
187 | if (this.rendered === false) { |
|
193 | if (this.rendered === false) { | |
188 | var text = this.get_source(); |
|
194 | var text = this.get_source(); | |
189 | if (text === "") {text = this.placeholder;}; |
|
195 | if (text === "") {text = this.placeholder;}; | |
190 | var html = IPython.markdown_converter.makeHtml(text); |
|
196 | var html = IPython.markdown_converter.makeHtml(text); | |
191 | this.set_rendered(html); |
|
197 | this.set_rendered(html); | |
192 | MathJax.Hub.Queue(["Typeset",MathJax.Hub]); |
|
198 | MathJax.Hub.Queue(["Typeset",MathJax.Hub]); | |
193 | this.element.find('div.text_cell_input').hide(); |
|
199 | this.element.find('div.text_cell_input').hide(); | |
194 | this.element.find("div.text_cell_render").show(); |
|
200 | this.element.find("div.text_cell_render").show(); | |
195 | this.rendered = true; |
|
201 | this.rendered = true; | |
196 | }; |
|
202 | }; | |
197 | }; |
|
203 | }; | |
198 |
|
204 | |||
199 |
|
205 | |||
200 | // RSTCell |
|
206 | // RSTCell | |
201 |
|
207 | |||
202 | var RSTCell = function (notebook) { |
|
208 | var RSTCell = function (notebook) { | |
203 | this.placeholder = "Type *ReStructured Text* and LaTeX: $\\alpha^2$"; |
|
209 | this.placeholder = "Type *ReStructured Text* and LaTeX: $\\alpha^2$"; | |
204 | IPython.TextCell.apply(this, arguments); |
|
210 | IPython.TextCell.apply(this, arguments); | |
205 | this.cell_type = 'rst'; |
|
211 | this.cell_type = 'rst'; | |
206 | }; |
|
212 | }; | |
207 |
|
213 | |||
208 |
|
214 | |||
209 | RSTCell.prototype = new TextCell(); |
|
215 | RSTCell.prototype = new TextCell(); | |
210 |
|
216 | |||
211 |
|
217 | |||
212 | RSTCell.prototype.render = function () { |
|
218 | RSTCell.prototype.render = function () { | |
213 | if (this.rendered === false) { |
|
219 | if (this.rendered === false) { | |
214 | var text = this.get_source(); |
|
220 | var text = this.get_source(); | |
215 | if (text === "") {text = this.placeholder;}; |
|
221 | if (text === "") {text = this.placeholder;}; | |
216 | var settings = { |
|
222 | var settings = { | |
217 | processData : false, |
|
223 | processData : false, | |
218 | cache : false, |
|
224 | cache : false, | |
219 | type : "POST", |
|
225 | type : "POST", | |
220 | data : text, |
|
226 | data : text, | |
221 | headers : {'Content-Type': 'application/x-rst'}, |
|
227 | headers : {'Content-Type': 'application/x-rst'}, | |
222 | success : $.proxy(this.handle_render,this) |
|
228 | success : $.proxy(this.handle_render,this) | |
223 | }; |
|
229 | }; | |
224 | $.ajax("/rstservice/render", settings); |
|
230 | $.ajax("/rstservice/render", settings); | |
225 | this.element.find('div.text_cell_input').hide(); |
|
231 | this.element.find('div.text_cell_input').hide(); | |
226 | this.element.find("div.text_cell_render").show(); |
|
232 | this.element.find("div.text_cell_render").show(); | |
227 | this.set_rendered("Rendering..."); |
|
233 | this.set_rendered("Rendering..."); | |
228 | }; |
|
234 | }; | |
229 | }; |
|
235 | }; | |
230 |
|
236 | |||
231 |
|
237 | |||
232 | RSTCell.prototype.handle_render = function (data, status, xhr) { |
|
238 | RSTCell.prototype.handle_render = function (data, status, xhr) { | |
233 | this.set_rendered(data); |
|
239 | this.set_rendered(data); | |
234 | MathJax.Hub.Queue(["Typeset",MathJax.Hub]); |
|
240 | MathJax.Hub.Queue(["Typeset",MathJax.Hub]); | |
235 | this.rendered = true; |
|
241 | this.rendered = true; | |
236 | }; |
|
242 | }; | |
237 |
|
243 | |||
238 |
|
244 | |||
239 | IPython.TextCell = TextCell; |
|
245 | IPython.TextCell = TextCell; | |
240 | IPython.HTMLCell = HTMLCell; |
|
246 | IPython.HTMLCell = HTMLCell; | |
241 | IPython.MarkdownCell = MarkdownCell; |
|
247 | IPython.MarkdownCell = MarkdownCell; | |
242 | IPython.RSTCell = RSTCell; |
|
248 | IPython.RSTCell = RSTCell; | |
243 |
|
249 | |||
244 |
|
250 | |||
245 | return IPython; |
|
251 | return IPython; | |
246 |
|
252 | |||
247 | }(IPython)); |
|
253 | }(IPython)); | |
248 |
|
254 |
@@ -1,95 +1,101 b'' | |||||
|
1 | //---------------------------------------------------------------------------- | |||
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |||
|
3 | // | |||
|
4 | // Distributed under the terms of the BSD License. The full license is in | |||
|
5 | // the file COPYING, distributed as part of this software. | |||
|
6 | //---------------------------------------------------------------------------- | |||
1 |
|
|
7 | ||
2 | //============================================================================ |
|
8 | //============================================================================ | |
3 | // Utilities |
|
9 | // Utilities | |
4 | //============================================================================ |
|
10 | //============================================================================ | |
5 |
|
11 | |||
6 | IPython.namespace('IPython.utils') |
|
12 | IPython.namespace('IPython.utils') | |
7 |
|
13 | |||
8 | IPython.utils = (function (IPython) { |
|
14 | IPython.utils = (function (IPython) { | |
9 |
|
15 | |||
10 | var uuid = function () { |
|
16 | var uuid = function () { | |
11 | // http://www.ietf.org/rfc/rfc4122.txt |
|
17 | // http://www.ietf.org/rfc/rfc4122.txt | |
12 | var s = []; |
|
18 | var s = []; | |
13 | var hexDigits = "0123456789ABCDEF"; |
|
19 | var hexDigits = "0123456789ABCDEF"; | |
14 | for (var i = 0; i < 32; i++) { |
|
20 | for (var i = 0; i < 32; i++) { | |
15 | s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); |
|
21 | s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); | |
16 | } |
|
22 | } | |
17 | s[12] = "4"; // bits 12-15 of the time_hi_and_version field to 0010 |
|
23 | s[12] = "4"; // bits 12-15 of the time_hi_and_version field to 0010 | |
18 | s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01 |
|
24 | s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01 | |
19 |
|
25 | |||
20 | var uuid = s.join(""); |
|
26 | var uuid = s.join(""); | |
21 | return uuid; |
|
27 | return uuid; | |
22 | }; |
|
28 | }; | |
23 |
|
29 | |||
24 |
|
30 | |||
25 | //Fix raw text to parse correctly in crazy XML |
|
31 | //Fix raw text to parse correctly in crazy XML | |
26 | function xmlencode(string) { |
|
32 | function xmlencode(string) { | |
27 | return string.replace(/\&/g,'&'+'amp;') |
|
33 | return string.replace(/\&/g,'&'+'amp;') | |
28 | .replace(/</g,'&'+'lt;') |
|
34 | .replace(/</g,'&'+'lt;') | |
29 | .replace(/>/g,'&'+'gt;') |
|
35 | .replace(/>/g,'&'+'gt;') | |
30 | .replace(/\'/g,'&'+'apos;') |
|
36 | .replace(/\'/g,'&'+'apos;') | |
31 | .replace(/\"/g,'&'+'quot;') |
|
37 | .replace(/\"/g,'&'+'quot;') | |
32 | .replace(/`/g,'&'+'#96;') |
|
38 | .replace(/`/g,'&'+'#96;') | |
33 | } |
|
39 | } | |
34 |
|
40 | |||
35 |
|
41 | |||
36 | //Map from terminal commands to CSS classes |
|
42 | //Map from terminal commands to CSS classes | |
37 | ansi_colormap = { |
|
43 | ansi_colormap = { | |
38 | "30":"ansiblack", "31":"ansired", |
|
44 | "30":"ansiblack", "31":"ansired", | |
39 | "32":"ansigreen", "33":"ansiyellow", |
|
45 | "32":"ansigreen", "33":"ansiyellow", | |
40 | "34":"ansiblue", "35":"ansipurple","36":"ansicyan", |
|
46 | "34":"ansiblue", "35":"ansipurple","36":"ansicyan", | |
41 | "37":"ansigrey", "01":"ansibold" |
|
47 | "37":"ansigrey", "01":"ansibold" | |
42 | } |
|
48 | } | |
43 |
|
49 | |||
44 | // Transform ANI color escape codes into HTML <span> tags with css |
|
50 | // Transform ANI color escape codes into HTML <span> tags with css | |
45 | // classes listed in the above ansi_colormap object. The actual color used |
|
51 | // classes listed in the above ansi_colormap object. The actual color used | |
46 | // are set in the css file. |
|
52 | // are set in the css file. | |
47 | function fixConsole(txt) { |
|
53 | function fixConsole(txt) { | |
48 | txt = xmlencode(txt) |
|
54 | txt = xmlencode(txt) | |
49 | var re = /\033\[([\d;]*?)m/ |
|
55 | var re = /\033\[([\d;]*?)m/ | |
50 | var opened = false |
|
56 | var opened = false | |
51 | var cmds = [] |
|
57 | var cmds = [] | |
52 | var opener = "" |
|
58 | var opener = "" | |
53 | var closer = "" |
|
59 | var closer = "" | |
54 |
|
60 | |||
55 | while (re.test(txt)) { |
|
61 | while (re.test(txt)) { | |
56 | var cmds = txt.match(re)[1].split(";") |
|
62 | var cmds = txt.match(re)[1].split(";") | |
57 | closer = opened?"</span>":"" |
|
63 | closer = opened?"</span>":"" | |
58 | opened = cmds.length > 1 || cmds[0] != 0 |
|
64 | opened = cmds.length > 1 || cmds[0] != 0 | |
59 | var rep = [] |
|
65 | var rep = [] | |
60 | for (var i in cmds) |
|
66 | for (var i in cmds) | |
61 | if (typeof(ansi_colormap[cmds[i]]) != "undefined") |
|
67 | if (typeof(ansi_colormap[cmds[i]]) != "undefined") | |
62 | rep.push(ansi_colormap[cmds[i]]) |
|
68 | rep.push(ansi_colormap[cmds[i]]) | |
63 | opener = rep.length > 0?"<span class=\""+rep.join(" ")+"\">":"" |
|
69 | opener = rep.length > 0?"<span class=\""+rep.join(" ")+"\">":"" | |
64 | txt = txt.replace(re, closer + opener) |
|
70 | txt = txt.replace(re, closer + opener) | |
65 | } |
|
71 | } | |
66 | if (opened) txt += "</span>" |
|
72 | if (opened) txt += "</span>" | |
67 | return txt.trim() |
|
73 | return txt.trim() | |
68 | } |
|
74 | } | |
69 |
|
75 | |||
70 |
|
76 | |||
71 | grow = function(element) { |
|
77 | grow = function(element) { | |
72 | // Grow the cell by hand. This is used upon reloading from JSON, when the |
|
78 | // Grow the cell by hand. This is used upon reloading from JSON, when the | |
73 | // autogrow handler is not called. |
|
79 | // autogrow handler is not called. | |
74 | var dom = element.get(0); |
|
80 | var dom = element.get(0); | |
75 | var lines_count = 0; |
|
81 | var lines_count = 0; | |
76 | // modified split rule from |
|
82 | // modified split rule from | |
77 | // http://stackoverflow.com/questions/2035910/how-to-get-the-number-of-lines-in-a-textarea/2036424#2036424 |
|
83 | // http://stackoverflow.com/questions/2035910/how-to-get-the-number-of-lines-in-a-textarea/2036424#2036424 | |
78 | var lines = dom.value.split(/\r|\r\n|\n/); |
|
84 | var lines = dom.value.split(/\r|\r\n|\n/); | |
79 | lines_count = lines.length; |
|
85 | lines_count = lines.length; | |
80 | if (lines_count >= 1) { |
|
86 | if (lines_count >= 1) { | |
81 | dom.rows = lines_count; |
|
87 | dom.rows = lines_count; | |
82 | } else { |
|
88 | } else { | |
83 | dom.rows = 1; |
|
89 | dom.rows = 1; | |
84 | } |
|
90 | } | |
85 | }; |
|
91 | }; | |
86 |
|
92 | |||
87 |
|
93 | |||
88 | return { |
|
94 | return { | |
89 | uuid : uuid, |
|
95 | uuid : uuid, | |
90 | fixConsole : fixConsole, |
|
96 | fixConsole : fixConsole, | |
91 | grow : grow |
|
97 | grow : grow | |
92 | } |
|
98 | } | |
93 |
|
99 | |||
94 | }(IPython)); |
|
100 | }(IPython)); | |
95 |
|
101 |
@@ -1,39 +1,26 b'' | |||||
1 | """Tests for the notebook kernel and session manager.""" |
|
1 | """Tests for the notebook kernel and session manager.""" | |
2 |
|
2 | |||
3 | from unittest import TestCase |
|
3 | from unittest import TestCase | |
4 |
|
4 | |||
5 | from IPython.frontend.html.notebook.kernelmanager import KernelManager |
|
5 | from IPython.frontend.html.notebook.kernelmanager import KernelManager | |
6 | from IPython.frontend.html.notebook.sessionmanager import SessionManagerRunningError |
|
|||
7 |
|
6 | |||
8 | class TestKernelManager(TestCase): |
|
7 | class TestKernelManager(TestCase): | |
9 |
|
8 | |||
10 | def test_km_lifecycle(self): |
|
9 | def test_km_lifecycle(self): | |
11 | km = KernelManager() |
|
10 | km = KernelManager() | |
12 | kid = km.start_kernel() |
|
11 | kid = km.start_kernel() | |
13 | self.assert_(kid in km) |
|
12 | self.assert_(kid in km) | |
14 | self.assertEquals(len(km),1) |
|
13 | self.assertEquals(len(km),1) | |
15 | km.kill_kernel(kid) |
|
14 | km.kill_kernel(kid) | |
16 | self.assert_(not kid in km) |
|
15 | self.assert_(not kid in km) | |
17 |
|
16 | |||
18 | kid = km.start_kernel() |
|
17 | kid = km.start_kernel() | |
19 | self.assertEquals('127.0.0.1',km.get_kernel_ip(kid)) |
|
18 | self.assertEquals('127.0.0.1',km.get_kernel_ip(kid)) | |
20 | port_dict = km.get_kernel_ports(kid) |
|
19 | port_dict = km.get_kernel_ports(kid) | |
21 | self.assert_('stdin_port' in port_dict) |
|
20 | self.assert_('stdin_port' in port_dict) | |
22 | self.assert_('iopub_port' in port_dict) |
|
21 | self.assert_('iopub_port' in port_dict) | |
23 | self.assert_('shell_port' in port_dict) |
|
22 | self.assert_('shell_port' in port_dict) | |
24 | self.assert_('hb_port' in port_dict) |
|
23 | self.assert_('hb_port' in port_dict) | |
25 | km.get_kernel_process(kid) |
|
24 | km.get_kernel_process(kid) | |
26 |
|
25 | |||
27 | def test_session_manager(self): |
|
|||
28 | km = KernelManager() |
|
|||
29 | kid = km.start_kernel() |
|
|||
30 | sm = km.create_session_manager(kid) |
|
|||
31 | self.assert_(sm._running) |
|
|||
32 | sm.stop() |
|
|||
33 | self.assert_(not sm._running) |
|
|||
34 | sm.start() |
|
|||
35 | self.assertRaises(SessionManagerRunningError, sm.start) |
|
|||
36 | sm.get_iopub_stream() |
|
|||
37 | sm.get_shell_stream() |
|
|||
38 | sm.session |
|
|||
39 |
|
26 |
@@ -1,80 +1,96 b'' | |||||
1 | import json |
|
1 | """Unfinished code for ZMQ/HTTP bridging. We use WebSockets instead. | |
2 |
|
|
2 | ||
3 | from tornado import web |
|
3 | Authors: | |
|
4 | ||||
|
5 | * Brian Granger | |||
|
6 | """ | |||
4 |
|
7 | |||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | # Copyright (C) 2008-2011 The IPython Development Team | |||
|
10 | # | |||
|
11 | # Distributed under the terms of the BSD License. The full license is in | |||
|
12 | # the file COPYING, distributed as part of this software. | |||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | ||||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | # Imports | |||
|
17 | #----------------------------------------------------------------------------- | |||
|
18 | ||||
|
19 | import json | |||
5 | import logging |
|
20 | import logging | |
6 |
|
21 | |||
|
22 | from tornado import web | |||
|
23 | ||||
|
24 | #----------------------------------------------------------------------------- | |||
|
25 | # Code | |||
|
26 | #----------------------------------------------------------------------------- | |||
7 |
|
27 | |||
8 | class ZMQHandler(web.RequestHandler): |
|
28 | class ZMQHandler(web.RequestHandler): | |
9 |
|
29 | |||
10 | def get_stream(self): |
|
30 | def get_stream(self): | |
11 | """Get the ZMQStream for this request.""" |
|
31 | """Get the ZMQStream for this request.""" | |
12 | raise NotImplementedError('Implement get_stream() in a subclass.') |
|
32 | raise NotImplementedError('Implement get_stream() in a subclass.') | |
13 |
|
33 | |||
14 | def _save_method_args(self, *args, **kwargs): |
|
34 | def _save_method_args(self, *args, **kwargs): | |
15 | """Save the args and kwargs to get/post/put/delete for future use. |
|
35 | """Save the args and kwargs to get/post/put/delete for future use. | |
16 |
|
36 | |||
17 | These arguments are not saved in the request or handler objects, but |
|
37 | These arguments are not saved in the request or handler objects, but | |
18 | are often needed by methods such as get_stream(). |
|
38 | are often needed by methods such as get_stream(). | |
19 | """ |
|
39 | """ | |
20 | self._method_args = args |
|
40 | self._method_args = args | |
21 | self._method_kwargs = kwargs |
|
41 | self._method_kwargs = kwargs | |
22 |
|
42 | |||
23 | def _handle_msgs(self, msg): |
|
43 | def _handle_msgs(self, msg): | |
24 | msgs = [msg] |
|
44 | msgs = [msg] | |
25 | stream = self.get_stream() |
|
45 | stream = self.get_stream() | |
26 | stream.on_recv(lambda m: msgs.append(json.loads(m))) |
|
46 | stream.on_recv(lambda m: msgs.append(json.loads(m))) | |
27 | stream.flush() |
|
47 | stream.flush() | |
28 | stream.stop_on_recv() |
|
48 | stream.stop_on_recv() | |
29 | logging.info("Reply: %r" % msgs) |
|
49 | logging.info("Reply: %r" % msgs) | |
30 | self.write(json.dumps(msgs)) |
|
50 | self.write(json.dumps(msgs)) | |
31 | self.finish() |
|
51 | self.finish() | |
32 |
|
52 | |||
33 |
|
53 | |||
34 | class ZMQPubHandler(ZMQHandler): |
|
54 | class ZMQPubHandler(ZMQHandler): | |
35 |
|
55 | |||
36 | SUPPORTED_METHODS = ("POST",) |
|
56 | SUPPORTED_METHODS = ("POST",) | |
37 |
|
57 | |||
38 | def post(self, *args, **kwargs): |
|
58 | def post(self, *args, **kwargs): | |
39 | self._save_method_args(*args, **kwargs) |
|
59 | self._save_method_args(*args, **kwargs) | |
40 | try: |
|
60 | try: | |
41 | msg = json.loads(self.request.body) |
|
61 | msg = json.loads(self.request.body) | |
42 | except: |
|
62 | except: | |
43 | self.send_error(status_code=415) |
|
63 | self.send_error(status_code=415) | |
44 | else: |
|
64 | else: | |
45 | logging.info("Request: %r" % msg) |
|
65 | logging.info("Request: %r" % msg) | |
46 | self.get_stream().send_json(msg) |
|
66 | self.get_stream().send_json(msg) | |
47 |
|
67 | |||
48 |
|
68 | |||
49 | class ZMQSubHandler(ZMQHandler): |
|
69 | class ZMQSubHandler(ZMQHandler): | |
50 |
|
70 | |||
51 | SUPPORTED_METHODS = ("GET",) |
|
71 | SUPPORTED_METHODS = ("GET",) | |
52 |
|
72 | |||
53 | @web.asynchronous |
|
73 | @web.asynchronous | |
54 | def get(self, *args, **kwargs): |
|
74 | def get(self, *args, **kwargs): | |
55 | self._save_method_args(*args, **kwargs) |
|
75 | self._save_method_args(*args, **kwargs) | |
56 | self.get_stream().on_recv(self._handle_msgs) |
|
76 | self.get_stream().on_recv(self._handle_msgs) | |
57 |
|
77 | |||
58 |
|
78 | |||
59 | class ZMQXReqHandler(ZMQHandler): |
|
79 | class ZMQXReqHandler(ZMQHandler): | |
60 |
|
80 | |||
61 | SUPPORTED_METHODS = ("POST",) |
|
81 | SUPPORTED_METHODS = ("POST",) | |
62 |
|
82 | |||
63 | @web.asynchronous |
|
83 | @web.asynchronous | |
64 | def post(self, *args, **kwargs): |
|
84 | def post(self, *args, **kwargs): | |
65 | self._save_method_args(*args, **kwargs) |
|
85 | self._save_method_args(*args, **kwargs) | |
66 | logging.info("request: %r" % self.request) |
|
86 | logging.info("request: %r" % self.request) | |
67 | try: |
|
87 | try: | |
68 | msg = json.loads(self.request.body) |
|
88 | msg = json.loads(self.request.body) | |
69 | except: |
|
89 | except: | |
70 | self.send_error(status_code=415) |
|
90 | self.send_error(status_code=415) | |
71 | else: |
|
91 | else: | |
72 | logging.info("Reply: %r" % msg) |
|
92 | logging.info("Reply: %r" % msg) | |
73 | stream = self.get_stream() |
|
93 | stream = self.get_stream() | |
74 | stream.send_json(msg) |
|
94 | stream.send_json(msg) | |
75 | stream.on_recv(self._handle_msgs) |
|
95 | stream.on_recv(self._handle_msgs) | |
76 |
|
96 | |||
77 |
|
||||
78 |
|
||||
79 |
|
||||
80 | No newline at end of file |
|
@@ -1,196 +1,217 b'' | |||||
|
1 | """The official API for working with notebooks in the current format version. | |||
|
2 | ||||
|
3 | Authors: | |||
|
4 | ||||
|
5 | * Brian Granger | |||
|
6 | """ | |||
|
7 | ||||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | # Copyright (C) 2008-2011 The IPython Development Team | |||
|
10 | # | |||
|
11 | # Distributed under the terms of the BSD License. The full license is in | |||
|
12 | # the file COPYING, distributed as part of this software. | |||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | ||||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | # Imports | |||
|
17 | #----------------------------------------------------------------------------- | |||
|
18 | ||||
1 | import json |
|
19 | import json | |
2 | from xml.etree import ElementTree as ET |
|
20 | from xml.etree import ElementTree as ET | |
3 | import re |
|
21 | import re | |
4 |
|
22 | |||
5 | from IPython.nbformat import v2 |
|
23 | from IPython.nbformat import v2 | |
6 | from IPython.nbformat import v1 |
|
24 | from IPython.nbformat import v1 | |
7 |
|
25 | |||
8 | from IPython.nbformat.v2 import ( |
|
26 | from IPython.nbformat.v2 import ( | |
9 | NotebookNode, |
|
27 | NotebookNode, | |
10 | new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet, |
|
28 | new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet, | |
11 | parse_filename |
|
29 | parse_filename | |
12 | ) |
|
30 | ) | |
13 |
|
31 | |||
|
32 | #----------------------------------------------------------------------------- | |||
|
33 | # Code | |||
|
34 | #----------------------------------------------------------------------------- | |||
14 |
|
35 | |||
15 | current_nbformat = 2 |
|
36 | current_nbformat = 2 | |
16 |
|
37 | |||
17 |
|
38 | |||
18 | class NBFormatError(Exception): |
|
39 | class NBFormatError(Exception): | |
19 | pass |
|
40 | pass | |
20 |
|
41 | |||
21 |
|
42 | |||
22 | def parse_json(s, **kwargs): |
|
43 | def parse_json(s, **kwargs): | |
23 | """Parse a string into a (nbformat, dict) tuple.""" |
|
44 | """Parse a string into a (nbformat, dict) tuple.""" | |
24 | d = json.loads(s, **kwargs) |
|
45 | d = json.loads(s, **kwargs) | |
25 | nbformat = d.get('nbformat',1) |
|
46 | nbformat = d.get('nbformat',1) | |
26 | return nbformat, d |
|
47 | return nbformat, d | |
27 |
|
48 | |||
28 |
|
49 | |||
29 | def parse_xml(s, **kwargs): |
|
50 | def parse_xml(s, **kwargs): | |
30 | """Parse a string into a (nbformat, etree) tuple.""" |
|
51 | """Parse a string into a (nbformat, etree) tuple.""" | |
31 | root = ET.fromstring(s) |
|
52 | root = ET.fromstring(s) | |
32 | nbformat_e = root.find('nbformat') |
|
53 | nbformat_e = root.find('nbformat') | |
33 | if nbformat_e is not None: |
|
54 | if nbformat_e is not None: | |
34 | nbformat = int(nbformat_e.text) |
|
55 | nbformat = int(nbformat_e.text) | |
35 | else: |
|
56 | else: | |
36 | raise NBFormatError('No nbformat version found') |
|
57 | raise NBFormatError('No nbformat version found') | |
37 | return nbformat, root |
|
58 | return nbformat, root | |
38 |
|
59 | |||
39 |
|
60 | |||
40 | def parse_py(s, **kwargs): |
|
61 | def parse_py(s, **kwargs): | |
41 | """Parse a string into a (nbformat, string) tuple.""" |
|
62 | """Parse a string into a (nbformat, string) tuple.""" | |
42 | pattern = r'# <nbformat>(?P<nbformat>\d+)</nbformat>' |
|
63 | pattern = r'# <nbformat>(?P<nbformat>\d+)</nbformat>' | |
43 | m = re.search(pattern,s) |
|
64 | m = re.search(pattern,s) | |
44 | if m is not None: |
|
65 | if m is not None: | |
45 | nbformat = int(m.group('nbformat')) |
|
66 | nbformat = int(m.group('nbformat')) | |
46 | else: |
|
67 | else: | |
47 | nbformat = 2 |
|
68 | nbformat = 2 | |
48 | return nbformat, s |
|
69 | return nbformat, s | |
49 |
|
70 | |||
50 |
|
71 | |||
51 | def reads_json(s, **kwargs): |
|
72 | def reads_json(s, **kwargs): | |
52 | """Read a JSON notebook from a string and return the NotebookNode object.""" |
|
73 | """Read a JSON notebook from a string and return the NotebookNode object.""" | |
53 | nbformat, d = parse_json(s, **kwargs) |
|
74 | nbformat, d = parse_json(s, **kwargs) | |
54 | if nbformat == 1: |
|
75 | if nbformat == 1: | |
55 | nb = v1.to_notebook_json(d, **kwargs) |
|
76 | nb = v1.to_notebook_json(d, **kwargs) | |
56 | nb = v2.convert_to_this_nbformat(nb, orig_version=1) |
|
77 | nb = v2.convert_to_this_nbformat(nb, orig_version=1) | |
57 | elif nbformat == 2: |
|
78 | elif nbformat == 2: | |
58 | nb = v2.to_notebook_json(d, **kwargs) |
|
79 | nb = v2.to_notebook_json(d, **kwargs) | |
59 | else: |
|
80 | else: | |
60 | raise NBFormatError('Unsupported JSON nbformat version: %i' % nbformat) |
|
81 | raise NBFormatError('Unsupported JSON nbformat version: %i' % nbformat) | |
61 | return nb |
|
82 | return nb | |
62 |
|
83 | |||
63 |
|
84 | |||
64 | def writes_json(nb, **kwargs): |
|
85 | def writes_json(nb, **kwargs): | |
65 | return v2.writes_json(nb, **kwargs) |
|
86 | return v2.writes_json(nb, **kwargs) | |
66 |
|
87 | |||
67 |
|
88 | |||
68 | def reads_xml(s, **kwargs): |
|
89 | def reads_xml(s, **kwargs): | |
69 | """Read an XML notebook from a string and return the NotebookNode object.""" |
|
90 | """Read an XML notebook from a string and return the NotebookNode object.""" | |
70 | nbformat, root = parse_xml(s, **kwargs) |
|
91 | nbformat, root = parse_xml(s, **kwargs) | |
71 | if nbformat == 2: |
|
92 | if nbformat == 2: | |
72 | nb = v2.to_notebook_xml(root, **kwargs) |
|
93 | nb = v2.to_notebook_xml(root, **kwargs) | |
73 | else: |
|
94 | else: | |
74 | raise NBFormatError('Unsupported XML nbformat version: %i' % nbformat) |
|
95 | raise NBFormatError('Unsupported XML nbformat version: %i' % nbformat) | |
75 | return nb |
|
96 | return nb | |
76 |
|
97 | |||
77 |
|
98 | |||
78 | def writes_xml(nb, **kwargs): |
|
99 | def writes_xml(nb, **kwargs): | |
79 | return v2.writes_xml(nb, **kwargs) |
|
100 | return v2.writes_xml(nb, **kwargs) | |
80 |
|
101 | |||
81 |
|
102 | |||
82 | def reads_py(s, **kwargs): |
|
103 | def reads_py(s, **kwargs): | |
83 | """Read a .py notebook from a string and return the NotebookNode object.""" |
|
104 | """Read a .py notebook from a string and return the NotebookNode object.""" | |
84 | nbformat, s = parse_py(s, **kwargs) |
|
105 | nbformat, s = parse_py(s, **kwargs) | |
85 | if nbformat == 2: |
|
106 | if nbformat == 2: | |
86 | nb = v2.to_notebook_py(s, **kwargs) |
|
107 | nb = v2.to_notebook_py(s, **kwargs) | |
87 | else: |
|
108 | else: | |
88 | raise NBFormatError('Unsupported PY nbformat version: %i' % nbformat) |
|
109 | raise NBFormatError('Unsupported PY nbformat version: %i' % nbformat) | |
89 | return nb |
|
110 | return nb | |
90 |
|
111 | |||
91 |
|
112 | |||
92 | def writes_py(nb, **kwargs): |
|
113 | def writes_py(nb, **kwargs): | |
93 | return v2.writes_py(nb, **kwargs) |
|
114 | return v2.writes_py(nb, **kwargs) | |
94 |
|
115 | |||
95 |
|
116 | |||
96 | # High level API |
|
117 | # High level API | |
97 |
|
118 | |||
98 |
|
119 | |||
99 | def reads(s, format, **kwargs): |
|
120 | def reads(s, format, **kwargs): | |
100 | """Read a notebook from a string and return the NotebookNode object. |
|
121 | """Read a notebook from a string and return the NotebookNode object. | |
101 |
|
122 | |||
102 | This function properly handles notebooks of any version. The notebook |
|
123 | This function properly handles notebooks of any version. The notebook | |
103 | returned will always be in the current version's format. |
|
124 | returned will always be in the current version's format. | |
104 |
|
125 | |||
105 | Parameters |
|
126 | Parameters | |
106 | ---------- |
|
127 | ---------- | |
107 | s : str |
|
128 | s : str | |
108 | The raw string to read the notebook from. |
|
129 | The raw string to read the notebook from. | |
109 | format : ('xml','json','py') |
|
130 | format : ('xml','json','py') | |
110 | The format that the string is in. |
|
131 | The format that the string is in. | |
111 |
|
132 | |||
112 | Returns |
|
133 | Returns | |
113 | ------- |
|
134 | ------- | |
114 | nb : NotebookNode |
|
135 | nb : NotebookNode | |
115 | The notebook that was read. |
|
136 | The notebook that was read. | |
116 | """ |
|
137 | """ | |
117 | if format == 'xml': |
|
138 | if format == 'xml': | |
118 | return reads_xml(s, **kwargs) |
|
139 | return reads_xml(s, **kwargs) | |
119 | elif format == 'json': |
|
140 | elif format == 'json': | |
120 | return reads_json(s, **kwargs) |
|
141 | return reads_json(s, **kwargs) | |
121 | elif format == 'py': |
|
142 | elif format == 'py': | |
122 | return reads_py(s, **kwargs) |
|
143 | return reads_py(s, **kwargs) | |
123 | else: |
|
144 | else: | |
124 | raise NBFormatError('Unsupported format: %s' % format) |
|
145 | raise NBFormatError('Unsupported format: %s' % format) | |
125 |
|
146 | |||
126 |
|
147 | |||
127 | def writes(nb, format, **kwargs): |
|
148 | def writes(nb, format, **kwargs): | |
128 | """Write a notebook to a string in a given format in the current nbformat version. |
|
149 | """Write a notebook to a string in a given format in the current nbformat version. | |
129 |
|
150 | |||
130 | This function always writes the notebook in the current nbformat version. |
|
151 | This function always writes the notebook in the current nbformat version. | |
131 |
|
152 | |||
132 | Parameters |
|
153 | Parameters | |
133 | ---------- |
|
154 | ---------- | |
134 | nb : NotebookNode |
|
155 | nb : NotebookNode | |
135 | The notebook to write. |
|
156 | The notebook to write. | |
136 | format : ('xml','json','py') |
|
157 | format : ('xml','json','py') | |
137 | The format to write the notebook in. |
|
158 | The format to write the notebook in. | |
138 |
|
159 | |||
139 | Returns |
|
160 | Returns | |
140 | ------- |
|
161 | ------- | |
141 | s : str |
|
162 | s : str | |
142 | The notebook string. |
|
163 | The notebook string. | |
143 | """ |
|
164 | """ | |
144 | if format == 'xml': |
|
165 | if format == 'xml': | |
145 | return writes_xml(nb, **kwargs) |
|
166 | return writes_xml(nb, **kwargs) | |
146 | elif format == 'json': |
|
167 | elif format == 'json': | |
147 | return writes_json(nb, **kwargs) |
|
168 | return writes_json(nb, **kwargs) | |
148 | elif format == 'py': |
|
169 | elif format == 'py': | |
149 | return writes_py(nb, **kwargs) |
|
170 | return writes_py(nb, **kwargs) | |
150 | else: |
|
171 | else: | |
151 | raise NBFormatError('Unsupported format: %s' % format) |
|
172 | raise NBFormatError('Unsupported format: %s' % format) | |
152 |
|
173 | |||
153 |
|
174 | |||
154 | def read(fp, format, **kwargs): |
|
175 | def read(fp, format, **kwargs): | |
155 | """Read a notebook from a file and return the NotebookNode object. |
|
176 | """Read a notebook from a file and return the NotebookNode object. | |
156 |
|
177 | |||
157 | This function properly handles notebooks of any version. The notebook |
|
178 | This function properly handles notebooks of any version. The notebook | |
158 | returned will always be in the current version's format. |
|
179 | returned will always be in the current version's format. | |
159 |
|
180 | |||
160 | Parameters |
|
181 | Parameters | |
161 | ---------- |
|
182 | ---------- | |
162 | fp : file |
|
183 | fp : file | |
163 | Any file-like object with a read method. |
|
184 | Any file-like object with a read method. | |
164 | format : ('xml','json','py') |
|
185 | format : ('xml','json','py') | |
165 | The format that the string is in. |
|
186 | The format that the string is in. | |
166 |
|
187 | |||
167 | Returns |
|
188 | Returns | |
168 | ------- |
|
189 | ------- | |
169 | nb : NotebookNode |
|
190 | nb : NotebookNode | |
170 | The notebook that was read. |
|
191 | The notebook that was read. | |
171 | """ |
|
192 | """ | |
172 | return reads(fp.read(), format, **kwargs) |
|
193 | return reads(fp.read(), format, **kwargs) | |
173 |
|
194 | |||
174 |
|
195 | |||
175 | def write(nb, fp, format, **kwargs): |
|
196 | def write(nb, fp, format, **kwargs): | |
176 | """Write a notebook to a file in a given format in the current nbformat version. |
|
197 | """Write a notebook to a file in a given format in the current nbformat version. | |
177 |
|
198 | |||
178 | This function always writes the notebook in the current nbformat version. |
|
199 | This function always writes the notebook in the current nbformat version. | |
179 |
|
200 | |||
180 | Parameters |
|
201 | Parameters | |
181 | ---------- |
|
202 | ---------- | |
182 | nb : NotebookNode |
|
203 | nb : NotebookNode | |
183 | The notebook to write. |
|
204 | The notebook to write. | |
184 | fp : file |
|
205 | fp : file | |
185 | Any file-like object with a write method. |
|
206 | Any file-like object with a write method. | |
186 | format : ('xml','json','py') |
|
207 | format : ('xml','json','py') | |
187 | The format to write the notebook in. |
|
208 | The format to write the notebook in. | |
188 |
|
209 | |||
189 | Returns |
|
210 | Returns | |
190 | ------- |
|
211 | ------- | |
191 | s : str |
|
212 | s : str | |
192 | The notebook string. |
|
213 | The notebook string. | |
193 | """ |
|
214 | """ | |
194 | return fp.write(writes(nb, format, **kwargs)) |
|
215 | return fp.write(writes(nb, format, **kwargs)) | |
195 |
|
216 | |||
196 |
|
217 |
@@ -1,12 +1,24 b'' | |||||
|
1 | """The main module for the v1 notebook format.""" | |||
|
2 | ||||
|
3 | #----------------------------------------------------------------------------- | |||
|
4 | # Copyright (C) 2008-2011 The IPython Development Team | |||
|
5 | # | |||
|
6 | # Distributed under the terms of the BSD License. The full license is in | |||
|
7 | # the file COPYING, distributed as part of this software. | |||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | ||||
|
10 | #----------------------------------------------------------------------------- | |||
|
11 | # Imports | |||
|
12 | #----------------------------------------------------------------------------- | |||
1 |
|
13 | |||
2 | from .nbbase import ( |
|
14 | from .nbbase import ( | |
3 | NotebookNode, |
|
15 | NotebookNode, | |
4 | new_code_cell, new_text_cell, new_notebook |
|
16 | new_code_cell, new_text_cell, new_notebook | |
5 | ) |
|
17 | ) | |
6 |
|
18 | |||
7 | from .nbjson import reads as reads_json, writes as writes_json |
|
19 | from .nbjson import reads as reads_json, writes as writes_json | |
8 | from .nbjson import reads as read_json, writes as write_json |
|
20 | from .nbjson import reads as read_json, writes as write_json | |
9 | from .nbjson import to_notebook as to_notebook_json |
|
21 | from .nbjson import to_notebook as to_notebook_json | |
10 |
|
22 | |||
11 | from .convert import convert_to_this_nbformat |
|
23 | from .convert import convert_to_this_nbformat | |
12 |
|
24 |
@@ -1,5 +1,16 b'' | |||||
|
1 | """Convert notebook to the v1 format.""" | |||
1 |
|
2 | |||
|
3 | #----------------------------------------------------------------------------- | |||
|
4 | # Copyright (C) 2008-2011 The IPython Development Team | |||
|
5 | # | |||
|
6 | # Distributed under the terms of the BSD License. The full license is in | |||
|
7 | # the file COPYING, distributed as part of this software. | |||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | ||||
|
10 | #----------------------------------------------------------------------------- | |||
|
11 | # Code | |||
|
12 | #----------------------------------------------------------------------------- | |||
2 |
|
13 | |||
3 | def convert_to_this_nbformat(nb, orig_version=None): |
|
14 | def convert_to_this_nbformat(nb, orig_version=None): | |
4 | raise ValueError('Cannot convert to v1 notebook format') |
|
15 | raise ValueError('Cannot convert to v1 notebook format') | |
5 |
|
16 |
@@ -1,53 +1,72 b'' | |||||
1 |
"""The basic dict based notebook format. |
|
1 | """The basic dict based notebook format. | |
|
2 | ||||
|
3 | Authors: | |||
|
4 | ||||
|
5 | * Brian Granger | |||
|
6 | """ | |||
|
7 | ||||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | # Copyright (C) 2008-2011 The IPython Development Team | |||
|
10 | # | |||
|
11 | # Distributed under the terms of the BSD License. The full license is in | |||
|
12 | # the file COPYING, distributed as part of this software. | |||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | ||||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | # Imports | |||
|
17 | #----------------------------------------------------------------------------- | |||
2 |
|
18 | |||
3 | import pprint |
|
19 | import pprint | |
4 | import uuid |
|
20 | import uuid | |
5 |
|
21 | |||
6 | from IPython.utils.ipstruct import Struct |
|
22 | from IPython.utils.ipstruct import Struct | |
7 |
|
23 | |||
|
24 | #----------------------------------------------------------------------------- | |||
|
25 | # Code | |||
|
26 | #----------------------------------------------------------------------------- | |||
8 |
|
27 | |||
9 | class NotebookNode(Struct): |
|
28 | class NotebookNode(Struct): | |
10 | pass |
|
29 | pass | |
11 |
|
30 | |||
12 |
|
31 | |||
13 | def from_dict(d): |
|
32 | def from_dict(d): | |
14 | if isinstance(d, dict): |
|
33 | if isinstance(d, dict): | |
15 | newd = NotebookNode() |
|
34 | newd = NotebookNode() | |
16 | for k,v in d.items(): |
|
35 | for k,v in d.items(): | |
17 | newd[k] = from_dict(v) |
|
36 | newd[k] = from_dict(v) | |
18 | return newd |
|
37 | return newd | |
19 | elif isinstance(d, (tuple, list)): |
|
38 | elif isinstance(d, (tuple, list)): | |
20 | return [from_dict(i) for i in d] |
|
39 | return [from_dict(i) for i in d] | |
21 | else: |
|
40 | else: | |
22 | return d |
|
41 | return d | |
23 |
|
42 | |||
24 |
|
43 | |||
25 | def new_code_cell(code=None, prompt_number=None): |
|
44 | def new_code_cell(code=None, prompt_number=None): | |
26 | """Create a new code cell with input and output""" |
|
45 | """Create a new code cell with input and output""" | |
27 | cell = NotebookNode() |
|
46 | cell = NotebookNode() | |
28 | cell.cell_type = u'code' |
|
47 | cell.cell_type = u'code' | |
29 | if code is not None: |
|
48 | if code is not None: | |
30 | cell.code = unicode(code) |
|
49 | cell.code = unicode(code) | |
31 | if prompt_number is not None: |
|
50 | if prompt_number is not None: | |
32 | cell.prompt_number = int(prompt_number) |
|
51 | cell.prompt_number = int(prompt_number) | |
33 | return cell |
|
52 | return cell | |
34 |
|
53 | |||
35 |
|
54 | |||
36 | def new_text_cell(text=None): |
|
55 | def new_text_cell(text=None): | |
37 | """Create a new text cell.""" |
|
56 | """Create a new text cell.""" | |
38 | cell = NotebookNode() |
|
57 | cell = NotebookNode() | |
39 | if text is not None: |
|
58 | if text is not None: | |
40 | cell.text = unicode(text) |
|
59 | cell.text = unicode(text) | |
41 | cell.cell_type = u'text' |
|
60 | cell.cell_type = u'text' | |
42 | return cell |
|
61 | return cell | |
43 |
|
62 | |||
44 |
|
63 | |||
45 | def new_notebook(cells=None): |
|
64 | def new_notebook(cells=None): | |
46 | """Create a notebook by name, id and a list of worksheets.""" |
|
65 | """Create a notebook by name, id and a list of worksheets.""" | |
47 | nb = NotebookNode() |
|
66 | nb = NotebookNode() | |
48 | if cells is not None: |
|
67 | if cells is not None: | |
49 | nb.cells = cells |
|
68 | nb.cells = cells | |
50 | else: |
|
69 | else: | |
51 | nb.cells = [] |
|
70 | nb.cells = [] | |
52 | return nb |
|
71 | return nb | |
53 |
|
72 |
@@ -1,35 +1,54 b'' | |||||
1 |
"""Read and write notebooks in JSON format. |
|
1 | """Read and write notebooks in JSON format. | |
|
2 | ||||
|
3 | Authors: | |||
|
4 | ||||
|
5 | * Brian Granger | |||
|
6 | """ | |||
|
7 | ||||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | # Copyright (C) 2008-2011 The IPython Development Team | |||
|
10 | # | |||
|
11 | # Distributed under the terms of the BSD License. The full license is in | |||
|
12 | # the file COPYING, distributed as part of this software. | |||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | ||||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | # Imports | |||
|
17 | #----------------------------------------------------------------------------- | |||
2 |
|
18 | |||
3 | from base64 import encodestring |
|
19 | from base64 import encodestring | |
4 | from .rwbase import NotebookReader, NotebookWriter |
|
20 | from .rwbase import NotebookReader, NotebookWriter | |
5 | from .nbbase import from_dict |
|
21 | from .nbbase import from_dict | |
6 | import json |
|
22 | import json | |
7 |
|
23 | |||
|
24 | #----------------------------------------------------------------------------- | |||
|
25 | # Code | |||
|
26 | #----------------------------------------------------------------------------- | |||
8 |
|
27 | |||
9 | class JSONReader(NotebookReader): |
|
28 | class JSONReader(NotebookReader): | |
10 |
|
29 | |||
11 | def reads(self, s, **kwargs): |
|
30 | def reads(self, s, **kwargs): | |
12 | nb = json.loads(s, **kwargs) |
|
31 | nb = json.loads(s, **kwargs) | |
13 | return self.to_notebook(nb, **kwargs) |
|
32 | return self.to_notebook(nb, **kwargs) | |
14 |
|
33 | |||
15 | def to_notebook(self, d, **kwargs): |
|
34 | def to_notebook(self, d, **kwargs): | |
16 | """Convert from a raw JSON dict to a nested NotebookNode structure.""" |
|
35 | """Convert from a raw JSON dict to a nested NotebookNode structure.""" | |
17 | return from_dict(d) |
|
36 | return from_dict(d) | |
18 |
|
37 | |||
19 |
|
38 | |||
20 | class JSONWriter(NotebookWriter): |
|
39 | class JSONWriter(NotebookWriter): | |
21 |
|
40 | |||
22 | def writes(self, nb, **kwargs): |
|
41 | def writes(self, nb, **kwargs): | |
23 | kwargs['indent'] = 4 |
|
42 | kwargs['indent'] = 4 | |
24 | return json.dumps(nb, **kwargs) |
|
43 | return json.dumps(nb, **kwargs) | |
25 |
|
44 | |||
26 |
|
45 | |||
27 | _reader = JSONReader() |
|
46 | _reader = JSONReader() | |
28 | _writer = JSONWriter() |
|
47 | _writer = JSONWriter() | |
29 |
|
48 | |||
30 | reads = _reader.reads |
|
49 | reads = _reader.reads | |
31 | read = _reader.read |
|
50 | read = _reader.read | |
32 | to_notebook = _reader.to_notebook |
|
51 | to_notebook = _reader.to_notebook | |
33 | write = _writer.write |
|
52 | write = _writer.write | |
34 | writes = _writer.writes |
|
53 | writes = _writer.writes | |
35 |
|
54 |
@@ -1,26 +1,47 b'' | |||||
|
1 | """Base classes and function for readers and writers. | |||
|
2 | ||||
|
3 | Authors: | |||
|
4 | ||||
|
5 | * Brian Granger | |||
|
6 | """ | |||
|
7 | ||||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | # Copyright (C) 2008-2011 The IPython Development Team | |||
|
10 | # | |||
|
11 | # Distributed under the terms of the BSD License. The full license is in | |||
|
12 | # the file COPYING, distributed as part of this software. | |||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | ||||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | # Imports | |||
|
17 | #----------------------------------------------------------------------------- | |||
|
18 | ||||
1 | from base64 import encodestring, decodestring |
|
19 | from base64 import encodestring, decodestring | |
2 |
|
20 | |||
|
21 | #----------------------------------------------------------------------------- | |||
|
22 | # Code | |||
|
23 | #----------------------------------------------------------------------------- | |||
3 |
|
24 | |||
4 | class NotebookReader(object): |
|
25 | class NotebookReader(object): | |
5 |
|
26 | |||
6 | def reads(self, s, **kwargs): |
|
27 | def reads(self, s, **kwargs): | |
7 | """Read a notebook from a string.""" |
|
28 | """Read a notebook from a string.""" | |
8 | raise NotImplementedError("loads must be implemented in a subclass") |
|
29 | raise NotImplementedError("loads must be implemented in a subclass") | |
9 |
|
30 | |||
10 | def read(self, fp, **kwargs): |
|
31 | def read(self, fp, **kwargs): | |
11 | """Read a notebook from a file like object""" |
|
32 | """Read a notebook from a file like object""" | |
12 | return self.reads(fp.read(), **kwargs) |
|
33 | return self.reads(fp.read(), **kwargs) | |
13 |
|
34 | |||
14 |
|
35 | |||
15 | class NotebookWriter(object): |
|
36 | class NotebookWriter(object): | |
16 |
|
37 | |||
17 | def writes(self, nb, **kwargs): |
|
38 | def writes(self, nb, **kwargs): | |
18 | """Write a notebook to a string.""" |
|
39 | """Write a notebook to a string.""" | |
19 | raise NotImplementedError("loads must be implemented in a subclass") |
|
40 | raise NotImplementedError("loads must be implemented in a subclass") | |
20 |
|
41 | |||
21 | def write(self, nb, fp, **kwargs): |
|
42 | def write(self, nb, fp, **kwargs): | |
22 | """Write a notebook to a file like object""" |
|
43 | """Write a notebook to a file like object""" | |
23 | return fp.write(self.writes(nb,**kwargs)) |
|
44 | return fp.write(self.writes(nb,**kwargs)) | |
24 |
|
45 | |||
25 |
|
46 | |||
26 |
|
47 |
@@ -1,57 +1,77 b'' | |||||
|
1 | """The main API for the v2 notebook format. | |||
|
2 | ||||
|
3 | Authors: | |||
|
4 | ||||
|
5 | * Brian Granger | |||
|
6 | """ | |||
|
7 | ||||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | # Copyright (C) 2008-2011 The IPython Development Team | |||
|
10 | # | |||
|
11 | # Distributed under the terms of the BSD License. The full license is in | |||
|
12 | # the file COPYING, distributed as part of this software. | |||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | ||||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | # Imports | |||
|
17 | #----------------------------------------------------------------------------- | |||
1 |
|
18 | |||
2 | from .nbbase import ( |
|
19 | from .nbbase import ( | |
3 | NotebookNode, |
|
20 | NotebookNode, | |
4 | new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet |
|
21 | new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet | |
5 | ) |
|
22 | ) | |
6 |
|
23 | |||
7 | from .nbjson import reads as reads_json, writes as writes_json |
|
24 | from .nbjson import reads as reads_json, writes as writes_json | |
8 | from .nbjson import reads as read_json, writes as write_json |
|
25 | from .nbjson import reads as read_json, writes as write_json | |
9 | from .nbjson import to_notebook as to_notebook_json |
|
26 | from .nbjson import to_notebook as to_notebook_json | |
10 |
|
27 | |||
11 | from .nbxml import reads as reads_xml, writes as writes_xml |
|
28 | from .nbxml import reads as reads_xml, writes as writes_xml | |
12 | from .nbxml import reads as read_xml, writes as write_xml |
|
29 | from .nbxml import reads as read_xml, writes as write_xml | |
13 | from .nbxml import to_notebook as to_notebook_xml |
|
30 | from .nbxml import to_notebook as to_notebook_xml | |
14 |
|
31 | |||
15 | from .nbpy import reads as reads_py, writes as writes_py |
|
32 | from .nbpy import reads as reads_py, writes as writes_py | |
16 | from .nbpy import reads as read_py, writes as write_py |
|
33 | from .nbpy import reads as read_py, writes as write_py | |
17 | from .nbpy import to_notebook as to_notebook_py |
|
34 | from .nbpy import to_notebook as to_notebook_py | |
18 |
|
35 | |||
19 | from .convert import convert_to_this_nbformat |
|
36 | from .convert import convert_to_this_nbformat | |
20 |
|
37 | |||
|
38 | #----------------------------------------------------------------------------- | |||
|
39 | # Code | |||
|
40 | #----------------------------------------------------------------------------- | |||
21 |
|
41 | |||
22 | def parse_filename(fname): |
|
42 | def parse_filename(fname): | |
23 | """Parse a notebook filename. |
|
43 | """Parse a notebook filename. | |
24 |
|
44 | |||
25 | This function takes a notebook filename and returns the notebook |
|
45 | This function takes a notebook filename and returns the notebook | |
26 | format (xml/json/py) and the notebook name. This logic can be |
|
46 | format (xml/json/py) and the notebook name. This logic can be | |
27 | summarized as follows: |
|
47 | summarized as follows: | |
28 |
|
48 | |||
29 | * notebook.ipynb -> (notebook.ipynb, notebook, xml) |
|
49 | * notebook.ipynb -> (notebook.ipynb, notebook, xml) | |
30 | * notebook.json -> (notebook.json, notebook, json) |
|
50 | * notebook.json -> (notebook.json, notebook, json) | |
31 | * notebook.py -> (notebook.py, notebook, py) |
|
51 | * notebook.py -> (notebook.py, notebook, py) | |
32 | * notebook -> (notebook.ipynb, notebook, xml) |
|
52 | * notebook -> (notebook.ipynb, notebook, xml) | |
33 |
|
53 | |||
34 | Parameters |
|
54 | Parameters | |
35 | ---------- |
|
55 | ---------- | |
36 | fname : unicode |
|
56 | fname : unicode | |
37 | The notebook filename. The filename can use a specific filename |
|
57 | The notebook filename. The filename can use a specific filename | |
38 | extention (.ipynb, .json, .py) or none, in which case .ipynb will |
|
58 | extention (.ipynb, .json, .py) or none, in which case .ipynb will | |
39 | be assumed. |
|
59 | be assumed. | |
40 |
|
60 | |||
41 | Returns |
|
61 | Returns | |
42 | ------- |
|
62 | ------- | |
43 | (fname, name, format) : (unicode, unicode, unicode) |
|
63 | (fname, name, format) : (unicode, unicode, unicode) | |
44 | The filename, notebook name and format. |
|
64 | The filename, notebook name and format. | |
45 | """ |
|
65 | """ | |
46 | if fname.endswith(u'.ipynb'): |
|
66 | if fname.endswith(u'.ipynb'): | |
47 | format = u'xml' |
|
67 | format = u'xml' | |
48 | elif fname.endswith(u'.json'): |
|
68 | elif fname.endswith(u'.json'): | |
49 | format = u'json' |
|
69 | format = u'json' | |
50 | elif fname.endswith(u'.py'): |
|
70 | elif fname.endswith(u'.py'): | |
51 | format = u'py' |
|
71 | format = u'py' | |
52 | else: |
|
72 | else: | |
53 | fname = fname + u'.ipynb' |
|
73 | fname = fname + u'.ipynb' | |
54 | format = u'xml' |
|
74 | format = u'xml' | |
55 | name = fname.split('.')[0] |
|
75 | name = fname.split('.')[0] | |
56 | return fname, name, format |
|
76 | return fname, name, format | |
57 |
|
77 |
@@ -1,20 +1,50 b'' | |||||
|
1 | """Code for converting notebooks to and from the v2 format. | |||
|
2 | ||||
|
3 | Authors: | |||
|
4 | ||||
|
5 | * Brian Granger | |||
|
6 | """ | |||
|
7 | ||||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | # Copyright (C) 2008-2011 The IPython Development Team | |||
|
10 | # | |||
|
11 | # Distributed under the terms of the BSD License. The full license is in | |||
|
12 | # the file COPYING, distributed as part of this software. | |||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | ||||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | # Imports | |||
|
17 | #----------------------------------------------------------------------------- | |||
|
18 | ||||
1 | from .nbbase import ( |
|
19 | from .nbbase import ( | |
2 | new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output |
|
20 | new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output | |
3 | ) |
|
21 | ) | |
4 |
|
22 | |||
|
23 | #----------------------------------------------------------------------------- | |||
|
24 | # Code | |||
|
25 | #----------------------------------------------------------------------------- | |||
|
26 | ||||
5 | def convert_to_this_nbformat(nb, orig_version=1): |
|
27 | def convert_to_this_nbformat(nb, orig_version=1): | |
|
28 | """Convert a notebook to the v2 format. | |||
|
29 | ||||
|
30 | Parameters | |||
|
31 | ---------- | |||
|
32 | nb : NotebookNode | |||
|
33 | The Python representation of the notebook to convert. | |||
|
34 | orig_version : int | |||
|
35 | The original version of the notebook to convert. | |||
|
36 | """ | |||
6 | if orig_version == 1: |
|
37 | if orig_version == 1: | |
7 | newnb = new_notebook() |
|
38 | newnb = new_notebook() | |
8 | ws = new_worksheet() |
|
39 | ws = new_worksheet() | |
9 | for cell in nb.cells: |
|
40 | for cell in nb.cells: | |
10 | if cell.cell_type == u'code': |
|
41 | if cell.cell_type == u'code': | |
11 | newcell = new_code_cell(input=cell.get('code'),prompt_number=cell.get('prompt_number')) |
|
42 | newcell = new_code_cell(input=cell.get('code'),prompt_number=cell.get('prompt_number')) | |
12 | elif cell.cell_type == u'text': |
|
43 | elif cell.cell_type == u'text': | |
13 | newcell = new_text_cell(u'markdown',source=cell.get('text')) |
|
44 | newcell = new_text_cell(u'markdown',source=cell.get('text')) | |
14 | ws.cells.append(newcell) |
|
45 | ws.cells.append(newcell) | |
15 | newnb.worksheets.append(ws) |
|
46 | newnb.worksheets.append(ws) | |
16 | return newnb |
|
47 | return newnb | |
17 | else: |
|
48 | else: | |
18 | raise ValueError('Cannot convert a notebook from v%s to v2' % orig_version) |
|
49 | raise ValueError('Cannot convert a notebook from v%s to v2' % orig_version) | |
19 |
|
50 | |||
20 |
|
@@ -1,132 +1,156 b'' | |||||
1 |
"""The basic dict based notebook format. |
|
1 | """The basic dict based notebook format. | |
|
2 | ||||
|
3 | The Python representation of a notebook is a nested structure of | |||
|
4 | dictionary subclasses that support attribute access | |||
|
5 | (IPython.utils.ipstruct.Struct). The functions in this module are merely | |||
|
6 | helpers to build the structs in the right form. | |||
|
7 | ||||
|
8 | Authors: | |||
|
9 | ||||
|
10 | * Brian Granger | |||
|
11 | """ | |||
|
12 | ||||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | # Copyright (C) 2008-2011 The IPython Development Team | |||
|
15 | # | |||
|
16 | # Distributed under the terms of the BSD License. The full license is in | |||
|
17 | # the file COPYING, distributed as part of this software. | |||
|
18 | #----------------------------------------------------------------------------- | |||
|
19 | ||||
|
20 | #----------------------------------------------------------------------------- | |||
|
21 | # Imports | |||
|
22 | #----------------------------------------------------------------------------- | |||
2 |
|
23 | |||
3 | import pprint |
|
24 | import pprint | |
4 | import uuid |
|
25 | import uuid | |
5 |
|
26 | |||
6 | from IPython.utils.ipstruct import Struct |
|
27 | from IPython.utils.ipstruct import Struct | |
7 |
|
28 | |||
|
29 | #----------------------------------------------------------------------------- | |||
|
30 | # Code | |||
|
31 | #----------------------------------------------------------------------------- | |||
8 |
|
32 | |||
9 | class NotebookNode(Struct): |
|
33 | class NotebookNode(Struct): | |
10 | pass |
|
34 | pass | |
11 |
|
35 | |||
12 |
|
36 | |||
13 | def from_dict(d): |
|
37 | def from_dict(d): | |
14 | if isinstance(d, dict): |
|
38 | if isinstance(d, dict): | |
15 | newd = NotebookNode() |
|
39 | newd = NotebookNode() | |
16 | for k,v in d.items(): |
|
40 | for k,v in d.items(): | |
17 | newd[k] = from_dict(v) |
|
41 | newd[k] = from_dict(v) | |
18 | return newd |
|
42 | return newd | |
19 | elif isinstance(d, (tuple, list)): |
|
43 | elif isinstance(d, (tuple, list)): | |
20 | return [from_dict(i) for i in d] |
|
44 | return [from_dict(i) for i in d] | |
21 | else: |
|
45 | else: | |
22 | return d |
|
46 | return d | |
23 |
|
47 | |||
24 |
|
48 | |||
25 | def new_output(output_type=None, output_text=None, output_png=None, |
|
49 | def new_output(output_type=None, output_text=None, output_png=None, | |
26 | output_html=None, output_svg=None, output_latex=None, output_json=None, |
|
50 | output_html=None, output_svg=None, output_latex=None, output_json=None, | |
27 | output_javascript=None, output_jpeg=None, prompt_number=None, |
|
51 | output_javascript=None, output_jpeg=None, prompt_number=None, | |
28 | etype=None, evalue=None, traceback=None): |
|
52 | etype=None, evalue=None, traceback=None): | |
29 | """Create a new code cell with input and output""" |
|
53 | """Create a new code cell with input and output""" | |
30 | output = NotebookNode() |
|
54 | output = NotebookNode() | |
31 | if output_type is not None: |
|
55 | if output_type is not None: | |
32 | output.output_type = unicode(output_type) |
|
56 | output.output_type = unicode(output_type) | |
33 |
|
57 | |||
34 | if output_type != 'pyerr': |
|
58 | if output_type != 'pyerr': | |
35 | if output_text is not None: |
|
59 | if output_text is not None: | |
36 | output.text = unicode(output_text) |
|
60 | output.text = unicode(output_text) | |
37 | if output_png is not None: |
|
61 | if output_png is not None: | |
38 | output.png = bytes(output_png) |
|
62 | output.png = bytes(output_png) | |
39 | if output_jpeg is not None: |
|
63 | if output_jpeg is not None: | |
40 | output.jpeg = bytes(output_jpeg) |
|
64 | output.jpeg = bytes(output_jpeg) | |
41 | if output_html is not None: |
|
65 | if output_html is not None: | |
42 | output.html = unicode(output_html) |
|
66 | output.html = unicode(output_html) | |
43 | if output_svg is not None: |
|
67 | if output_svg is not None: | |
44 | output.svg = unicode(output_svg) |
|
68 | output.svg = unicode(output_svg) | |
45 | if output_latex is not None: |
|
69 | if output_latex is not None: | |
46 | output.latex = unicode(output_latex) |
|
70 | output.latex = unicode(output_latex) | |
47 | if output_json is not None: |
|
71 | if output_json is not None: | |
48 | output.json = unicode(output_json) |
|
72 | output.json = unicode(output_json) | |
49 | if output_javascript is not None: |
|
73 | if output_javascript is not None: | |
50 | output.javascript = unicode(output_javascript) |
|
74 | output.javascript = unicode(output_javascript) | |
51 |
|
75 | |||
52 | if output_type == u'pyout': |
|
76 | if output_type == u'pyout': | |
53 | if prompt_number is not None: |
|
77 | if prompt_number is not None: | |
54 | output.prompt_number = int(prompt_number) |
|
78 | output.prompt_number = int(prompt_number) | |
55 |
|
79 | |||
56 | if output_type == u'pyerr': |
|
80 | if output_type == u'pyerr': | |
57 | if etype is not None: |
|
81 | if etype is not None: | |
58 | output.etype = unicode(etype) |
|
82 | output.etype = unicode(etype) | |
59 | if evalue is not None: |
|
83 | if evalue is not None: | |
60 | output.evalue = unicode(evalue) |
|
84 | output.evalue = unicode(evalue) | |
61 | if traceback is not None: |
|
85 | if traceback is not None: | |
62 | output.traceback = [unicode(frame) for frame in list(traceback)] |
|
86 | output.traceback = [unicode(frame) for frame in list(traceback)] | |
63 |
|
87 | |||
64 | return output |
|
88 | return output | |
65 |
|
89 | |||
66 |
|
90 | |||
67 | def new_code_cell(input=None, prompt_number=None, outputs=None, |
|
91 | def new_code_cell(input=None, prompt_number=None, outputs=None, | |
68 | language=u'python', collapsed=False): |
|
92 | language=u'python', collapsed=False): | |
69 | """Create a new code cell with input and output""" |
|
93 | """Create a new code cell with input and output""" | |
70 | cell = NotebookNode() |
|
94 | cell = NotebookNode() | |
71 | cell.cell_type = u'code' |
|
95 | cell.cell_type = u'code' | |
72 | if language is not None: |
|
96 | if language is not None: | |
73 | cell.language = unicode(language) |
|
97 | cell.language = unicode(language) | |
74 | if input is not None: |
|
98 | if input is not None: | |
75 | cell.input = unicode(input) |
|
99 | cell.input = unicode(input) | |
76 | if prompt_number is not None: |
|
100 | if prompt_number is not None: | |
77 | cell.prompt_number = int(prompt_number) |
|
101 | cell.prompt_number = int(prompt_number) | |
78 | if outputs is None: |
|
102 | if outputs is None: | |
79 | cell.outputs = [] |
|
103 | cell.outputs = [] | |
80 | else: |
|
104 | else: | |
81 | cell.outputs = outputs |
|
105 | cell.outputs = outputs | |
82 | if collapsed is not None: |
|
106 | if collapsed is not None: | |
83 | cell.collapsed = bool(collapsed) |
|
107 | cell.collapsed = bool(collapsed) | |
84 |
|
108 | |||
85 | return cell |
|
109 | return cell | |
86 |
|
110 | |||
87 | def new_text_cell(cell_type, source=None, rendered=None): |
|
111 | def new_text_cell(cell_type, source=None, rendered=None): | |
88 | """Create a new text cell.""" |
|
112 | """Create a new text cell.""" | |
89 | cell = NotebookNode() |
|
113 | cell = NotebookNode() | |
90 | if source is not None: |
|
114 | if source is not None: | |
91 | cell.source = unicode(source) |
|
115 | cell.source = unicode(source) | |
92 | if rendered is not None: |
|
116 | if rendered is not None: | |
93 | cell.rendered = unicode(rendered) |
|
117 | cell.rendered = unicode(rendered) | |
94 | cell.cell_type = cell_type |
|
118 | cell.cell_type = cell_type | |
95 | return cell |
|
119 | return cell | |
96 |
|
120 | |||
97 |
|
121 | |||
98 | def new_worksheet(name=None, cells=None): |
|
122 | def new_worksheet(name=None, cells=None): | |
99 | """Create a worksheet by name with with a list of cells.""" |
|
123 | """Create a worksheet by name with with a list of cells.""" | |
100 | ws = NotebookNode() |
|
124 | ws = NotebookNode() | |
101 | if name is not None: |
|
125 | if name is not None: | |
102 | ws.name = unicode(name) |
|
126 | ws.name = unicode(name) | |
103 | if cells is None: |
|
127 | if cells is None: | |
104 | ws.cells = [] |
|
128 | ws.cells = [] | |
105 | else: |
|
129 | else: | |
106 | ws.cells = list(cells) |
|
130 | ws.cells = list(cells) | |
107 | return ws |
|
131 | return ws | |
108 |
|
132 | |||
109 |
|
133 | |||
110 | def new_notebook(name=None, worksheets=None, author=None, email=None, |
|
134 | def new_notebook(name=None, worksheets=None, author=None, email=None, | |
111 | created=None, saved=None, license=None): |
|
135 | created=None, saved=None, license=None): | |
112 | """Create a notebook by name, id and a list of worksheets.""" |
|
136 | """Create a notebook by name, id and a list of worksheets.""" | |
113 | nb = NotebookNode() |
|
137 | nb = NotebookNode() | |
114 | nb.nbformat = 2 |
|
138 | nb.nbformat = 2 | |
115 | if name is not None: |
|
139 | if name is not None: | |
116 | nb.name = unicode(name) |
|
140 | nb.name = unicode(name) | |
117 | if worksheets is None: |
|
141 | if worksheets is None: | |
118 | nb.worksheets = [] |
|
142 | nb.worksheets = [] | |
119 | else: |
|
143 | else: | |
120 | nb.worksheets = list(worksheets) |
|
144 | nb.worksheets = list(worksheets) | |
121 | if author is not None: |
|
145 | if author is not None: | |
122 | nb.author = unicode(author) |
|
146 | nb.author = unicode(author) | |
123 | if email is not None: |
|
147 | if email is not None: | |
124 | nb.email = unicode(email) |
|
148 | nb.email = unicode(email) | |
125 | if created is not None: |
|
149 | if created is not None: | |
126 | nb.created = unicode(created) |
|
150 | nb.created = unicode(created) | |
127 | if saved is not None: |
|
151 | if saved is not None: | |
128 | nb.saved = unicode(saved) |
|
152 | nb.saved = unicode(saved) | |
129 | if license is not None: |
|
153 | if license is not None: | |
130 | nb.license = unicode(license) |
|
154 | nb.license = unicode(license) | |
131 | return nb |
|
155 | return nb | |
132 |
|
156 |
@@ -1,43 +1,62 b'' | |||||
1 |
"""Read and write notebooks in JSON format. |
|
1 | """Read and write notebooks in JSON format. | |
|
2 | ||||
|
3 | Authors: | |||
|
4 | ||||
|
5 | * Brian Granger | |||
|
6 | """ | |||
|
7 | ||||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | # Copyright (C) 2008-2011 The IPython Development Team | |||
|
10 | # | |||
|
11 | # Distributed under the terms of the BSD License. The full license is in | |||
|
12 | # the file COPYING, distributed as part of this software. | |||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | ||||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | # Imports | |||
|
17 | #----------------------------------------------------------------------------- | |||
2 |
|
18 | |||
3 | from base64 import encodestring |
|
19 | from base64 import encodestring | |
4 | from .nbbase import from_dict |
|
20 | from .nbbase import from_dict | |
5 | from .rwbase import NotebookReader, NotebookWriter, base64_decode |
|
21 | from .rwbase import NotebookReader, NotebookWriter, base64_decode | |
6 | import json |
|
22 | import json | |
7 |
|
23 | |||
|
24 | #----------------------------------------------------------------------------- | |||
|
25 | # Code | |||
|
26 | #----------------------------------------------------------------------------- | |||
8 |
|
27 | |||
9 | class BytesEncoder(json.JSONEncoder): |
|
28 | class BytesEncoder(json.JSONEncoder): | |
10 | def default(self, obj): |
|
29 | def default(self, obj): | |
11 | if isinstance(obj, bytes): |
|
30 | if isinstance(obj, bytes): | |
12 | return unicode(encodestring(bytes)) |
|
31 | return unicode(encodestring(bytes)) | |
13 | return json.JSONEncoder.default(self, obj) |
|
32 | return json.JSONEncoder.default(self, obj) | |
14 |
|
33 | |||
15 |
|
34 | |||
16 | class JSONReader(NotebookReader): |
|
35 | class JSONReader(NotebookReader): | |
17 |
|
36 | |||
18 | def reads(self, s, **kwargs): |
|
37 | def reads(self, s, **kwargs): | |
19 | nb = json.loads(s, **kwargs) |
|
38 | nb = json.loads(s, **kwargs) | |
20 | nb = self.to_notebook(nb, **kwargs) |
|
39 | nb = self.to_notebook(nb, **kwargs) | |
21 | return nb |
|
40 | return nb | |
22 |
|
41 | |||
23 | def to_notebook(self, d, **kwargs): |
|
42 | def to_notebook(self, d, **kwargs): | |
24 | return base64_decode(from_dict(d)) |
|
43 | return base64_decode(from_dict(d)) | |
25 |
|
44 | |||
26 |
|
45 | |||
27 | class JSONWriter(NotebookWriter): |
|
46 | class JSONWriter(NotebookWriter): | |
28 |
|
47 | |||
29 | def writes(self, nb, **kwargs): |
|
48 | def writes(self, nb, **kwargs): | |
30 | kwargs['cls'] = BytesEncoder |
|
49 | kwargs['cls'] = BytesEncoder | |
31 | kwargs['indent'] = 4 |
|
50 | kwargs['indent'] = 4 | |
32 | return json.dumps(nb, **kwargs) |
|
51 | return json.dumps(nb, **kwargs) | |
33 |
|
52 | |||
34 |
|
53 | |||
35 | _reader = JSONReader() |
|
54 | _reader = JSONReader() | |
36 | _writer = JSONWriter() |
|
55 | _writer = JSONWriter() | |
37 |
|
56 | |||
38 | reads = _reader.reads |
|
57 | reads = _reader.reads | |
39 | read = _reader.read |
|
58 | read = _reader.read | |
40 | to_notebook = _reader.to_notebook |
|
59 | to_notebook = _reader.to_notebook | |
41 | write = _writer.write |
|
60 | write = _writer.write | |
42 | writes = _writer.writes |
|
61 | writes = _writer.writes | |
43 |
|
62 |
@@ -1,128 +1,147 b'' | |||||
1 |
"""Read and write notebooks as regular .py files. |
|
1 | """Read and write notebooks as regular .py files. | |
|
2 | ||||
|
3 | Authors: | |||
|
4 | ||||
|
5 | * Brian Granger | |||
|
6 | """ | |||
|
7 | ||||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | # Copyright (C) 2008-2011 The IPython Development Team | |||
|
10 | # | |||
|
11 | # Distributed under the terms of the BSD License. The full license is in | |||
|
12 | # the file COPYING, distributed as part of this software. | |||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | ||||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | # Imports | |||
|
17 | #----------------------------------------------------------------------------- | |||
2 |
|
18 | |||
3 | from .rwbase import NotebookReader, NotebookWriter |
|
19 | from .rwbase import NotebookReader, NotebookWriter | |
4 | from .nbbase import new_code_cell, new_text_cell, new_worksheet, new_notebook |
|
20 | from .nbbase import new_code_cell, new_text_cell, new_worksheet, new_notebook | |
5 |
|
21 | |||
|
22 | #----------------------------------------------------------------------------- | |||
|
23 | # Code | |||
|
24 | #----------------------------------------------------------------------------- | |||
6 |
|
25 | |||
7 | class PyReaderError(Exception): |
|
26 | class PyReaderError(Exception): | |
8 | pass |
|
27 | pass | |
9 |
|
28 | |||
10 |
|
29 | |||
11 | class PyReader(NotebookReader): |
|
30 | class PyReader(NotebookReader): | |
12 |
|
31 | |||
13 | def reads(self, s, **kwargs): |
|
32 | def reads(self, s, **kwargs): | |
14 | return self.to_notebook(s,**kwargs) |
|
33 | return self.to_notebook(s,**kwargs) | |
15 |
|
34 | |||
16 | def to_notebook(self, s, **kwargs): |
|
35 | def to_notebook(self, s, **kwargs): | |
17 | lines = s.splitlines() |
|
36 | lines = s.splitlines() | |
18 | cells = [] |
|
37 | cells = [] | |
19 | cell_lines = [] |
|
38 | cell_lines = [] | |
20 | state = u'codecell' |
|
39 | state = u'codecell' | |
21 | for line in lines: |
|
40 | for line in lines: | |
22 | if line.startswith(u'# <nbformat>'): |
|
41 | if line.startswith(u'# <nbformat>'): | |
23 | pass |
|
42 | pass | |
24 | elif line.startswith(u'# <codecell>'): |
|
43 | elif line.startswith(u'# <codecell>'): | |
25 | cell = self.new_cell(state, cell_lines) |
|
44 | cell = self.new_cell(state, cell_lines) | |
26 | if cell is not None: |
|
45 | if cell is not None: | |
27 | cells.append(cell) |
|
46 | cells.append(cell) | |
28 | state = u'codecell' |
|
47 | state = u'codecell' | |
29 | cell_lines = [] |
|
48 | cell_lines = [] | |
30 | elif line.startswith(u'# <htmlcell>'): |
|
49 | elif line.startswith(u'# <htmlcell>'): | |
31 | cell = self.new_cell(state, cell_lines) |
|
50 | cell = self.new_cell(state, cell_lines) | |
32 | if cell is not None: |
|
51 | if cell is not None: | |
33 | cells.append(cell) |
|
52 | cells.append(cell) | |
34 | state = u'htmlcell' |
|
53 | state = u'htmlcell' | |
35 | cell_lines = [] |
|
54 | cell_lines = [] | |
36 | elif line.startswith(u'# <markdowncell>'): |
|
55 | elif line.startswith(u'# <markdowncell>'): | |
37 | cell = self.new_cell(state, cell_lines) |
|
56 | cell = self.new_cell(state, cell_lines) | |
38 | if cell is not None: |
|
57 | if cell is not None: | |
39 | cells.append(cell) |
|
58 | cells.append(cell) | |
40 | state = u'markdowncell' |
|
59 | state = u'markdowncell' | |
41 | cell_lines = [] |
|
60 | cell_lines = [] | |
42 | else: |
|
61 | else: | |
43 | cell_lines.append(line) |
|
62 | cell_lines.append(line) | |
44 | if cell_lines and state == u'codecell': |
|
63 | if cell_lines and state == u'codecell': | |
45 | cell = self.new_cell(state, cell_lines) |
|
64 | cell = self.new_cell(state, cell_lines) | |
46 | if cell is not None: |
|
65 | if cell is not None: | |
47 | cells.append(cell) |
|
66 | cells.append(cell) | |
48 | ws = new_worksheet(cells=cells) |
|
67 | ws = new_worksheet(cells=cells) | |
49 | nb = new_notebook(worksheets=[ws]) |
|
68 | nb = new_notebook(worksheets=[ws]) | |
50 | return nb |
|
69 | return nb | |
51 |
|
70 | |||
52 | def new_cell(self, state, lines): |
|
71 | def new_cell(self, state, lines): | |
53 | if state == u'codecell': |
|
72 | if state == u'codecell': | |
54 | input = u'\n'.join(lines) |
|
73 | input = u'\n'.join(lines) | |
55 | input = input.strip(u'\n') |
|
74 | input = input.strip(u'\n') | |
56 | if input: |
|
75 | if input: | |
57 | return new_code_cell(input=input) |
|
76 | return new_code_cell(input=input) | |
58 | elif state == u'htmlcell': |
|
77 | elif state == u'htmlcell': | |
59 | text = self._remove_comments(lines) |
|
78 | text = self._remove_comments(lines) | |
60 | if text: |
|
79 | if text: | |
61 | return new_text_cell(u'html',source=text) |
|
80 | return new_text_cell(u'html',source=text) | |
62 | elif state == u'markdowncell': |
|
81 | elif state == u'markdowncell': | |
63 | text = self._remove_comments(lines) |
|
82 | text = self._remove_comments(lines) | |
64 | if text: |
|
83 | if text: | |
65 | return new_text_cell(u'markdown',source=text) |
|
84 | return new_text_cell(u'markdown',source=text) | |
66 |
|
85 | |||
67 | def _remove_comments(self, lines): |
|
86 | def _remove_comments(self, lines): | |
68 | new_lines = [] |
|
87 | new_lines = [] | |
69 | for line in lines: |
|
88 | for line in lines: | |
70 | if line.startswith(u'#'): |
|
89 | if line.startswith(u'#'): | |
71 | new_lines.append(line[2:]) |
|
90 | new_lines.append(line[2:]) | |
72 | else: |
|
91 | else: | |
73 | new_lines.append(line) |
|
92 | new_lines.append(line) | |
74 | text = u'\n'.join(new_lines) |
|
93 | text = u'\n'.join(new_lines) | |
75 | text = text.strip(u'\n') |
|
94 | text = text.strip(u'\n') | |
76 | return text |
|
95 | return text | |
77 |
|
96 | |||
78 | def split_lines_into_blocks(self, lines): |
|
97 | def split_lines_into_blocks(self, lines): | |
79 | if len(lines) == 1: |
|
98 | if len(lines) == 1: | |
80 | yield lines[0] |
|
99 | yield lines[0] | |
81 | raise StopIteration() |
|
100 | raise StopIteration() | |
82 | import ast |
|
101 | import ast | |
83 | source = '\n'.join(lines) |
|
102 | source = '\n'.join(lines) | |
84 | code = ast.parse(source) |
|
103 | code = ast.parse(source) | |
85 | starts = [x.lineno-1 for x in code.body] |
|
104 | starts = [x.lineno-1 for x in code.body] | |
86 | for i in range(len(starts)-1): |
|
105 | for i in range(len(starts)-1): | |
87 | yield '\n'.join(lines[starts[i]:starts[i+1]]).strip('\n') |
|
106 | yield '\n'.join(lines[starts[i]:starts[i+1]]).strip('\n') | |
88 | yield '\n'.join(lines[starts[-1]:]).strip('\n') |
|
107 | yield '\n'.join(lines[starts[-1]:]).strip('\n') | |
89 |
|
108 | |||
90 |
|
109 | |||
91 | class PyWriter(NotebookWriter): |
|
110 | class PyWriter(NotebookWriter): | |
92 |
|
111 | |||
93 | def writes(self, nb, **kwargs): |
|
112 | def writes(self, nb, **kwargs): | |
94 | lines = [] |
|
113 | lines = [] | |
95 | lines.extend([u'# <nbformat>2</nbformat>','']) |
|
114 | lines.extend([u'# <nbformat>2</nbformat>','']) | |
96 | for ws in nb.worksheets: |
|
115 | for ws in nb.worksheets: | |
97 | for cell in ws.cells: |
|
116 | for cell in ws.cells: | |
98 | if cell.cell_type == u'code': |
|
117 | if cell.cell_type == u'code': | |
99 | input = cell.get(u'input') |
|
118 | input = cell.get(u'input') | |
100 | if input is not None: |
|
119 | if input is not None: | |
101 | lines.extend([u'# <codecell>',u'']) |
|
120 | lines.extend([u'# <codecell>',u'']) | |
102 | lines.extend(input.splitlines()) |
|
121 | lines.extend(input.splitlines()) | |
103 | lines.append(u'') |
|
122 | lines.append(u'') | |
104 | elif cell.cell_type == u'html': |
|
123 | elif cell.cell_type == u'html': | |
105 | input = cell.get(u'source') |
|
124 | input = cell.get(u'source') | |
106 | if input is not None: |
|
125 | if input is not None: | |
107 | lines.extend([u'# <htmlcell>',u'']) |
|
126 | lines.extend([u'# <htmlcell>',u'']) | |
108 | lines.extend([u'# ' + line for line in input.splitlines()]) |
|
127 | lines.extend([u'# ' + line for line in input.splitlines()]) | |
109 | lines.append(u'') |
|
128 | lines.append(u'') | |
110 | elif cell.cell_type == u'markdown': |
|
129 | elif cell.cell_type == u'markdown': | |
111 | input = cell.get(u'source') |
|
130 | input = cell.get(u'source') | |
112 | if input is not None: |
|
131 | if input is not None: | |
113 | lines.extend([u'# <markdowncell>',u'']) |
|
132 | lines.extend([u'# <markdowncell>',u'']) | |
114 | lines.extend([u'# ' + line for line in input.splitlines()]) |
|
133 | lines.extend([u'# ' + line for line in input.splitlines()]) | |
115 | lines.append(u'') |
|
134 | lines.append(u'') | |
116 | lines.append('') |
|
135 | lines.append('') | |
117 | return unicode('\n'.join(lines)) |
|
136 | return unicode('\n'.join(lines)) | |
118 |
|
137 | |||
119 |
|
138 | |||
120 | _reader = PyReader() |
|
139 | _reader = PyReader() | |
121 | _writer = PyWriter() |
|
140 | _writer = PyWriter() | |
122 |
|
141 | |||
123 | reads = _reader.reads |
|
142 | reads = _reader.reads | |
124 | read = _reader.read |
|
143 | read = _reader.read | |
125 | to_notebook = _reader.to_notebook |
|
144 | to_notebook = _reader.to_notebook | |
126 | write = _writer.write |
|
145 | write = _writer.write | |
127 | writes = _writer.writes |
|
146 | writes = _writer.writes | |
128 |
|
147 |
@@ -1,226 +1,246 b'' | |||||
1 |
"""Read and write notebook files as XML. |
|
1 | """Read and write notebook files as XML. | |
|
2 | ||||
|
3 | Authors: | |||
|
4 | ||||
|
5 | * Brian Granger | |||
|
6 | """ | |||
|
7 | ||||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | # Copyright (C) 2008-2011 The IPython Development Team | |||
|
10 | # | |||
|
11 | # Distributed under the terms of the BSD License. The full license is in | |||
|
12 | # the file COPYING, distributed as part of this software. | |||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | ||||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | # Imports | |||
|
17 | #----------------------------------------------------------------------------- | |||
2 |
|
18 | |||
3 | from base64 import encodestring, decodestring |
|
19 | from base64 import encodestring, decodestring | |
4 | from xml.etree import ElementTree as ET |
|
20 | from xml.etree import ElementTree as ET | |
5 |
|
21 | |||
6 | from .rwbase import NotebookReader, NotebookWriter |
|
22 | from .rwbase import NotebookReader, NotebookWriter | |
7 | from .nbbase import ( |
|
23 | from .nbbase import ( | |
8 | new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output |
|
24 | new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output | |
9 | ) |
|
25 | ) | |
10 |
|
26 | |||
|
27 | #----------------------------------------------------------------------------- | |||
|
28 | # Code | |||
|
29 | #----------------------------------------------------------------------------- | |||
|
30 | ||||
11 | def indent(elem, level=0): |
|
31 | def indent(elem, level=0): | |
12 | i = "\n" + level*" " |
|
32 | i = "\n" + level*" " | |
13 | if len(elem): |
|
33 | if len(elem): | |
14 | if not elem.text or not elem.text.strip(): |
|
34 | if not elem.text or not elem.text.strip(): | |
15 | elem.text = i + " " |
|
35 | elem.text = i + " " | |
16 | if not elem.tail or not elem.tail.strip(): |
|
36 | if not elem.tail or not elem.tail.strip(): | |
17 | elem.tail = i |
|
37 | elem.tail = i | |
18 | for elem in elem: |
|
38 | for elem in elem: | |
19 | indent(elem, level+1) |
|
39 | indent(elem, level+1) | |
20 | if not elem.tail or not elem.tail.strip(): |
|
40 | if not elem.tail or not elem.tail.strip(): | |
21 | elem.tail = i |
|
41 | elem.tail = i | |
22 | else: |
|
42 | else: | |
23 | if level and (not elem.tail or not elem.tail.strip()): |
|
43 | if level and (not elem.tail or not elem.tail.strip()): | |
24 | elem.tail = i |
|
44 | elem.tail = i | |
25 |
|
45 | |||
26 |
|
46 | |||
27 | def _get_text(e, tag): |
|
47 | def _get_text(e, tag): | |
28 | sub_e = e.find(tag) |
|
48 | sub_e = e.find(tag) | |
29 | if sub_e is None: |
|
49 | if sub_e is None: | |
30 | return None |
|
50 | return None | |
31 | else: |
|
51 | else: | |
32 | return sub_e.text |
|
52 | return sub_e.text | |
33 |
|
53 | |||
34 |
|
54 | |||
35 | def _set_text(nbnode, attr, parent, tag): |
|
55 | def _set_text(nbnode, attr, parent, tag): | |
36 | if attr in nbnode: |
|
56 | if attr in nbnode: | |
37 | e = ET.SubElement(parent, tag) |
|
57 | e = ET.SubElement(parent, tag) | |
38 | e.text = nbnode[attr] |
|
58 | e.text = nbnode[attr] | |
39 |
|
59 | |||
40 |
|
60 | |||
41 | def _get_int(e, tag): |
|
61 | def _get_int(e, tag): | |
42 | sub_e = e.find(tag) |
|
62 | sub_e = e.find(tag) | |
43 | if sub_e is None: |
|
63 | if sub_e is None: | |
44 | return None |
|
64 | return None | |
45 | else: |
|
65 | else: | |
46 | return int(sub_e.text) |
|
66 | return int(sub_e.text) | |
47 |
|
67 | |||
48 |
|
68 | |||
49 | def _set_int(nbnode, attr, parent, tag): |
|
69 | def _set_int(nbnode, attr, parent, tag): | |
50 | if attr in nbnode: |
|
70 | if attr in nbnode: | |
51 | e = ET.SubElement(parent, tag) |
|
71 | e = ET.SubElement(parent, tag) | |
52 | e.text = unicode(nbnode[attr]) |
|
72 | e.text = unicode(nbnode[attr]) | |
53 |
|
73 | |||
54 |
|
74 | |||
55 | def _get_bool(e, tag): |
|
75 | def _get_bool(e, tag): | |
56 | sub_e = e.find(tag) |
|
76 | sub_e = e.find(tag) | |
57 | if sub_e is None: |
|
77 | if sub_e is None: | |
58 | return None |
|
78 | return None | |
59 | else: |
|
79 | else: | |
60 | return bool(int(sub_e.text)) |
|
80 | return bool(int(sub_e.text)) | |
61 |
|
81 | |||
62 |
|
82 | |||
63 | def _set_bool(nbnode, attr, parent, tag): |
|
83 | def _set_bool(nbnode, attr, parent, tag): | |
64 | if attr in nbnode: |
|
84 | if attr in nbnode: | |
65 | e = ET.SubElement(parent, tag) |
|
85 | e = ET.SubElement(parent, tag) | |
66 | if nbnode[attr]: |
|
86 | if nbnode[attr]: | |
67 | e.text = u'1' |
|
87 | e.text = u'1' | |
68 | else: |
|
88 | else: | |
69 | e.text = u'0' |
|
89 | e.text = u'0' | |
70 |
|
90 | |||
71 |
|
91 | |||
72 | def _get_binary(e, tag): |
|
92 | def _get_binary(e, tag): | |
73 | sub_e = e.find(tag) |
|
93 | sub_e = e.find(tag) | |
74 | if sub_e is None: |
|
94 | if sub_e is None: | |
75 | return None |
|
95 | return None | |
76 | else: |
|
96 | else: | |
77 | return decodestring(sub_e.text) |
|
97 | return decodestring(sub_e.text) | |
78 |
|
98 | |||
79 |
|
99 | |||
80 | def _set_binary(nbnode, attr, parent, tag): |
|
100 | def _set_binary(nbnode, attr, parent, tag): | |
81 | if attr in nbnode: |
|
101 | if attr in nbnode: | |
82 | e = ET.SubElement(parent, tag) |
|
102 | e = ET.SubElement(parent, tag) | |
83 | e.text = encodestring(nbnode[attr]) |
|
103 | e.text = encodestring(nbnode[attr]) | |
84 |
|
104 | |||
85 |
|
105 | |||
86 | class XMLReader(NotebookReader): |
|
106 | class XMLReader(NotebookReader): | |
87 |
|
107 | |||
88 | def reads(self, s, **kwargs): |
|
108 | def reads(self, s, **kwargs): | |
89 | root = ET.fromstring(s) |
|
109 | root = ET.fromstring(s) | |
90 | return self.to_notebook(root, **kwargs) |
|
110 | return self.to_notebook(root, **kwargs) | |
91 |
|
111 | |||
92 | def to_notebook(self, root, **kwargs): |
|
112 | def to_notebook(self, root, **kwargs): | |
93 | nbname = _get_text(root,u'name') |
|
113 | nbname = _get_text(root,u'name') | |
94 | nbauthor = _get_text(root,u'author') |
|
114 | nbauthor = _get_text(root,u'author') | |
95 | nbemail = _get_text(root,u'email') |
|
115 | nbemail = _get_text(root,u'email') | |
96 | nblicense = _get_text(root,u'license') |
|
116 | nblicense = _get_text(root,u'license') | |
97 | nbcreated = _get_text(root,u'created') |
|
117 | nbcreated = _get_text(root,u'created') | |
98 | nbsaved = _get_text(root,u'saved') |
|
118 | nbsaved = _get_text(root,u'saved') | |
99 |
|
119 | |||
100 | worksheets = [] |
|
120 | worksheets = [] | |
101 | for ws_e in root.find(u'worksheets').getiterator(u'worksheet'): |
|
121 | for ws_e in root.find(u'worksheets').getiterator(u'worksheet'): | |
102 | wsname = _get_text(ws_e,u'name') |
|
122 | wsname = _get_text(ws_e,u'name') | |
103 | cells = [] |
|
123 | cells = [] | |
104 | for cell_e in ws_e.find(u'cells').getiterator(): |
|
124 | for cell_e in ws_e.find(u'cells').getiterator(): | |
105 | if cell_e.tag == u'codecell': |
|
125 | if cell_e.tag == u'codecell': | |
106 | input = _get_text(cell_e,u'input') |
|
126 | input = _get_text(cell_e,u'input') | |
107 | prompt_number = _get_int(cell_e,u'prompt_number') |
|
127 | prompt_number = _get_int(cell_e,u'prompt_number') | |
108 | collapsed = _get_bool(cell_e,u'collapsed') |
|
128 | collapsed = _get_bool(cell_e,u'collapsed') | |
109 | language = _get_text(cell_e,u'language') |
|
129 | language = _get_text(cell_e,u'language') | |
110 | outputs = [] |
|
130 | outputs = [] | |
111 | for output_e in cell_e.find(u'outputs').getiterator(u'output'): |
|
131 | for output_e in cell_e.find(u'outputs').getiterator(u'output'): | |
112 | output_type = _get_text(output_e,u'output_type') |
|
132 | output_type = _get_text(output_e,u'output_type') | |
113 | output_text = _get_text(output_e,u'text') |
|
133 | output_text = _get_text(output_e,u'text') | |
114 | output_png = _get_binary(output_e,u'png') |
|
134 | output_png = _get_binary(output_e,u'png') | |
115 | output_jpeg = _get_binary(output_e,u'jpeg') |
|
135 | output_jpeg = _get_binary(output_e,u'jpeg') | |
116 | output_svg = _get_text(output_e,u'svg') |
|
136 | output_svg = _get_text(output_e,u'svg') | |
117 | output_html = _get_text(output_e,u'html') |
|
137 | output_html = _get_text(output_e,u'html') | |
118 | output_latex = _get_text(output_e,u'latex') |
|
138 | output_latex = _get_text(output_e,u'latex') | |
119 | output_json = _get_text(output_e,u'json') |
|
139 | output_json = _get_text(output_e,u'json') | |
120 | output_javascript = _get_text(output_e,u'javascript') |
|
140 | output_javascript = _get_text(output_e,u'javascript') | |
121 |
|
141 | |||
122 | out_prompt_number = _get_int(output_e,u'prompt_number') |
|
142 | out_prompt_number = _get_int(output_e,u'prompt_number') | |
123 | etype = _get_text(output_e,u'etype') |
|
143 | etype = _get_text(output_e,u'etype') | |
124 | evalue = _get_text(output_e,u'evalue') |
|
144 | evalue = _get_text(output_e,u'evalue') | |
125 | traceback = [] |
|
145 | traceback = [] | |
126 | traceback_e = output_e.find(u'traceback') |
|
146 | traceback_e = output_e.find(u'traceback') | |
127 | if traceback_e is not None: |
|
147 | if traceback_e is not None: | |
128 | for frame_e in traceback_e.getiterator(u'frame'): |
|
148 | for frame_e in traceback_e.getiterator(u'frame'): | |
129 | traceback.append(frame_e.text) |
|
149 | traceback.append(frame_e.text) | |
130 | if len(traceback) == 0: |
|
150 | if len(traceback) == 0: | |
131 | traceback = None |
|
151 | traceback = None | |
132 | output = new_output(output_type=output_type,output_png=output_png, |
|
152 | output = new_output(output_type=output_type,output_png=output_png, | |
133 | output_text=output_text, output_svg=output_svg, |
|
153 | output_text=output_text, output_svg=output_svg, | |
134 | output_html=output_html, output_latex=output_latex, |
|
154 | output_html=output_html, output_latex=output_latex, | |
135 | output_json=output_json, output_javascript=output_javascript, |
|
155 | output_json=output_json, output_javascript=output_javascript, | |
136 | output_jpeg=output_jpeg, prompt_number=out_prompt_number, |
|
156 | output_jpeg=output_jpeg, prompt_number=out_prompt_number, | |
137 | etype=etype, evalue=evalue, traceback=traceback |
|
157 | etype=etype, evalue=evalue, traceback=traceback | |
138 | ) |
|
158 | ) | |
139 | outputs.append(output) |
|
159 | outputs.append(output) | |
140 | cc = new_code_cell(input=input,prompt_number=prompt_number, |
|
160 | cc = new_code_cell(input=input,prompt_number=prompt_number, | |
141 | language=language,outputs=outputs,collapsed=collapsed) |
|
161 | language=language,outputs=outputs,collapsed=collapsed) | |
142 | cells.append(cc) |
|
162 | cells.append(cc) | |
143 | if cell_e.tag == u'htmlcell': |
|
163 | if cell_e.tag == u'htmlcell': | |
144 | source = _get_text(cell_e,u'source') |
|
164 | source = _get_text(cell_e,u'source') | |
145 | rendered = _get_text(cell_e,u'rendered') |
|
165 | rendered = _get_text(cell_e,u'rendered') | |
146 | cells.append(new_text_cell(u'html', source=source, rendered=rendered)) |
|
166 | cells.append(new_text_cell(u'html', source=source, rendered=rendered)) | |
147 | if cell_e.tag == u'markdowncell': |
|
167 | if cell_e.tag == u'markdowncell': | |
148 | source = _get_text(cell_e,u'source') |
|
168 | source = _get_text(cell_e,u'source') | |
149 | rendered = _get_text(cell_e,u'rendered') |
|
169 | rendered = _get_text(cell_e,u'rendered') | |
150 | cells.append(new_text_cell(u'markdown', source=source, rendered=rendered)) |
|
170 | cells.append(new_text_cell(u'markdown', source=source, rendered=rendered)) | |
151 | ws = new_worksheet(name=wsname,cells=cells) |
|
171 | ws = new_worksheet(name=wsname,cells=cells) | |
152 | worksheets.append(ws) |
|
172 | worksheets.append(ws) | |
153 |
|
173 | |||
154 | nb = new_notebook(name=nbname,worksheets=worksheets,author=nbauthor, |
|
174 | nb = new_notebook(name=nbname,worksheets=worksheets,author=nbauthor, | |
155 | email=nbemail,license=nblicense,saved=nbsaved,created=nbcreated) |
|
175 | email=nbemail,license=nblicense,saved=nbsaved,created=nbcreated) | |
156 | return nb |
|
176 | return nb | |
157 |
|
177 | |||
158 |
|
178 | |||
159 | class XMLWriter(NotebookWriter): |
|
179 | class XMLWriter(NotebookWriter): | |
160 |
|
180 | |||
161 | def writes(self, nb, **kwargs): |
|
181 | def writes(self, nb, **kwargs): | |
162 | nb_e = ET.Element(u'notebook') |
|
182 | nb_e = ET.Element(u'notebook') | |
163 | _set_text(nb,u'name',nb_e,u'name') |
|
183 | _set_text(nb,u'name',nb_e,u'name') | |
164 | _set_text(nb,u'author',nb_e,u'author') |
|
184 | _set_text(nb,u'author',nb_e,u'author') | |
165 | _set_text(nb,u'email',nb_e,u'email') |
|
185 | _set_text(nb,u'email',nb_e,u'email') | |
166 | _set_text(nb,u'license',nb_e,u'license') |
|
186 | _set_text(nb,u'license',nb_e,u'license') | |
167 | _set_text(nb,u'created',nb_e,u'created') |
|
187 | _set_text(nb,u'created',nb_e,u'created') | |
168 | _set_text(nb,u'saved',nb_e,u'saved') |
|
188 | _set_text(nb,u'saved',nb_e,u'saved') | |
169 | _set_int(nb,u'nbformat',nb_e,u'nbformat') |
|
189 | _set_int(nb,u'nbformat',nb_e,u'nbformat') | |
170 | wss_e = ET.SubElement(nb_e,u'worksheets') |
|
190 | wss_e = ET.SubElement(nb_e,u'worksheets') | |
171 | for ws in nb.worksheets: |
|
191 | for ws in nb.worksheets: | |
172 | ws_e = ET.SubElement(wss_e, u'worksheet') |
|
192 | ws_e = ET.SubElement(wss_e, u'worksheet') | |
173 | _set_text(ws,u'name',ws_e,u'name') |
|
193 | _set_text(ws,u'name',ws_e,u'name') | |
174 | cells_e = ET.SubElement(ws_e,u'cells') |
|
194 | cells_e = ET.SubElement(ws_e,u'cells') | |
175 | for cell in ws.cells: |
|
195 | for cell in ws.cells: | |
176 | cell_type = cell.cell_type |
|
196 | cell_type = cell.cell_type | |
177 | if cell_type == u'code': |
|
197 | if cell_type == u'code': | |
178 | cell_e = ET.SubElement(cells_e, u'codecell') |
|
198 | cell_e = ET.SubElement(cells_e, u'codecell') | |
179 | _set_text(cell,u'input',cell_e,u'input') |
|
199 | _set_text(cell,u'input',cell_e,u'input') | |
180 | _set_text(cell,u'language',cell_e,u'language') |
|
200 | _set_text(cell,u'language',cell_e,u'language') | |
181 | _set_int(cell,u'prompt_number',cell_e,u'prompt_number') |
|
201 | _set_int(cell,u'prompt_number',cell_e,u'prompt_number') | |
182 | _set_bool(cell,u'collapsed',cell_e,u'collapsed') |
|
202 | _set_bool(cell,u'collapsed',cell_e,u'collapsed') | |
183 | outputs_e = ET.SubElement(cell_e, u'outputs') |
|
203 | outputs_e = ET.SubElement(cell_e, u'outputs') | |
184 | for output in cell.outputs: |
|
204 | for output in cell.outputs: | |
185 | output_e = ET.SubElement(outputs_e, u'output') |
|
205 | output_e = ET.SubElement(outputs_e, u'output') | |
186 | _set_text(output,u'output_type',output_e,u'output_type') |
|
206 | _set_text(output,u'output_type',output_e,u'output_type') | |
187 | _set_text(output,u'text',output_e,u'text') |
|
207 | _set_text(output,u'text',output_e,u'text') | |
188 | _set_binary(output,u'png',output_e,u'png') |
|
208 | _set_binary(output,u'png',output_e,u'png') | |
189 | _set_binary(output,u'jpeg',output_e,u'jpeg') |
|
209 | _set_binary(output,u'jpeg',output_e,u'jpeg') | |
190 | _set_text(output,u'html',output_e,u'html') |
|
210 | _set_text(output,u'html',output_e,u'html') | |
191 | _set_text(output,u'svg',output_e,u'svg') |
|
211 | _set_text(output,u'svg',output_e,u'svg') | |
192 | _set_text(output,u'latex',output_e,u'latex') |
|
212 | _set_text(output,u'latex',output_e,u'latex') | |
193 | _set_text(output,u'json',output_e,u'json') |
|
213 | _set_text(output,u'json',output_e,u'json') | |
194 | _set_text(output,u'javascript',output_e,u'javascript') |
|
214 | _set_text(output,u'javascript',output_e,u'javascript') | |
195 | _set_int(output,u'prompt_number',output_e,u'prompt_number') |
|
215 | _set_int(output,u'prompt_number',output_e,u'prompt_number') | |
196 | _set_text(output,u'etype',output_e,u'etype') |
|
216 | _set_text(output,u'etype',output_e,u'etype') | |
197 | _set_text(output,u'evalue',output_e,u'evalue') |
|
217 | _set_text(output,u'evalue',output_e,u'evalue') | |
198 | if u'traceback' in output: |
|
218 | if u'traceback' in output: | |
199 | tb_e = ET.SubElement(output_e, u'traceback') |
|
219 | tb_e = ET.SubElement(output_e, u'traceback') | |
200 | for frame in output.traceback: |
|
220 | for frame in output.traceback: | |
201 | frame_e = ET.SubElement(tb_e, u'frame') |
|
221 | frame_e = ET.SubElement(tb_e, u'frame') | |
202 | frame_e.text = frame |
|
222 | frame_e.text = frame | |
203 | elif cell_type == u'html': |
|
223 | elif cell_type == u'html': | |
204 | cell_e = ET.SubElement(cells_e, u'htmlcell') |
|
224 | cell_e = ET.SubElement(cells_e, u'htmlcell') | |
205 | _set_text(cell,u'source',cell_e,u'source') |
|
225 | _set_text(cell,u'source',cell_e,u'source') | |
206 | _set_text(cell,u'rendered',cell_e,u'rendered') |
|
226 | _set_text(cell,u'rendered',cell_e,u'rendered') | |
207 | elif cell_type == u'markdown': |
|
227 | elif cell_type == u'markdown': | |
208 | cell_e = ET.SubElement(cells_e, u'markdowncell') |
|
228 | cell_e = ET.SubElement(cells_e, u'markdowncell') | |
209 | _set_text(cell,u'source',cell_e,u'source') |
|
229 | _set_text(cell,u'source',cell_e,u'source') | |
210 | _set_text(cell,u'rendered',cell_e,u'rendered') |
|
230 | _set_text(cell,u'rendered',cell_e,u'rendered') | |
211 |
|
231 | |||
212 | indent(nb_e) |
|
232 | indent(nb_e) | |
213 | txt = ET.tostring(nb_e, encoding="utf-8") |
|
233 | txt = ET.tostring(nb_e, encoding="utf-8") | |
214 | txt = '<?xml version="1.0" encoding="utf-8"?>\n' + txt |
|
234 | txt = '<?xml version="1.0" encoding="utf-8"?>\n' + txt | |
215 | return txt |
|
235 | return txt | |
216 |
|
236 | |||
217 |
|
237 | |||
218 | _reader = XMLReader() |
|
238 | _reader = XMLReader() | |
219 | _writer = XMLWriter() |
|
239 | _writer = XMLWriter() | |
220 |
|
240 | |||
221 | reads = _reader.reads |
|
241 | reads = _reader.reads | |
222 | read = _reader.read |
|
242 | read = _reader.read | |
223 | to_notebook = _reader.to_notebook |
|
243 | to_notebook = _reader.to_notebook | |
224 | write = _writer.write |
|
244 | write = _writer.write | |
225 | writes = _writer.writes |
|
245 | writes = _writer.writes | |
226 |
|
246 |
@@ -1,50 +1,74 b'' | |||||
|
1 | """Base classes and utilities for readers and writers. | |||
|
2 | ||||
|
3 | Authors: | |||
|
4 | ||||
|
5 | * Brian Granger | |||
|
6 | """ | |||
|
7 | ||||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | # Copyright (C) 2008-2011 The IPython Development Team | |||
|
10 | # | |||
|
11 | # Distributed under the terms of the BSD License. The full license is in | |||
|
12 | # the file COPYING, distributed as part of this software. | |||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | ||||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | # Imports | |||
|
17 | #----------------------------------------------------------------------------- | |||
|
18 | ||||
1 | from base64 import encodestring, decodestring |
|
19 | from base64 import encodestring, decodestring | |
2 | import pprint |
|
20 | import pprint | |
3 |
|
21 | |||
|
22 | #----------------------------------------------------------------------------- | |||
|
23 | # Code | |||
|
24 | #----------------------------------------------------------------------------- | |||
|
25 | ||||
4 | def base64_decode(nb): |
|
26 | def base64_decode(nb): | |
5 | """Base64 encode all bytes objects in the notebook.""" |
|
27 | """Base64 encode all bytes objects in the notebook.""" | |
6 | for ws in nb.worksheets: |
|
28 | for ws in nb.worksheets: | |
7 | for cell in ws.cells: |
|
29 | for cell in ws.cells: | |
8 | if cell.cell_type == 'code': |
|
30 | if cell.cell_type == 'code': | |
9 | if 'png' in cell: |
|
31 | if 'png' in cell: | |
10 | cell.png = bytes(decodestring(cell.png)) |
|
32 | cell.png = bytes(decodestring(cell.png)) | |
11 | if 'jpeg' in cell: |
|
33 | if 'jpeg' in cell: | |
12 | cell.jpeg = bytes(decodestring(cell.jpeg)) |
|
34 | cell.jpeg = bytes(decodestring(cell.jpeg)) | |
13 | return nb |
|
35 | return nb | |
14 |
|
36 | |||
15 |
|
37 | |||
16 | def base64_encode(nb): |
|
38 | def base64_encode(nb): | |
17 | """Base64 decode all binary objects in the notebook.""" |
|
39 | """Base64 decode all binary objects in the notebook.""" | |
18 | for ws in nb.worksheets: |
|
40 | for ws in nb.worksheets: | |
19 | for cell in ws.cells: |
|
41 | for cell in ws.cells: | |
20 | if cell.cell_type == 'code': |
|
42 | if cell.cell_type == 'code': | |
21 | if 'png' in cell: |
|
43 | if 'png' in cell: | |
22 | cell.png = unicode(encodestring(cell.png)) |
|
44 | cell.png = unicode(encodestring(cell.png)) | |
23 | if 'jpeg' in cell: |
|
45 | if 'jpeg' in cell: | |
24 | cell.jpeg = unicode(encodestring(cell.jpeg)) |
|
46 | cell.jpeg = unicode(encodestring(cell.jpeg)) | |
25 | return nb |
|
47 | return nb | |
26 |
|
48 | |||
27 |
|
49 | |||
28 | class NotebookReader(object): |
|
50 | class NotebookReader(object): | |
|
51 | """A class for reading notebooks.""" | |||
29 |
|
52 | |||
30 | def reads(self, s, **kwargs): |
|
53 | def reads(self, s, **kwargs): | |
31 | """Read a notebook from a string.""" |
|
54 | """Read a notebook from a string.""" | |
32 | raise NotImplementedError("loads must be implemented in a subclass") |
|
55 | raise NotImplementedError("loads must be implemented in a subclass") | |
33 |
|
56 | |||
34 | def read(self, fp, **kwargs): |
|
57 | def read(self, fp, **kwargs): | |
35 | """Read a notebook from a file like object""" |
|
58 | """Read a notebook from a file like object""" | |
36 | return self.read(fp.read(), **kwargs) |
|
59 | return self.read(fp.read(), **kwargs) | |
37 |
|
60 | |||
38 |
|
61 | |||
39 | class NotebookWriter(object): |
|
62 | class NotebookWriter(object): | |
|
63 | """A class for writing notebooks.""" | |||
40 |
|
64 | |||
41 | def writes(self, nb, **kwargs): |
|
65 | def writes(self, nb, **kwargs): | |
42 | """Write a notebook to a string.""" |
|
66 | """Write a notebook to a string.""" | |
43 | raise NotImplementedError("loads must be implemented in a subclass") |
|
67 | raise NotImplementedError("loads must be implemented in a subclass") | |
44 |
|
68 | |||
45 | def write(self, nb, fp, **kwargs): |
|
69 | def write(self, nb, fp, **kwargs): | |
46 | """Write a notebook to a file like object""" |
|
70 | """Write a notebook to a file like object""" | |
47 | return fp.write(self.writes(nb,**kwargs)) |
|
71 | return fp.write(self.writes(nb,**kwargs)) | |
48 |
|
72 | |||
49 |
|
73 | |||
50 |
|
74 |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now