Show More
@@ -1,2012 +1,2012 b'' | |||||
1 | """Completion for IPython. |
|
1 | """Completion for IPython. | |
2 |
|
2 | |||
3 | This module started as fork of the rlcompleter module in the Python standard |
|
3 | This module started as fork of the rlcompleter module in the Python standard | |
4 | library. The original enhancements made to rlcompleter have been sent |
|
4 | library. The original enhancements made to rlcompleter have been sent | |
5 | upstream and were accepted as of Python 2.3, |
|
5 | upstream and were accepted as of Python 2.3, | |
6 |
|
6 | |||
7 | This module now support a wide variety of completion mechanism both available |
|
7 | This module now support a wide variety of completion mechanism both available | |
8 | for normal classic Python code, as well as completer for IPython specific |
|
8 | for normal classic Python code, as well as completer for IPython specific | |
9 | Syntax like magics. |
|
9 | Syntax like magics. | |
10 |
|
10 | |||
11 | Latex and Unicode completion |
|
11 | Latex and Unicode completion | |
12 | ============================ |
|
12 | ============================ | |
13 |
|
13 | |||
14 | IPython and compatible frontends not only can complete your code, but can help |
|
14 | IPython and compatible frontends not only can complete your code, but can help | |
15 | you to input a wide range of characters. In particular we allow you to insert |
|
15 | you to input a wide range of characters. In particular we allow you to insert | |
16 | a unicode character using the tab completion mechanism. |
|
16 | a unicode character using the tab completion mechanism. | |
17 |
|
17 | |||
18 | Forward latex/unicode completion |
|
18 | Forward latex/unicode completion | |
19 | -------------------------------- |
|
19 | -------------------------------- | |
20 |
|
20 | |||
21 | Forward completion allows you to easily type a unicode character using its latex |
|
21 | Forward completion allows you to easily type a unicode character using its latex | |
22 | name, or unicode long description. To do so type a backslash follow by the |
|
22 | name, or unicode long description. To do so type a backslash follow by the | |
23 | relevant name and press tab: |
|
23 | relevant name and press tab: | |
24 |
|
24 | |||
25 |
|
25 | |||
26 | Using latex completion: |
|
26 | Using latex completion: | |
27 |
|
27 | |||
28 | .. code:: |
|
28 | .. code:: | |
29 |
|
29 | |||
30 | \\alpha<tab> |
|
30 | \\alpha<tab> | |
31 | Ξ± |
|
31 | Ξ± | |
32 |
|
32 | |||
33 | or using unicode completion: |
|
33 | or using unicode completion: | |
34 |
|
34 | |||
35 |
|
35 | |||
36 | .. code:: |
|
36 | .. code:: | |
37 |
|
37 | |||
38 | \\greek small letter alpha<tab> |
|
38 | \\greek small letter alpha<tab> | |
39 | Ξ± |
|
39 | Ξ± | |
40 |
|
40 | |||
41 |
|
41 | |||
42 | Only valid Python identifiers will complete. Combining characters (like arrow or |
|
42 | Only valid Python identifiers will complete. Combining characters (like arrow or | |
43 | dots) are also available, unlike latex they need to be put after the their |
|
43 | dots) are also available, unlike latex they need to be put after the their | |
44 | counterpart that is to say, `F\\\\vec<tab>` is correct, not `\\\\vec<tab>F`. |
|
44 | counterpart that is to say, `F\\\\vec<tab>` is correct, not `\\\\vec<tab>F`. | |
45 |
|
45 | |||
46 | Some browsers are known to display combining characters incorrectly. |
|
46 | Some browsers are known to display combining characters incorrectly. | |
47 |
|
47 | |||
48 | Backward latex completion |
|
48 | Backward latex completion | |
49 | ------------------------- |
|
49 | ------------------------- | |
50 |
|
50 | |||
51 | It is sometime challenging to know how to type a character, if you are using |
|
51 | It is sometime challenging to know how to type a character, if you are using | |
52 | IPython, or any compatible frontend you can prepend backslash to the character |
|
52 | IPython, or any compatible frontend you can prepend backslash to the character | |
53 | and press `<tab>` to expand it to its latex form. |
|
53 | and press `<tab>` to expand it to its latex form. | |
54 |
|
54 | |||
55 | .. code:: |
|
55 | .. code:: | |
56 |
|
56 | |||
57 | \\Ξ±<tab> |
|
57 | \\Ξ±<tab> | |
58 | \\alpha |
|
58 | \\alpha | |
59 |
|
59 | |||
60 |
|
60 | |||
61 | Both forward and backward completions can be deactivated by setting the |
|
61 | Both forward and backward completions can be deactivated by setting the | |
62 | ``Completer.backslash_combining_completions`` option to ``False``. |
|
62 | ``Completer.backslash_combining_completions`` option to ``False``. | |
63 |
|
63 | |||
64 |
|
64 | |||
65 | Experimental |
|
65 | Experimental | |
66 | ============ |
|
66 | ============ | |
67 |
|
67 | |||
68 | Starting with IPython 6.0, this module can make use of the Jedi library to |
|
68 | Starting with IPython 6.0, this module can make use of the Jedi library to | |
69 | generate completions both using static analysis of the code, and dynamically |
|
69 | generate completions both using static analysis of the code, and dynamically | |
70 | inspecting multiple namespaces. The APIs attached to this new mechanism is |
|
70 | inspecting multiple namespaces. The APIs attached to this new mechanism is | |
71 | unstable and will raise unless use in an :any:`provisionalcompleter` context |
|
71 | unstable and will raise unless use in an :any:`provisionalcompleter` context | |
72 | manager. |
|
72 | manager. | |
73 |
|
73 | |||
74 | You will find that the following are experimental: |
|
74 | You will find that the following are experimental: | |
75 |
|
75 | |||
76 | - :any:`provisionalcompleter` |
|
76 | - :any:`provisionalcompleter` | |
77 | - :any:`IPCompleter.completions` |
|
77 | - :any:`IPCompleter.completions` | |
78 | - :any:`Completion` |
|
78 | - :any:`Completion` | |
79 | - :any:`rectify_completions` |
|
79 | - :any:`rectify_completions` | |
80 |
|
80 | |||
81 | .. note:: |
|
81 | .. note:: | |
82 |
|
82 | |||
83 | better name for :any:`rectify_completions` ? |
|
83 | better name for :any:`rectify_completions` ? | |
84 |
|
84 | |||
85 | We welcome any feedback on these new API, and we also encourage you to try this |
|
85 | We welcome any feedback on these new API, and we also encourage you to try this | |
86 | module in debug mode (start IPython with ``--Completer.debug=True``) in order |
|
86 | module in debug mode (start IPython with ``--Completer.debug=True``) in order | |
87 | to have extra logging information is :any:`jedi` is crashing, or if current |
|
87 | to have extra logging information is :any:`jedi` is crashing, or if current | |
88 | IPython completer pending deprecations are returning results not yet handled |
|
88 | IPython completer pending deprecations are returning results not yet handled | |
89 | by :any:`jedi` |
|
89 | by :any:`jedi` | |
90 |
|
90 | |||
91 | Using Jedi for tab completion allow snippets like the following to work without |
|
91 | Using Jedi for tab completion allow snippets like the following to work without | |
92 | having to execute any code: |
|
92 | having to execute any code: | |
93 |
|
93 | |||
94 | >>> myvar = ['hello', 42] |
|
94 | >>> myvar = ['hello', 42] | |
95 | ... myvar[1].bi<tab> |
|
95 | ... myvar[1].bi<tab> | |
96 |
|
96 | |||
97 | Tab completion will be able to infer that ``myvar[1]`` is a real number without |
|
97 | Tab completion will be able to infer that ``myvar[1]`` is a real number without | |
98 | executing any code unlike the previously available ``IPCompleter.greedy`` |
|
98 | executing any code unlike the previously available ``IPCompleter.greedy`` | |
99 | option. |
|
99 | option. | |
100 |
|
100 | |||
101 | Be sure to update :any:`jedi` to the latest stable version or to try the |
|
101 | Be sure to update :any:`jedi` to the latest stable version or to try the | |
102 | current development version to get better completions. |
|
102 | current development version to get better completions. | |
103 | """ |
|
103 | """ | |
104 |
|
104 | |||
105 |
|
105 | |||
106 | # Copyright (c) IPython Development Team. |
|
106 | # Copyright (c) IPython Development Team. | |
107 | # Distributed under the terms of the Modified BSD License. |
|
107 | # Distributed under the terms of the Modified BSD License. | |
108 | # |
|
108 | # | |
109 | # Some of this code originated from rlcompleter in the Python standard library |
|
109 | # Some of this code originated from rlcompleter in the Python standard library | |
110 | # Copyright (C) 2001 Python Software Foundation, www.python.org |
|
110 | # Copyright (C) 2001 Python Software Foundation, www.python.org | |
111 |
|
111 | |||
112 |
|
112 | |||
113 | import __main__ |
|
113 | import __main__ | |
114 | import builtins as builtin_mod |
|
114 | import builtins as builtin_mod | |
115 | import glob |
|
115 | import glob | |
116 | import time |
|
116 | import time | |
117 | import inspect |
|
117 | import inspect | |
118 | import itertools |
|
118 | import itertools | |
119 | import keyword |
|
119 | import keyword | |
120 | import os |
|
120 | import os | |
121 | import re |
|
121 | import re | |
122 | import sys |
|
122 | import sys | |
123 | import unicodedata |
|
123 | import unicodedata | |
124 | import string |
|
124 | import string | |
125 | import warnings |
|
125 | import warnings | |
126 |
|
126 | |||
127 | from contextlib import contextmanager |
|
127 | from contextlib import contextmanager | |
128 | from importlib import import_module |
|
128 | from importlib import import_module | |
129 | from typing import Iterator, List, Tuple, Iterable, Union |
|
129 | from typing import Iterator, List, Tuple, Iterable, Union | |
130 | from types import SimpleNamespace |
|
130 | from types import SimpleNamespace | |
131 |
|
131 | |||
132 | from traitlets.config.configurable import Configurable |
|
132 | from traitlets.config.configurable import Configurable | |
133 | from IPython.core.error import TryNext |
|
133 | from IPython.core.error import TryNext | |
134 | from IPython.core.inputsplitter import ESC_MAGIC |
|
134 | from IPython.core.inputsplitter import ESC_MAGIC | |
135 | from IPython.core.latex_symbols import latex_symbols, reverse_latex_symbol |
|
135 | from IPython.core.latex_symbols import latex_symbols, reverse_latex_symbol | |
136 | from IPython.core.oinspect import InspectColors |
|
136 | from IPython.core.oinspect import InspectColors | |
137 | from IPython.utils import generics |
|
137 | from IPython.utils import generics | |
138 | from IPython.utils.dir2 import dir2, get_real_method |
|
138 | from IPython.utils.dir2 import dir2, get_real_method | |
139 | from IPython.utils.process import arg_split |
|
139 | from IPython.utils.process import arg_split | |
140 | from traitlets import Bool, Enum, observe, Int |
|
140 | from traitlets import Bool, Enum, observe, Int | |
141 |
|
141 | |||
142 | # skip module docstests |
|
142 | # skip module docstests | |
143 | skip_doctest = True |
|
143 | skip_doctest = True | |
144 |
|
144 | |||
145 | try: |
|
145 | try: | |
146 | import jedi |
|
146 | import jedi | |
147 | import jedi.api.helpers |
|
147 | import jedi.api.helpers | |
148 | import jedi.api.classes |
|
148 | import jedi.api.classes | |
149 | JEDI_INSTALLED = True |
|
149 | JEDI_INSTALLED = True | |
150 | except ImportError: |
|
150 | except ImportError: | |
151 | JEDI_INSTALLED = False |
|
151 | JEDI_INSTALLED = False | |
152 | #----------------------------------------------------------------------------- |
|
152 | #----------------------------------------------------------------------------- | |
153 | # Globals |
|
153 | # Globals | |
154 | #----------------------------------------------------------------------------- |
|
154 | #----------------------------------------------------------------------------- | |
155 |
|
155 | |||
156 | # Public API |
|
156 | # Public API | |
157 | __all__ = ['Completer','IPCompleter'] |
|
157 | __all__ = ['Completer','IPCompleter'] | |
158 |
|
158 | |||
159 | if sys.platform == 'win32': |
|
159 | if sys.platform == 'win32': | |
160 | PROTECTABLES = ' ' |
|
160 | PROTECTABLES = ' ' | |
161 | else: |
|
161 | else: | |
162 | PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&' |
|
162 | PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&' | |
163 |
|
163 | |||
164 |
|
164 | |||
165 | _deprecation_readline_sentinel = object() |
|
165 | _deprecation_readline_sentinel = object() | |
166 |
|
166 | |||
167 |
|
167 | |||
168 | class ProvisionalCompleterWarning(FutureWarning): |
|
168 | class ProvisionalCompleterWarning(FutureWarning): | |
169 | """ |
|
169 | """ | |
170 | Exception raise by an experimental feature in this module. |
|
170 | Exception raise by an experimental feature in this module. | |
171 |
|
171 | |||
172 | Wrap code in :any:`provisionalcompleter` context manager if you |
|
172 | Wrap code in :any:`provisionalcompleter` context manager if you | |
173 | are certain you want to use an unstable feature. |
|
173 | are certain you want to use an unstable feature. | |
174 | """ |
|
174 | """ | |
175 | pass |
|
175 | pass | |
176 |
|
176 | |||
177 | warnings.filterwarnings('error', category=ProvisionalCompleterWarning) |
|
177 | warnings.filterwarnings('error', category=ProvisionalCompleterWarning) | |
178 |
|
178 | |||
179 | @contextmanager |
|
179 | @contextmanager | |
180 | def provisionalcompleter(action='ignore'): |
|
180 | def provisionalcompleter(action='ignore'): | |
181 | """ |
|
181 | """ | |
182 |
|
182 | |||
183 |
|
183 | |||
184 | This contest manager has to be used in any place where unstable completer |
|
184 | This contest manager has to be used in any place where unstable completer | |
185 | behavior and API may be called. |
|
185 | behavior and API may be called. | |
186 |
|
186 | |||
187 | >>> with provisionalcompleter(): |
|
187 | >>> with provisionalcompleter(): | |
188 | ... completer.do_experimetal_things() # works |
|
188 | ... completer.do_experimetal_things() # works | |
189 |
|
189 | |||
190 | >>> completer.do_experimental_things() # raises. |
|
190 | >>> completer.do_experimental_things() # raises. | |
191 |
|
191 | |||
192 | .. note:: Unstable |
|
192 | .. note:: Unstable | |
193 |
|
193 | |||
194 | By using this context manager you agree that the API in use may change |
|
194 | By using this context manager you agree that the API in use may change | |
195 | without warning, and that you won't complain if they do so. |
|
195 | without warning, and that you won't complain if they do so. | |
196 |
|
196 | |||
197 | You also understand that if the API is not to you liking you should report |
|
197 | You also understand that if the API is not to you liking you should report | |
198 | a bug to explain your use case upstream and improve the API and will loose |
|
198 | a bug to explain your use case upstream and improve the API and will loose | |
199 | credibility if you complain after the API is make stable. |
|
199 | credibility if you complain after the API is make stable. | |
200 |
|
200 | |||
201 | We'll be happy to get your feedback , feature request and improvement on |
|
201 | We'll be happy to get your feedback , feature request and improvement on | |
202 | any of the unstable APIs ! |
|
202 | any of the unstable APIs ! | |
203 | """ |
|
203 | """ | |
204 | with warnings.catch_warnings(): |
|
204 | with warnings.catch_warnings(): | |
205 | warnings.filterwarnings(action, category=ProvisionalCompleterWarning) |
|
205 | warnings.filterwarnings(action, category=ProvisionalCompleterWarning) | |
206 | yield |
|
206 | yield | |
207 |
|
207 | |||
208 |
|
208 | |||
209 | def has_open_quotes(s): |
|
209 | def has_open_quotes(s): | |
210 | """Return whether a string has open quotes. |
|
210 | """Return whether a string has open quotes. | |
211 |
|
211 | |||
212 | This simply counts whether the number of quote characters of either type in |
|
212 | This simply counts whether the number of quote characters of either type in | |
213 | the string is odd. |
|
213 | the string is odd. | |
214 |
|
214 | |||
215 | Returns |
|
215 | Returns | |
216 | ------- |
|
216 | ------- | |
217 | If there is an open quote, the quote character is returned. Else, return |
|
217 | If there is an open quote, the quote character is returned. Else, return | |
218 | False. |
|
218 | False. | |
219 | """ |
|
219 | """ | |
220 | # We check " first, then ', so complex cases with nested quotes will get |
|
220 | # We check " first, then ', so complex cases with nested quotes will get | |
221 | # the " to take precedence. |
|
221 | # the " to take precedence. | |
222 | if s.count('"') % 2: |
|
222 | if s.count('"') % 2: | |
223 | return '"' |
|
223 | return '"' | |
224 | elif s.count("'") % 2: |
|
224 | elif s.count("'") % 2: | |
225 | return "'" |
|
225 | return "'" | |
226 | else: |
|
226 | else: | |
227 | return False |
|
227 | return False | |
228 |
|
228 | |||
229 |
|
229 | |||
230 | def protect_filename(s, protectables=PROTECTABLES): |
|
230 | def protect_filename(s, protectables=PROTECTABLES): | |
231 | """Escape a string to protect certain characters.""" |
|
231 | """Escape a string to protect certain characters.""" | |
232 | if set(s) & set(protectables): |
|
232 | if set(s) & set(protectables): | |
233 | if sys.platform == "win32": |
|
233 | if sys.platform == "win32": | |
234 | return '"' + s + '"' |
|
234 | return '"' + s + '"' | |
235 | else: |
|
235 | else: | |
236 | return "".join(("\\" + c if c in protectables else c) for c in s) |
|
236 | return "".join(("\\" + c if c in protectables else c) for c in s) | |
237 | else: |
|
237 | else: | |
238 | return s |
|
238 | return s | |
239 |
|
239 | |||
240 |
|
240 | |||
241 | def expand_user(path:str) -> Tuple[str, bool, str]: |
|
241 | def expand_user(path:str) -> Tuple[str, bool, str]: | |
242 | """Expand ``~``-style usernames in strings. |
|
242 | """Expand ``~``-style usernames in strings. | |
243 |
|
243 | |||
244 | This is similar to :func:`os.path.expanduser`, but it computes and returns |
|
244 | This is similar to :func:`os.path.expanduser`, but it computes and returns | |
245 | extra information that will be useful if the input was being used in |
|
245 | extra information that will be useful if the input was being used in | |
246 | computing completions, and you wish to return the completions with the |
|
246 | computing completions, and you wish to return the completions with the | |
247 | original '~' instead of its expanded value. |
|
247 | original '~' instead of its expanded value. | |
248 |
|
248 | |||
249 | Parameters |
|
249 | Parameters | |
250 | ---------- |
|
250 | ---------- | |
251 | path : str |
|
251 | path : str | |
252 | String to be expanded. If no ~ is present, the output is the same as the |
|
252 | String to be expanded. If no ~ is present, the output is the same as the | |
253 | input. |
|
253 | input. | |
254 |
|
254 | |||
255 | Returns |
|
255 | Returns | |
256 | ------- |
|
256 | ------- | |
257 | newpath : str |
|
257 | newpath : str | |
258 | Result of ~ expansion in the input path. |
|
258 | Result of ~ expansion in the input path. | |
259 | tilde_expand : bool |
|
259 | tilde_expand : bool | |
260 | Whether any expansion was performed or not. |
|
260 | Whether any expansion was performed or not. | |
261 | tilde_val : str |
|
261 | tilde_val : str | |
262 | The value that ~ was replaced with. |
|
262 | The value that ~ was replaced with. | |
263 | """ |
|
263 | """ | |
264 | # Default values |
|
264 | # Default values | |
265 | tilde_expand = False |
|
265 | tilde_expand = False | |
266 | tilde_val = '' |
|
266 | tilde_val = '' | |
267 | newpath = path |
|
267 | newpath = path | |
268 |
|
268 | |||
269 | if path.startswith('~'): |
|
269 | if path.startswith('~'): | |
270 | tilde_expand = True |
|
270 | tilde_expand = True | |
271 | rest = len(path)-1 |
|
271 | rest = len(path)-1 | |
272 | newpath = os.path.expanduser(path) |
|
272 | newpath = os.path.expanduser(path) | |
273 | if rest: |
|
273 | if rest: | |
274 | tilde_val = newpath[:-rest] |
|
274 | tilde_val = newpath[:-rest] | |
275 | else: |
|
275 | else: | |
276 | tilde_val = newpath |
|
276 | tilde_val = newpath | |
277 |
|
277 | |||
278 | return newpath, tilde_expand, tilde_val |
|
278 | return newpath, tilde_expand, tilde_val | |
279 |
|
279 | |||
280 |
|
280 | |||
281 | def compress_user(path:str, tilde_expand:bool, tilde_val:str) -> str: |
|
281 | def compress_user(path:str, tilde_expand:bool, tilde_val:str) -> str: | |
282 | """Does the opposite of expand_user, with its outputs. |
|
282 | """Does the opposite of expand_user, with its outputs. | |
283 | """ |
|
283 | """ | |
284 | if tilde_expand: |
|
284 | if tilde_expand: | |
285 | return path.replace(tilde_val, '~') |
|
285 | return path.replace(tilde_val, '~') | |
286 | else: |
|
286 | else: | |
287 | return path |
|
287 | return path | |
288 |
|
288 | |||
289 |
|
289 | |||
290 | def completions_sorting_key(word): |
|
290 | def completions_sorting_key(word): | |
291 | """key for sorting completions |
|
291 | """key for sorting completions | |
292 |
|
292 | |||
293 | This does several things: |
|
293 | This does several things: | |
294 |
|
294 | |||
295 | - Demote any completions starting with underscores to the end |
|
295 | - Demote any completions starting with underscores to the end | |
296 | - Insert any %magic and %%cellmagic completions in the alphabetical order |
|
296 | - Insert any %magic and %%cellmagic completions in the alphabetical order | |
297 | by their name |
|
297 | by their name | |
298 | """ |
|
298 | """ | |
299 | prio1, prio2 = 0, 0 |
|
299 | prio1, prio2 = 0, 0 | |
300 |
|
300 | |||
301 | if word.startswith('__'): |
|
301 | if word.startswith('__'): | |
302 | prio1 = 2 |
|
302 | prio1 = 2 | |
303 | elif word.startswith('_'): |
|
303 | elif word.startswith('_'): | |
304 | prio1 = 1 |
|
304 | prio1 = 1 | |
305 |
|
305 | |||
306 | if word.endswith('='): |
|
306 | if word.endswith('='): | |
307 | prio1 = -1 |
|
307 | prio1 = -1 | |
308 |
|
308 | |||
309 | if word.startswith('%%'): |
|
309 | if word.startswith('%%'): | |
310 | # If there's another % in there, this is something else, so leave it alone |
|
310 | # If there's another % in there, this is something else, so leave it alone | |
311 | if not "%" in word[2:]: |
|
311 | if not "%" in word[2:]: | |
312 | word = word[2:] |
|
312 | word = word[2:] | |
313 | prio2 = 2 |
|
313 | prio2 = 2 | |
314 | elif word.startswith('%'): |
|
314 | elif word.startswith('%'): | |
315 | if not "%" in word[1:]: |
|
315 | if not "%" in word[1:]: | |
316 | word = word[1:] |
|
316 | word = word[1:] | |
317 | prio2 = 1 |
|
317 | prio2 = 1 | |
318 |
|
318 | |||
319 | return prio1, word, prio2 |
|
319 | return prio1, word, prio2 | |
320 |
|
320 | |||
321 |
|
321 | |||
322 | class _FakeJediCompletion: |
|
322 | class _FakeJediCompletion: | |
323 | """ |
|
323 | """ | |
324 | This is a workaround to communicate to the UI that Jedi has crashed and to |
|
324 | This is a workaround to communicate to the UI that Jedi has crashed and to | |
325 | report a bug. Will be used only id :any:`IPCompleter.debug` is set to true. |
|
325 | report a bug. Will be used only id :any:`IPCompleter.debug` is set to true. | |
326 |
|
326 | |||
327 | Added in IPython 6.0 so should likely be removed for 7.0 |
|
327 | Added in IPython 6.0 so should likely be removed for 7.0 | |
328 |
|
328 | |||
329 | """ |
|
329 | """ | |
330 |
|
330 | |||
331 | def __init__(self, name): |
|
331 | def __init__(self, name): | |
332 |
|
332 | |||
333 | self.name = name |
|
333 | self.name = name | |
334 | self.complete = name |
|
334 | self.complete = name | |
335 | self.type = 'crashed' |
|
335 | self.type = 'crashed' | |
336 | self.name_with_symbols = name |
|
336 | self.name_with_symbols = name | |
337 | self.signature = '' |
|
337 | self.signature = '' | |
338 | self._origin = 'fake' |
|
338 | self._origin = 'fake' | |
339 |
|
339 | |||
340 | def __repr__(self): |
|
340 | def __repr__(self): | |
341 | return '<Fake completion object jedi has crashed>' |
|
341 | return '<Fake completion object jedi has crashed>' | |
342 |
|
342 | |||
343 |
|
343 | |||
344 | class Completion: |
|
344 | class Completion: | |
345 | """ |
|
345 | """ | |
346 | Completion object used and return by IPython completers. |
|
346 | Completion object used and return by IPython completers. | |
347 |
|
347 | |||
348 | .. warning:: Unstable |
|
348 | .. warning:: Unstable | |
349 |
|
349 | |||
350 | This function is unstable, API may change without warning. |
|
350 | This function is unstable, API may change without warning. | |
351 | It will also raise unless use in proper context manager. |
|
351 | It will also raise unless use in proper context manager. | |
352 |
|
352 | |||
353 | This act as a middle ground :any:`Completion` object between the |
|
353 | This act as a middle ground :any:`Completion` object between the | |
354 | :any:`jedi.api.classes.Completion` object and the Prompt Toolkit completion |
|
354 | :any:`jedi.api.classes.Completion` object and the Prompt Toolkit completion | |
355 | object. While Jedi need a lot of information about evaluator and how the |
|
355 | object. While Jedi need a lot of information about evaluator and how the | |
356 | code should be ran/inspected, PromptToolkit (and other frontend) mostly |
|
356 | code should be ran/inspected, PromptToolkit (and other frontend) mostly | |
357 | need user facing information. |
|
357 | need user facing information. | |
358 |
|
358 | |||
359 | - Which range should be replaced replaced by what. |
|
359 | - Which range should be replaced replaced by what. | |
360 | - Some metadata (like completion type), or meta informations to displayed to |
|
360 | - Some metadata (like completion type), or meta informations to displayed to | |
361 | the use user. |
|
361 | the use user. | |
362 |
|
362 | |||
363 | For debugging purpose we can also store the origin of the completion (``jedi``, |
|
363 | For debugging purpose we can also store the origin of the completion (``jedi``, | |
364 | ``IPython.python_matches``, ``IPython.magics_matches``...). |
|
364 | ``IPython.python_matches``, ``IPython.magics_matches``...). | |
365 | """ |
|
365 | """ | |
366 |
|
366 | |||
367 | __slots__ = ['start', 'end', 'text', 'type', 'signature', '_origin'] |
|
367 | __slots__ = ['start', 'end', 'text', 'type', 'signature', '_origin'] | |
368 |
|
368 | |||
369 | def __init__(self, start: int, end: int, text: str, *, type: str=None, _origin='', signature='') -> None: |
|
369 | def __init__(self, start: int, end: int, text: str, *, type: str=None, _origin='', signature='') -> None: | |
370 | warnings.warn("``Completion`` is a provisional API (as of IPython 6.0). " |
|
370 | warnings.warn("``Completion`` is a provisional API (as of IPython 6.0). " | |
371 | "It may change without warnings. " |
|
371 | "It may change without warnings. " | |
372 | "Use in corresponding context manager.", |
|
372 | "Use in corresponding context manager.", | |
373 | category=ProvisionalCompleterWarning, stacklevel=2) |
|
373 | category=ProvisionalCompleterWarning, stacklevel=2) | |
374 |
|
374 | |||
375 | self.start = start |
|
375 | self.start = start | |
376 | self.end = end |
|
376 | self.end = end | |
377 | self.text = text |
|
377 | self.text = text | |
378 | self.type = type |
|
378 | self.type = type | |
379 | self.signature = signature |
|
379 | self.signature = signature | |
380 | self._origin = _origin |
|
380 | self._origin = _origin | |
381 |
|
381 | |||
382 | def __repr__(self): |
|
382 | def __repr__(self): | |
383 | return '<Completion start=%s end=%s text=%r type=%r, signature=%r,>' % \ |
|
383 | return '<Completion start=%s end=%s text=%r type=%r, signature=%r,>' % \ | |
384 | (self.start, self.end, self.text, self.type or '?', self.signature or '?') |
|
384 | (self.start, self.end, self.text, self.type or '?', self.signature or '?') | |
385 |
|
385 | |||
386 | def __eq__(self, other)->Bool: |
|
386 | def __eq__(self, other)->Bool: | |
387 | """ |
|
387 | """ | |
388 | Equality and hash do not hash the type (as some completer may not be |
|
388 | Equality and hash do not hash the type (as some completer may not be | |
389 | able to infer the type), but are use to (partially) de-duplicate |
|
389 | able to infer the type), but are use to (partially) de-duplicate | |
390 | completion. |
|
390 | completion. | |
391 |
|
391 | |||
392 | Completely de-duplicating completion is a bit tricker that just |
|
392 | Completely de-duplicating completion is a bit tricker that just | |
393 | comparing as it depends on surrounding text, which Completions are not |
|
393 | comparing as it depends on surrounding text, which Completions are not | |
394 | aware of. |
|
394 | aware of. | |
395 | """ |
|
395 | """ | |
396 | return self.start == other.start and \ |
|
396 | return self.start == other.start and \ | |
397 | self.end == other.end and \ |
|
397 | self.end == other.end and \ | |
398 | self.text == other.text |
|
398 | self.text == other.text | |
399 |
|
399 | |||
400 | def __hash__(self): |
|
400 | def __hash__(self): | |
401 | return hash((self.start, self.end, self.text)) |
|
401 | return hash((self.start, self.end, self.text)) | |
402 |
|
402 | |||
403 |
|
403 | |||
404 | _IC = Iterable[Completion] |
|
404 | _IC = Iterable[Completion] | |
405 |
|
405 | |||
406 |
|
406 | |||
407 | def _deduplicate_completions(text: str, completions: _IC)-> _IC: |
|
407 | def _deduplicate_completions(text: str, completions: _IC)-> _IC: | |
408 | """ |
|
408 | """ | |
409 | Deduplicate a set of completions. |
|
409 | Deduplicate a set of completions. | |
410 |
|
410 | |||
411 | .. warning:: Unstable |
|
411 | .. warning:: Unstable | |
412 |
|
412 | |||
413 | This function is unstable, API may change without warning. |
|
413 | This function is unstable, API may change without warning. | |
414 |
|
414 | |||
415 | Parameters |
|
415 | Parameters | |
416 | ---------- |
|
416 | ---------- | |
417 | text: str |
|
417 | text: str | |
418 | text that should be completed. |
|
418 | text that should be completed. | |
419 | completions: Iterator[Completion] |
|
419 | completions: Iterator[Completion] | |
420 | iterator over the completions to deduplicate |
|
420 | iterator over the completions to deduplicate | |
421 |
|
421 | |||
422 | Yields |
|
422 | Yields | |
423 | ------ |
|
423 | ------ | |
424 | `Completions` objects |
|
424 | `Completions` objects | |
425 |
|
425 | |||
426 |
|
426 | |||
427 | Completions coming from multiple sources, may be different but end up having |
|
427 | Completions coming from multiple sources, may be different but end up having | |
428 | the same effect when applied to ``text``. If this is the case, this will |
|
428 | the same effect when applied to ``text``. If this is the case, this will | |
429 | consider completions as equal and only emit the first encountered. |
|
429 | consider completions as equal and only emit the first encountered. | |
430 |
|
430 | |||
431 | Not folded in `completions()` yet for debugging purpose, and to detect when |
|
431 | Not folded in `completions()` yet for debugging purpose, and to detect when | |
432 | the IPython completer does return things that Jedi does not, but should be |
|
432 | the IPython completer does return things that Jedi does not, but should be | |
433 | at some point. |
|
433 | at some point. | |
434 | """ |
|
434 | """ | |
435 | completions = list(completions) |
|
435 | completions = list(completions) | |
436 | if not completions: |
|
436 | if not completions: | |
437 | return |
|
437 | return | |
438 |
|
438 | |||
439 | new_start = min(c.start for c in completions) |
|
439 | new_start = min(c.start for c in completions) | |
440 | new_end = max(c.end for c in completions) |
|
440 | new_end = max(c.end for c in completions) | |
441 |
|
441 | |||
442 | seen = set() |
|
442 | seen = set() | |
443 | for c in completions: |
|
443 | for c in completions: | |
444 | new_text = text[new_start:c.start] + c.text + text[c.end:new_end] |
|
444 | new_text = text[new_start:c.start] + c.text + text[c.end:new_end] | |
445 | if new_text not in seen: |
|
445 | if new_text not in seen: | |
446 | yield c |
|
446 | yield c | |
447 | seen.add(new_text) |
|
447 | seen.add(new_text) | |
448 |
|
448 | |||
449 |
|
449 | |||
450 | def rectify_completions(text: str, completions: _IC, *, _debug=False)->_IC: |
|
450 | def rectify_completions(text: str, completions: _IC, *, _debug=False)->_IC: | |
451 | """ |
|
451 | """ | |
452 | Rectify a set of completions to all have the same ``start`` and ``end`` |
|
452 | Rectify a set of completions to all have the same ``start`` and ``end`` | |
453 |
|
453 | |||
454 | .. warning:: Unstable |
|
454 | .. warning:: Unstable | |
455 |
|
455 | |||
456 | This function is unstable, API may change without warning. |
|
456 | This function is unstable, API may change without warning. | |
457 | It will also raise unless use in proper context manager. |
|
457 | It will also raise unless use in proper context manager. | |
458 |
|
458 | |||
459 | Parameters |
|
459 | Parameters | |
460 | ---------- |
|
460 | ---------- | |
461 | text: str |
|
461 | text: str | |
462 | text that should be completed. |
|
462 | text that should be completed. | |
463 | completions: Iterator[Completion] |
|
463 | completions: Iterator[Completion] | |
464 | iterator over the completions to rectify |
|
464 | iterator over the completions to rectify | |
465 |
|
465 | |||
466 |
|
466 | |||
467 | :any:`jedi.api.classes.Completion` s returned by Jedi may not have the same start and end, though |
|
467 | :any:`jedi.api.classes.Completion` s returned by Jedi may not have the same start and end, though | |
468 | the Jupyter Protocol requires them to behave like so. This will readjust |
|
468 | the Jupyter Protocol requires them to behave like so. This will readjust | |
469 | the completion to have the same ``start`` and ``end`` by padding both |
|
469 | the completion to have the same ``start`` and ``end`` by padding both | |
470 | extremities with surrounding text. |
|
470 | extremities with surrounding text. | |
471 |
|
471 | |||
472 | During stabilisation should support a ``_debug`` option to log which |
|
472 | During stabilisation should support a ``_debug`` option to log which | |
473 | completion are return by the IPython completer and not found in Jedi in |
|
473 | completion are return by the IPython completer and not found in Jedi in | |
474 | order to make upstream bug report. |
|
474 | order to make upstream bug report. | |
475 | """ |
|
475 | """ | |
476 | warnings.warn("`rectify_completions` is a provisional API (as of IPython 6.0). " |
|
476 | warnings.warn("`rectify_completions` is a provisional API (as of IPython 6.0). " | |
477 | "It may change without warnings. " |
|
477 | "It may change without warnings. " | |
478 | "Use in corresponding context manager.", |
|
478 | "Use in corresponding context manager.", | |
479 | category=ProvisionalCompleterWarning, stacklevel=2) |
|
479 | category=ProvisionalCompleterWarning, stacklevel=2) | |
480 |
|
480 | |||
481 | completions = list(completions) |
|
481 | completions = list(completions) | |
482 | if not completions: |
|
482 | if not completions: | |
483 | return |
|
483 | return | |
484 | starts = (c.start for c in completions) |
|
484 | starts = (c.start for c in completions) | |
485 | ends = (c.end for c in completions) |
|
485 | ends = (c.end for c in completions) | |
486 |
|
486 | |||
487 | new_start = min(starts) |
|
487 | new_start = min(starts) | |
488 | new_end = max(ends) |
|
488 | new_end = max(ends) | |
489 |
|
489 | |||
490 | seen_jedi = set() |
|
490 | seen_jedi = set() | |
491 | seen_python_matches = set() |
|
491 | seen_python_matches = set() | |
492 | for c in completions: |
|
492 | for c in completions: | |
493 | new_text = text[new_start:c.start] + c.text + text[c.end:new_end] |
|
493 | new_text = text[new_start:c.start] + c.text + text[c.end:new_end] | |
494 | if c._origin == 'jedi': |
|
494 | if c._origin == 'jedi': | |
495 | seen_jedi.add(new_text) |
|
495 | seen_jedi.add(new_text) | |
496 | elif c._origin == 'IPCompleter.python_matches': |
|
496 | elif c._origin == 'IPCompleter.python_matches': | |
497 | seen_python_matches.add(new_text) |
|
497 | seen_python_matches.add(new_text) | |
498 | yield Completion(new_start, new_end, new_text, type=c.type, _origin=c._origin, signature=c.signature) |
|
498 | yield Completion(new_start, new_end, new_text, type=c.type, _origin=c._origin, signature=c.signature) | |
499 | diff = seen_python_matches.difference(seen_jedi) |
|
499 | diff = seen_python_matches.difference(seen_jedi) | |
500 | if diff and _debug: |
|
500 | if diff and _debug: | |
501 | print('IPython.python matches have extras:', diff) |
|
501 | print('IPython.python matches have extras:', diff) | |
502 |
|
502 | |||
503 |
|
503 | |||
504 | if sys.platform == 'win32': |
|
504 | if sys.platform == 'win32': | |
505 | DELIMS = ' \t\n`!@#$^&*()=+[{]}|;\'",<>?' |
|
505 | DELIMS = ' \t\n`!@#$^&*()=+[{]}|;\'",<>?' | |
506 | else: |
|
506 | else: | |
507 | DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?' |
|
507 | DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?' | |
508 |
|
508 | |||
509 | GREEDY_DELIMS = ' =\r\n' |
|
509 | GREEDY_DELIMS = ' =\r\n' | |
510 |
|
510 | |||
511 |
|
511 | |||
512 | class CompletionSplitter(object): |
|
512 | class CompletionSplitter(object): | |
513 | """An object to split an input line in a manner similar to readline. |
|
513 | """An object to split an input line in a manner similar to readline. | |
514 |
|
514 | |||
515 | By having our own implementation, we can expose readline-like completion in |
|
515 | By having our own implementation, we can expose readline-like completion in | |
516 | a uniform manner to all frontends. This object only needs to be given the |
|
516 | a uniform manner to all frontends. This object only needs to be given the | |
517 | line of text to be split and the cursor position on said line, and it |
|
517 | line of text to be split and the cursor position on said line, and it | |
518 | returns the 'word' to be completed on at the cursor after splitting the |
|
518 | returns the 'word' to be completed on at the cursor after splitting the | |
519 | entire line. |
|
519 | entire line. | |
520 |
|
520 | |||
521 | What characters are used as splitting delimiters can be controlled by |
|
521 | What characters are used as splitting delimiters can be controlled by | |
522 | setting the ``delims`` attribute (this is a property that internally |
|
522 | setting the ``delims`` attribute (this is a property that internally | |
523 | automatically builds the necessary regular expression)""" |
|
523 | automatically builds the necessary regular expression)""" | |
524 |
|
524 | |||
525 | # Private interface |
|
525 | # Private interface | |
526 |
|
526 | |||
527 | # A string of delimiter characters. The default value makes sense for |
|
527 | # A string of delimiter characters. The default value makes sense for | |
528 | # IPython's most typical usage patterns. |
|
528 | # IPython's most typical usage patterns. | |
529 | _delims = DELIMS |
|
529 | _delims = DELIMS | |
530 |
|
530 | |||
531 | # The expression (a normal string) to be compiled into a regular expression |
|
531 | # The expression (a normal string) to be compiled into a regular expression | |
532 | # for actual splitting. We store it as an attribute mostly for ease of |
|
532 | # for actual splitting. We store it as an attribute mostly for ease of | |
533 | # debugging, since this type of code can be so tricky to debug. |
|
533 | # debugging, since this type of code can be so tricky to debug. | |
534 | _delim_expr = None |
|
534 | _delim_expr = None | |
535 |
|
535 | |||
536 | # The regular expression that does the actual splitting |
|
536 | # The regular expression that does the actual splitting | |
537 | _delim_re = None |
|
537 | _delim_re = None | |
538 |
|
538 | |||
539 | def __init__(self, delims=None): |
|
539 | def __init__(self, delims=None): | |
540 | delims = CompletionSplitter._delims if delims is None else delims |
|
540 | delims = CompletionSplitter._delims if delims is None else delims | |
541 | self.delims = delims |
|
541 | self.delims = delims | |
542 |
|
542 | |||
543 | @property |
|
543 | @property | |
544 | def delims(self): |
|
544 | def delims(self): | |
545 | """Return the string of delimiter characters.""" |
|
545 | """Return the string of delimiter characters.""" | |
546 | return self._delims |
|
546 | return self._delims | |
547 |
|
547 | |||
548 | @delims.setter |
|
548 | @delims.setter | |
549 | def delims(self, delims): |
|
549 | def delims(self, delims): | |
550 | """Set the delimiters for line splitting.""" |
|
550 | """Set the delimiters for line splitting.""" | |
551 | expr = '[' + ''.join('\\'+ c for c in delims) + ']' |
|
551 | expr = '[' + ''.join('\\'+ c for c in delims) + ']' | |
552 | self._delim_re = re.compile(expr) |
|
552 | self._delim_re = re.compile(expr) | |
553 | self._delims = delims |
|
553 | self._delims = delims | |
554 | self._delim_expr = expr |
|
554 | self._delim_expr = expr | |
555 |
|
555 | |||
556 | def split_line(self, line, cursor_pos=None): |
|
556 | def split_line(self, line, cursor_pos=None): | |
557 | """Split a line of text with a cursor at the given position. |
|
557 | """Split a line of text with a cursor at the given position. | |
558 | """ |
|
558 | """ | |
559 | l = line if cursor_pos is None else line[:cursor_pos] |
|
559 | l = line if cursor_pos is None else line[:cursor_pos] | |
560 | return self._delim_re.split(l)[-1] |
|
560 | return self._delim_re.split(l)[-1] | |
561 |
|
561 | |||
562 |
|
562 | |||
563 |
|
563 | |||
564 | class Completer(Configurable): |
|
564 | class Completer(Configurable): | |
565 |
|
565 | |||
566 | greedy = Bool(False, |
|
566 | greedy = Bool(False, | |
567 | help="""Activate greedy completion |
|
567 | help="""Activate greedy completion | |
568 | PENDING DEPRECTION. this is now mostly taken care of with Jedi. |
|
568 | PENDING DEPRECTION. this is now mostly taken care of with Jedi. | |
569 |
|
569 | |||
570 | This will enable completion on elements of lists, results of function calls, etc., |
|
570 | This will enable completion on elements of lists, results of function calls, etc., | |
571 | but can be unsafe because the code is actually evaluated on TAB. |
|
571 | but can be unsafe because the code is actually evaluated on TAB. | |
572 | """ |
|
572 | """ | |
573 | ).tag(config=True) |
|
573 | ).tag(config=True) | |
574 |
|
574 | |||
575 | use_jedi = Bool(default_value=JEDI_INSTALLED, |
|
575 | use_jedi = Bool(default_value=JEDI_INSTALLED, | |
576 | help="Experimental: Use Jedi to generate autocompletions. " |
|
576 | help="Experimental: Use Jedi to generate autocompletions. " | |
577 | "Default to True if jedi is installed").tag(config=True) |
|
577 | "Default to True if jedi is installed").tag(config=True) | |
578 |
|
578 | |||
579 | jedi_compute_type_timeout = Int(default_value=400, |
|
579 | jedi_compute_type_timeout = Int(default_value=400, | |
580 | help="""Experimental: restrict time (in milliseconds) during which Jedi can compute types. |
|
580 | help="""Experimental: restrict time (in milliseconds) during which Jedi can compute types. | |
581 | Set to 0 to stop computing types. Non-zero value lower than 100ms may hurt |
|
581 | Set to 0 to stop computing types. Non-zero value lower than 100ms may hurt | |
582 | performance by preventing jedi to build its cache. |
|
582 | performance by preventing jedi to build its cache. | |
583 | """).tag(config=True) |
|
583 | """).tag(config=True) | |
584 |
|
584 | |||
585 | debug = Bool(default_value=False, |
|
585 | debug = Bool(default_value=False, | |
586 | help='Enable debug for the Completer. Mostly print extra ' |
|
586 | help='Enable debug for the Completer. Mostly print extra ' | |
587 | 'information for experimental jedi integration.')\ |
|
587 | 'information for experimental jedi integration.')\ | |
588 | .tag(config=True) |
|
588 | .tag(config=True) | |
589 |
|
589 | |||
590 | backslash_combining_completions = Bool(True, |
|
590 | backslash_combining_completions = Bool(True, | |
591 | help="Enable unicode completions, e.g. \\alpha<tab> . " |
|
591 | help="Enable unicode completions, e.g. \\alpha<tab> . " | |
592 | "Includes completion of latex commands, unicode names, and expanding " |
|
592 | "Includes completion of latex commands, unicode names, and expanding " | |
593 | "unicode characters back to latex commands.").tag(config=True) |
|
593 | "unicode characters back to latex commands.").tag(config=True) | |
594 |
|
594 | |||
595 |
|
595 | |||
596 |
|
596 | |||
597 | def __init__(self, namespace=None, global_namespace=None, **kwargs): |
|
597 | def __init__(self, namespace=None, global_namespace=None, **kwargs): | |
598 | """Create a new completer for the command line. |
|
598 | """Create a new completer for the command line. | |
599 |
|
599 | |||
600 | Completer(namespace=ns, global_namespace=ns2) -> completer instance. |
|
600 | Completer(namespace=ns, global_namespace=ns2) -> completer instance. | |
601 |
|
601 | |||
602 | If unspecified, the default namespace where completions are performed |
|
602 | If unspecified, the default namespace where completions are performed | |
603 | is __main__ (technically, __main__.__dict__). Namespaces should be |
|
603 | is __main__ (technically, __main__.__dict__). Namespaces should be | |
604 | given as dictionaries. |
|
604 | given as dictionaries. | |
605 |
|
605 | |||
606 | An optional second namespace can be given. This allows the completer |
|
606 | An optional second namespace can be given. This allows the completer | |
607 | to handle cases where both the local and global scopes need to be |
|
607 | to handle cases where both the local and global scopes need to be | |
608 | distinguished. |
|
608 | distinguished. | |
609 | """ |
|
609 | """ | |
610 |
|
610 | |||
611 | # Don't bind to namespace quite yet, but flag whether the user wants a |
|
611 | # Don't bind to namespace quite yet, but flag whether the user wants a | |
612 | # specific namespace or to use __main__.__dict__. This will allow us |
|
612 | # specific namespace or to use __main__.__dict__. This will allow us | |
613 | # to bind to __main__.__dict__ at completion time, not now. |
|
613 | # to bind to __main__.__dict__ at completion time, not now. | |
614 | if namespace is None: |
|
614 | if namespace is None: | |
615 | self.use_main_ns = True |
|
615 | self.use_main_ns = True | |
616 | else: |
|
616 | else: | |
617 | self.use_main_ns = False |
|
617 | self.use_main_ns = False | |
618 | self.namespace = namespace |
|
618 | self.namespace = namespace | |
619 |
|
619 | |||
620 | # The global namespace, if given, can be bound directly |
|
620 | # The global namespace, if given, can be bound directly | |
621 | if global_namespace is None: |
|
621 | if global_namespace is None: | |
622 | self.global_namespace = {} |
|
622 | self.global_namespace = {} | |
623 | else: |
|
623 | else: | |
624 | self.global_namespace = global_namespace |
|
624 | self.global_namespace = global_namespace | |
625 |
|
625 | |||
626 | super(Completer, self).__init__(**kwargs) |
|
626 | super(Completer, self).__init__(**kwargs) | |
627 |
|
627 | |||
628 | def complete(self, text, state): |
|
628 | def complete(self, text, state): | |
629 | """Return the next possible completion for 'text'. |
|
629 | """Return the next possible completion for 'text'. | |
630 |
|
630 | |||
631 | This is called successively with state == 0, 1, 2, ... until it |
|
631 | This is called successively with state == 0, 1, 2, ... until it | |
632 | returns None. The completion should begin with 'text'. |
|
632 | returns None. The completion should begin with 'text'. | |
633 |
|
633 | |||
634 | """ |
|
634 | """ | |
635 | if self.use_main_ns: |
|
635 | if self.use_main_ns: | |
636 | self.namespace = __main__.__dict__ |
|
636 | self.namespace = __main__.__dict__ | |
637 |
|
637 | |||
638 | if state == 0: |
|
638 | if state == 0: | |
639 | if "." in text: |
|
639 | if "." in text: | |
640 | self.matches = self.attr_matches(text) |
|
640 | self.matches = self.attr_matches(text) | |
641 | else: |
|
641 | else: | |
642 | self.matches = self.global_matches(text) |
|
642 | self.matches = self.global_matches(text) | |
643 | try: |
|
643 | try: | |
644 | return self.matches[state] |
|
644 | return self.matches[state] | |
645 | except IndexError: |
|
645 | except IndexError: | |
646 | return None |
|
646 | return None | |
647 |
|
647 | |||
648 | def global_matches(self, text): |
|
648 | def global_matches(self, text): | |
649 | """Compute matches when text is a simple name. |
|
649 | """Compute matches when text is a simple name. | |
650 |
|
650 | |||
651 | Return a list of all keywords, built-in functions and names currently |
|
651 | Return a list of all keywords, built-in functions and names currently | |
652 | defined in self.namespace or self.global_namespace that match. |
|
652 | defined in self.namespace or self.global_namespace that match. | |
653 |
|
653 | |||
654 | """ |
|
654 | """ | |
655 | matches = [] |
|
655 | matches = [] | |
656 | match_append = matches.append |
|
656 | match_append = matches.append | |
657 | n = len(text) |
|
657 | n = len(text) | |
658 | for lst in [keyword.kwlist, |
|
658 | for lst in [keyword.kwlist, | |
659 | builtin_mod.__dict__.keys(), |
|
659 | builtin_mod.__dict__.keys(), | |
660 | self.namespace.keys(), |
|
660 | self.namespace.keys(), | |
661 | self.global_namespace.keys()]: |
|
661 | self.global_namespace.keys()]: | |
662 | for word in lst: |
|
662 | for word in lst: | |
663 | if word[:n] == text and word != "__builtins__": |
|
663 | if word[:n] == text and word != "__builtins__": | |
664 | match_append(word) |
|
664 | match_append(word) | |
665 |
|
665 | |||
666 | snake_case_re = re.compile(r"[^_]+(_[^_]+)+?\Z") |
|
666 | snake_case_re = re.compile(r"[^_]+(_[^_]+)+?\Z") | |
667 | for lst in [self.namespace.keys(), |
|
667 | for lst in [self.namespace.keys(), | |
668 | self.global_namespace.keys()]: |
|
668 | self.global_namespace.keys()]: | |
669 | shortened = {"_".join([sub[0] for sub in word.split('_')]) : word |
|
669 | shortened = {"_".join([sub[0] for sub in word.split('_')]) : word | |
670 | for word in lst if snake_case_re.match(word)} |
|
670 | for word in lst if snake_case_re.match(word)} | |
671 | for word in shortened.keys(): |
|
671 | for word in shortened.keys(): | |
672 | if word[:n] == text and word != "__builtins__": |
|
672 | if word[:n] == text and word != "__builtins__": | |
673 | match_append(shortened[word]) |
|
673 | match_append(shortened[word]) | |
674 | return matches |
|
674 | return matches | |
675 |
|
675 | |||
676 | def attr_matches(self, text): |
|
676 | def attr_matches(self, text): | |
677 | """Compute matches when text contains a dot. |
|
677 | """Compute matches when text contains a dot. | |
678 |
|
678 | |||
679 | Assuming the text is of the form NAME.NAME....[NAME], and is |
|
679 | Assuming the text is of the form NAME.NAME....[NAME], and is | |
680 | evaluatable in self.namespace or self.global_namespace, it will be |
|
680 | evaluatable in self.namespace or self.global_namespace, it will be | |
681 | evaluated and its attributes (as revealed by dir()) are used as |
|
681 | evaluated and its attributes (as revealed by dir()) are used as | |
682 | possible completions. (For class instances, class members are are |
|
682 | possible completions. (For class instances, class members are are | |
683 | also considered.) |
|
683 | also considered.) | |
684 |
|
684 | |||
685 | WARNING: this can still invoke arbitrary C code, if an object |
|
685 | WARNING: this can still invoke arbitrary C code, if an object | |
686 | with a __getattr__ hook is evaluated. |
|
686 | with a __getattr__ hook is evaluated. | |
687 |
|
687 | |||
688 | """ |
|
688 | """ | |
689 |
|
689 | |||
690 | # Another option, seems to work great. Catches things like ''.<tab> |
|
690 | # Another option, seems to work great. Catches things like ''.<tab> | |
691 | m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text) |
|
691 | m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text) | |
692 |
|
692 | |||
693 | if m: |
|
693 | if m: | |
694 | expr, attr = m.group(1, 3) |
|
694 | expr, attr = m.group(1, 3) | |
695 | elif self.greedy: |
|
695 | elif self.greedy: | |
696 | m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer) |
|
696 | m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer) | |
697 | if not m2: |
|
697 | if not m2: | |
698 | return [] |
|
698 | return [] | |
699 | expr, attr = m2.group(1,2) |
|
699 | expr, attr = m2.group(1,2) | |
700 | else: |
|
700 | else: | |
701 | return [] |
|
701 | return [] | |
702 |
|
702 | |||
703 | try: |
|
703 | try: | |
704 | obj = eval(expr, self.namespace) |
|
704 | obj = eval(expr, self.namespace) | |
705 | except: |
|
705 | except: | |
706 | try: |
|
706 | try: | |
707 | obj = eval(expr, self.global_namespace) |
|
707 | obj = eval(expr, self.global_namespace) | |
708 | except: |
|
708 | except: | |
709 | return [] |
|
709 | return [] | |
710 |
|
710 | |||
711 | if self.limit_to__all__ and hasattr(obj, '__all__'): |
|
711 | if self.limit_to__all__ and hasattr(obj, '__all__'): | |
712 | words = get__all__entries(obj) |
|
712 | words = get__all__entries(obj) | |
713 | else: |
|
713 | else: | |
714 | words = dir2(obj) |
|
714 | words = dir2(obj) | |
715 |
|
715 | |||
716 | try: |
|
716 | try: | |
717 | words = generics.complete_object(obj, words) |
|
717 | words = generics.complete_object(obj, words) | |
718 | except TryNext: |
|
718 | except TryNext: | |
719 | pass |
|
719 | pass | |
720 | except AssertionError: |
|
720 | except AssertionError: | |
721 | raise |
|
721 | raise | |
722 | except Exception: |
|
722 | except Exception: | |
723 | # Silence errors from completion function |
|
723 | # Silence errors from completion function | |
724 | #raise # dbg |
|
724 | #raise # dbg | |
725 | pass |
|
725 | pass | |
726 | # Build match list to return |
|
726 | # Build match list to return | |
727 | n = len(attr) |
|
727 | n = len(attr) | |
728 | return [u"%s.%s" % (expr, w) for w in words if w[:n] == attr ] |
|
728 | return [u"%s.%s" % (expr, w) for w in words if w[:n] == attr ] | |
729 |
|
729 | |||
730 |
|
730 | |||
731 | def get__all__entries(obj): |
|
731 | def get__all__entries(obj): | |
732 | """returns the strings in the __all__ attribute""" |
|
732 | """returns the strings in the __all__ attribute""" | |
733 | try: |
|
733 | try: | |
734 | words = getattr(obj, '__all__') |
|
734 | words = getattr(obj, '__all__') | |
735 | except: |
|
735 | except: | |
736 | return [] |
|
736 | return [] | |
737 |
|
737 | |||
738 | return [w for w in words if isinstance(w, str)] |
|
738 | return [w for w in words if isinstance(w, str)] | |
739 |
|
739 | |||
740 |
|
740 | |||
741 | def match_dict_keys(keys: List[str], prefix: str, delims: str): |
|
741 | def match_dict_keys(keys: List[str], prefix: str, delims: str): | |
742 | """Used by dict_key_matches, matching the prefix to a list of keys |
|
742 | """Used by dict_key_matches, matching the prefix to a list of keys | |
743 |
|
743 | |||
744 | Parameters |
|
744 | Parameters | |
745 | ========== |
|
745 | ========== | |
746 | keys: |
|
746 | keys: | |
747 | list of keys in dictionary currently being completed. |
|
747 | list of keys in dictionary currently being completed. | |
748 | prefix: |
|
748 | prefix: | |
749 | Part of the text already typed by the user. e.g. `mydict[b'fo` |
|
749 | Part of the text already typed by the user. e.g. `mydict[b'fo` | |
750 | delims: |
|
750 | delims: | |
751 | String of delimiters to consider when finding the current key. |
|
751 | String of delimiters to consider when finding the current key. | |
752 |
|
752 | |||
753 | Returns |
|
753 | Returns | |
754 | ======= |
|
754 | ======= | |
755 |
|
755 | |||
756 | A tuple of three elements: ``quote``, ``token_start``, ``matched``, with |
|
756 | A tuple of three elements: ``quote``, ``token_start``, ``matched``, with | |
757 | ``quote`` being the quote that need to be used to close current string. |
|
757 | ``quote`` being the quote that need to be used to close current string. | |
758 | ``token_start`` the position where the replacement should start occurring, |
|
758 | ``token_start`` the position where the replacement should start occurring, | |
759 | ``matches`` a list of replacement/completion |
|
759 | ``matches`` a list of replacement/completion | |
760 |
|
760 | |||
761 | """ |
|
761 | """ | |
762 | if not prefix: |
|
762 | if not prefix: | |
763 | return None, 0, [repr(k) for k in keys |
|
763 | return None, 0, [repr(k) for k in keys | |
764 | if isinstance(k, (str, bytes))] |
|
764 | if isinstance(k, (str, bytes))] | |
765 | quote_match = re.search('["\']', prefix) |
|
765 | quote_match = re.search('["\']', prefix) | |
766 | quote = quote_match.group() |
|
766 | quote = quote_match.group() | |
767 | try: |
|
767 | try: | |
768 | prefix_str = eval(prefix + quote, {}) |
|
768 | prefix_str = eval(prefix + quote, {}) | |
769 | except Exception: |
|
769 | except Exception: | |
770 | return None, 0, [] |
|
770 | return None, 0, [] | |
771 |
|
771 | |||
772 | pattern = '[^' + ''.join('\\' + c for c in delims) + ']*$' |
|
772 | pattern = '[^' + ''.join('\\' + c for c in delims) + ']*$' | |
773 | token_match = re.search(pattern, prefix, re.UNICODE) |
|
773 | token_match = re.search(pattern, prefix, re.UNICODE) | |
774 | token_start = token_match.start() |
|
774 | token_start = token_match.start() | |
775 | token_prefix = token_match.group() |
|
775 | token_prefix = token_match.group() | |
776 |
|
776 | |||
777 | matched = [] |
|
777 | matched = [] | |
778 | for key in keys: |
|
778 | for key in keys: | |
779 | try: |
|
779 | try: | |
780 | if not key.startswith(prefix_str): |
|
780 | if not key.startswith(prefix_str): | |
781 | continue |
|
781 | continue | |
782 | except (AttributeError, TypeError, UnicodeError): |
|
782 | except (AttributeError, TypeError, UnicodeError): | |
783 | # Python 3+ TypeError on b'a'.startswith('a') or vice-versa |
|
783 | # Python 3+ TypeError on b'a'.startswith('a') or vice-versa | |
784 | continue |
|
784 | continue | |
785 |
|
785 | |||
786 | # reformat remainder of key to begin with prefix |
|
786 | # reformat remainder of key to begin with prefix | |
787 | rem = key[len(prefix_str):] |
|
787 | rem = key[len(prefix_str):] | |
788 | # force repr wrapped in ' |
|
788 | # force repr wrapped in ' | |
789 | rem_repr = repr(rem + '"') if isinstance(rem, str) else repr(rem + b'"') |
|
789 | rem_repr = repr(rem + '"') if isinstance(rem, str) else repr(rem + b'"') | |
790 | if rem_repr.startswith('u') and prefix[0] not in 'uU': |
|
790 | if rem_repr.startswith('u') and prefix[0] not in 'uU': | |
791 | # Found key is unicode, but prefix is Py2 string. |
|
791 | # Found key is unicode, but prefix is Py2 string. | |
792 | # Therefore attempt to interpret key as string. |
|
792 | # Therefore attempt to interpret key as string. | |
793 | try: |
|
793 | try: | |
794 | rem_repr = repr(rem.encode('ascii') + '"') |
|
794 | rem_repr = repr(rem.encode('ascii') + '"') | |
795 | except UnicodeEncodeError: |
|
795 | except UnicodeEncodeError: | |
796 | continue |
|
796 | continue | |
797 |
|
797 | |||
798 | rem_repr = rem_repr[1 + rem_repr.index("'"):-2] |
|
798 | rem_repr = rem_repr[1 + rem_repr.index("'"):-2] | |
799 | if quote == '"': |
|
799 | if quote == '"': | |
800 | # The entered prefix is quoted with ", |
|
800 | # The entered prefix is quoted with ", | |
801 | # but the match is quoted with '. |
|
801 | # but the match is quoted with '. | |
802 | # A contained " hence needs escaping for comparison: |
|
802 | # A contained " hence needs escaping for comparison: | |
803 | rem_repr = rem_repr.replace('"', '\\"') |
|
803 | rem_repr = rem_repr.replace('"', '\\"') | |
804 |
|
804 | |||
805 | # then reinsert prefix from start of token |
|
805 | # then reinsert prefix from start of token | |
806 | matched.append('%s%s' % (token_prefix, rem_repr)) |
|
806 | matched.append('%s%s' % (token_prefix, rem_repr)) | |
807 | return quote, token_start, matched |
|
807 | return quote, token_start, matched | |
808 |
|
808 | |||
809 |
|
809 | |||
810 | def cursor_to_position(text:str, line:int, column:int)->int: |
|
810 | def cursor_to_position(text:str, line:int, column:int)->int: | |
811 | """ |
|
811 | """ | |
812 |
|
812 | |||
813 | Convert the (line,column) position of the cursor in text to an offset in a |
|
813 | Convert the (line,column) position of the cursor in text to an offset in a | |
814 | string. |
|
814 | string. | |
815 |
|
815 | |||
816 | Parameters |
|
816 | Parameters | |
817 | ---------- |
|
817 | ---------- | |
818 |
|
818 | |||
819 | text : str |
|
819 | text : str | |
820 | The text in which to calculate the cursor offset |
|
820 | The text in which to calculate the cursor offset | |
821 | line : int |
|
821 | line : int | |
822 | Line of the cursor; 0-indexed |
|
822 | Line of the cursor; 0-indexed | |
823 | column : int |
|
823 | column : int | |
824 | Column of the cursor 0-indexed |
|
824 | Column of the cursor 0-indexed | |
825 |
|
825 | |||
826 | Return |
|
826 | Return | |
827 | ------ |
|
827 | ------ | |
828 | Position of the cursor in ``text``, 0-indexed. |
|
828 | Position of the cursor in ``text``, 0-indexed. | |
829 |
|
829 | |||
830 | See Also |
|
830 | See Also | |
831 | -------- |
|
831 | -------- | |
832 | position_to_cursor: reciprocal of this function |
|
832 | position_to_cursor: reciprocal of this function | |
833 |
|
833 | |||
834 | """ |
|
834 | """ | |
835 | lines = text.split('\n') |
|
835 | lines = text.split('\n') | |
836 | assert line <= len(lines), '{} <= {}'.format(str(line), str(len(lines))) |
|
836 | assert line <= len(lines), '{} <= {}'.format(str(line), str(len(lines))) | |
837 |
|
837 | |||
838 | return sum(len(l) + 1 for l in lines[:line]) + column |
|
838 | return sum(len(l) + 1 for l in lines[:line]) + column | |
839 |
|
839 | |||
840 | def position_to_cursor(text:str, offset:int)->Tuple[int, int]: |
|
840 | def position_to_cursor(text:str, offset:int)->Tuple[int, int]: | |
841 | """ |
|
841 | """ | |
842 | Convert the position of the cursor in text (0 indexed) to a line |
|
842 | Convert the position of the cursor in text (0 indexed) to a line | |
843 | number(0-indexed) and a column number (0-indexed) pair |
|
843 | number(0-indexed) and a column number (0-indexed) pair | |
844 |
|
844 | |||
845 | Position should be a valid position in ``text``. |
|
845 | Position should be a valid position in ``text``. | |
846 |
|
846 | |||
847 | Parameters |
|
847 | Parameters | |
848 | ---------- |
|
848 | ---------- | |
849 |
|
849 | |||
850 | text : str |
|
850 | text : str | |
851 | The text in which to calculate the cursor offset |
|
851 | The text in which to calculate the cursor offset | |
852 | offset : int |
|
852 | offset : int | |
853 | Position of the cursor in ``text``, 0-indexed. |
|
853 | Position of the cursor in ``text``, 0-indexed. | |
854 |
|
854 | |||
855 | Return |
|
855 | Return | |
856 | ------ |
|
856 | ------ | |
857 | (line, column) : (int, int) |
|
857 | (line, column) : (int, int) | |
858 | Line of the cursor; 0-indexed, column of the cursor 0-indexed |
|
858 | Line of the cursor; 0-indexed, column of the cursor 0-indexed | |
859 |
|
859 | |||
860 |
|
860 | |||
861 | See Also |
|
861 | See Also | |
862 | -------- |
|
862 | -------- | |
863 | cursor_to_position : reciprocal of this function |
|
863 | cursor_to_position : reciprocal of this function | |
864 |
|
864 | |||
865 |
|
865 | |||
866 | """ |
|
866 | """ | |
867 |
|
867 | |||
868 | assert 0 < offset <= len(text) , "0 < %s <= %s" % (offset , len(text)) |
|
868 | assert 0 < offset <= len(text) , "0 < %s <= %s" % (offset , len(text)) | |
869 |
|
869 | |||
870 | before = text[:offset] |
|
870 | before = text[:offset] | |
871 | blines = before.split('\n') # ! splitnes trim trailing \n |
|
871 | blines = before.split('\n') # ! splitnes trim trailing \n | |
872 | line = before.count('\n') |
|
872 | line = before.count('\n') | |
873 | col = len(blines[-1]) |
|
873 | col = len(blines[-1]) | |
874 | return line, col |
|
874 | return line, col | |
875 |
|
875 | |||
876 |
|
876 | |||
877 | def _safe_isinstance(obj, module, class_name): |
|
877 | def _safe_isinstance(obj, module, class_name): | |
878 | """Checks if obj is an instance of module.class_name if loaded |
|
878 | """Checks if obj is an instance of module.class_name if loaded | |
879 | """ |
|
879 | """ | |
880 | return (module in sys.modules and |
|
880 | return (module in sys.modules and | |
881 | isinstance(obj, getattr(import_module(module), class_name))) |
|
881 | isinstance(obj, getattr(import_module(module), class_name))) | |
882 |
|
882 | |||
883 |
|
883 | |||
884 | def back_unicode_name_matches(text): |
|
884 | def back_unicode_name_matches(text): | |
885 | u"""Match unicode characters back to unicode name |
|
885 | u"""Match unicode characters back to unicode name | |
886 |
|
886 | |||
887 | This does ``β`` -> ``\\snowman`` |
|
887 | This does ``β`` -> ``\\snowman`` | |
888 |
|
888 | |||
889 | Note that snowman is not a valid python3 combining character but will be expanded. |
|
889 | Note that snowman is not a valid python3 combining character but will be expanded. | |
890 | Though it will not recombine back to the snowman character by the completion machinery. |
|
890 | Though it will not recombine back to the snowman character by the completion machinery. | |
891 |
|
891 | |||
892 | This will not either back-complete standard sequences like \\n, \\b ... |
|
892 | This will not either back-complete standard sequences like \\n, \\b ... | |
893 |
|
893 | |||
894 | Used on Python 3 only. |
|
894 | Used on Python 3 only. | |
895 | """ |
|
895 | """ | |
896 | if len(text)<2: |
|
896 | if len(text)<2: | |
897 | return u'', () |
|
897 | return u'', () | |
898 | maybe_slash = text[-2] |
|
898 | maybe_slash = text[-2] | |
899 | if maybe_slash != '\\': |
|
899 | if maybe_slash != '\\': | |
900 | return u'', () |
|
900 | return u'', () | |
901 |
|
901 | |||
902 | char = text[-1] |
|
902 | char = text[-1] | |
903 | # no expand on quote for completion in strings. |
|
903 | # no expand on quote for completion in strings. | |
904 | # nor backcomplete standard ascii keys |
|
904 | # nor backcomplete standard ascii keys | |
905 | if char in string.ascii_letters or char in ['"',"'"]: |
|
905 | if char in string.ascii_letters or char in ['"',"'"]: | |
906 | return u'', () |
|
906 | return u'', () | |
907 | try : |
|
907 | try : | |
908 | unic = unicodedata.name(char) |
|
908 | unic = unicodedata.name(char) | |
909 | return '\\'+char,['\\'+unic] |
|
909 | return '\\'+char,['\\'+unic] | |
910 | except KeyError: |
|
910 | except KeyError: | |
911 | pass |
|
911 | pass | |
912 | return u'', () |
|
912 | return u'', () | |
913 |
|
913 | |||
914 | def back_latex_name_matches(text:str): |
|
914 | def back_latex_name_matches(text:str): | |
915 | """Match latex characters back to unicode name |
|
915 | """Match latex characters back to unicode name | |
916 |
|
916 | |||
917 | This does ``\\β΅`` -> ``\\aleph`` |
|
917 | This does ``\\β΅`` -> ``\\aleph`` | |
918 |
|
918 | |||
919 | Used on Python 3 only. |
|
919 | Used on Python 3 only. | |
920 | """ |
|
920 | """ | |
921 | if len(text)<2: |
|
921 | if len(text)<2: | |
922 | return u'', () |
|
922 | return u'', () | |
923 | maybe_slash = text[-2] |
|
923 | maybe_slash = text[-2] | |
924 | if maybe_slash != '\\': |
|
924 | if maybe_slash != '\\': | |
925 | return u'', () |
|
925 | return u'', () | |
926 |
|
926 | |||
927 |
|
927 | |||
928 | char = text[-1] |
|
928 | char = text[-1] | |
929 | # no expand on quote for completion in strings. |
|
929 | # no expand on quote for completion in strings. | |
930 | # nor backcomplete standard ascii keys |
|
930 | # nor backcomplete standard ascii keys | |
931 | if char in string.ascii_letters or char in ['"',"'"]: |
|
931 | if char in string.ascii_letters or char in ['"',"'"]: | |
932 | return u'', () |
|
932 | return u'', () | |
933 | try : |
|
933 | try : | |
934 | latex = reverse_latex_symbol[char] |
|
934 | latex = reverse_latex_symbol[char] | |
935 | # '\\' replace the \ as well |
|
935 | # '\\' replace the \ as well | |
936 | return '\\'+char,[latex] |
|
936 | return '\\'+char,[latex] | |
937 | except KeyError: |
|
937 | except KeyError: | |
938 | pass |
|
938 | pass | |
939 | return u'', () |
|
939 | return u'', () | |
940 |
|
940 | |||
941 |
|
941 | |||
942 | def _formatparamchildren(parameter) -> str: |
|
942 | def _formatparamchildren(parameter) -> str: | |
943 | """ |
|
943 | """ | |
944 | Get parameter name and value from Jedi Private API |
|
944 | Get parameter name and value from Jedi Private API | |
945 |
|
945 | |||
946 | Jedi does not expose a simple way to get `param=value` from its API. |
|
946 | Jedi does not expose a simple way to get `param=value` from its API. | |
947 |
|
947 | |||
948 | Prameter |
|
948 | Prameter | |
949 | ======== |
|
949 | ======== | |
950 |
|
950 | |||
951 | parameter: |
|
951 | parameter: | |
952 | Jedi's function `Param` |
|
952 | Jedi's function `Param` | |
953 |
|
953 | |||
954 | Returns |
|
954 | Returns | |
955 | ======= |
|
955 | ======= | |
956 |
|
956 | |||
957 | A string like 'a', 'b=1', '*args', '**kwargs' |
|
957 | A string like 'a', 'b=1', '*args', '**kwargs' | |
958 |
|
958 | |||
959 |
|
959 | |||
960 | """ |
|
960 | """ | |
961 | description = parameter.description |
|
961 | description = parameter.description | |
962 | if not description.startswith('param '): |
|
962 | if not description.startswith('param '): | |
963 | raise ValueError('Jedi function parameter description have change format.' |
|
963 | raise ValueError('Jedi function parameter description have change format.' | |
964 | 'Expected "param ...", found %r".' % description) |
|
964 | 'Expected "param ...", found %r".' % description) | |
965 | return description[6:] |
|
965 | return description[6:] | |
966 |
|
966 | |||
967 | def _make_signature(completion)-> str: |
|
967 | def _make_signature(completion)-> str: | |
968 | """ |
|
968 | """ | |
969 | Make the signature from a jedi completion |
|
969 | Make the signature from a jedi completion | |
970 |
|
970 | |||
971 | Parameter |
|
971 | Parameter | |
972 | ========= |
|
972 | ========= | |
973 |
|
973 | |||
974 | completion: jedi.Completion |
|
974 | completion: jedi.Completion | |
975 | object does not complete a function type |
|
975 | object does not complete a function type | |
976 |
|
976 | |||
977 | Returns |
|
977 | Returns | |
978 | ======= |
|
978 | ======= | |
979 |
|
979 | |||
980 | a string consisting of the function signature, with the parenthesis but |
|
980 | a string consisting of the function signature, with the parenthesis but | |
981 | without the function name. example: |
|
981 | without the function name. example: | |
982 | `(a, *args, b=1, **kwargs)` |
|
982 | `(a, *args, b=1, **kwargs)` | |
983 |
|
983 | |||
984 | """ |
|
984 | """ | |
985 |
|
985 | |||
986 | return '(%s)'% ', '.join([f for f in (_formatparamchildren(p) for p in completion.params) if f]) |
|
986 | return '(%s)'% ', '.join([f for f in (_formatparamchildren(p) for p in completion.params) if f]) | |
987 |
|
987 | |||
988 | class IPCompleter(Completer): |
|
988 | class IPCompleter(Completer): | |
989 | """Extension of the completer class with IPython-specific features""" |
|
989 | """Extension of the completer class with IPython-specific features""" | |
990 |
|
990 | |||
991 | @observe('greedy') |
|
991 | @observe('greedy') | |
992 | def _greedy_changed(self, change): |
|
992 | def _greedy_changed(self, change): | |
993 | """update the splitter and readline delims when greedy is changed""" |
|
993 | """update the splitter and readline delims when greedy is changed""" | |
994 | if change['new']: |
|
994 | if change['new']: | |
995 | self.splitter.delims = GREEDY_DELIMS |
|
995 | self.splitter.delims = GREEDY_DELIMS | |
996 | else: |
|
996 | else: | |
997 | self.splitter.delims = DELIMS |
|
997 | self.splitter.delims = DELIMS | |
998 |
|
998 | |||
999 | merge_completions = Bool(True, |
|
999 | merge_completions = Bool(True, | |
1000 | help="""Whether to merge completion results into a single list |
|
1000 | help="""Whether to merge completion results into a single list | |
1001 |
|
1001 | |||
1002 | If False, only the completion results from the first non-empty |
|
1002 | If False, only the completion results from the first non-empty | |
1003 | completer will be returned. |
|
1003 | completer will be returned. | |
1004 | """ |
|
1004 | """ | |
1005 | ).tag(config=True) |
|
1005 | ).tag(config=True) | |
1006 | omit__names = Enum((0,1,2), default_value=2, |
|
1006 | omit__names = Enum((0,1,2), default_value=2, | |
1007 | help="""Instruct the completer to omit private method names |
|
1007 | help="""Instruct the completer to omit private method names | |
1008 |
|
1008 | |||
1009 | Specifically, when completing on ``object.<tab>``. |
|
1009 | Specifically, when completing on ``object.<tab>``. | |
1010 |
|
1010 | |||
1011 | When 2 [default]: all names that start with '_' will be excluded. |
|
1011 | When 2 [default]: all names that start with '_' will be excluded. | |
1012 |
|
1012 | |||
1013 | When 1: all 'magic' names (``__foo__``) will be excluded. |
|
1013 | When 1: all 'magic' names (``__foo__``) will be excluded. | |
1014 |
|
1014 | |||
1015 | When 0: nothing will be excluded. |
|
1015 | When 0: nothing will be excluded. | |
1016 | """ |
|
1016 | """ | |
1017 | ).tag(config=True) |
|
1017 | ).tag(config=True) | |
1018 | limit_to__all__ = Bool(False, |
|
1018 | limit_to__all__ = Bool(False, | |
1019 | help=""" |
|
1019 | help=""" | |
1020 | DEPRECATED as of version 5.0. |
|
1020 | DEPRECATED as of version 5.0. | |
1021 |
|
1021 | |||
1022 | Instruct the completer to use __all__ for the completion |
|
1022 | Instruct the completer to use __all__ for the completion | |
1023 |
|
1023 | |||
1024 | Specifically, when completing on ``object.<tab>``. |
|
1024 | Specifically, when completing on ``object.<tab>``. | |
1025 |
|
1025 | |||
1026 | When True: only those names in obj.__all__ will be included. |
|
1026 | When True: only those names in obj.__all__ will be included. | |
1027 |
|
1027 | |||
1028 | When False [default]: the __all__ attribute is ignored |
|
1028 | When False [default]: the __all__ attribute is ignored | |
1029 | """, |
|
1029 | """, | |
1030 | ).tag(config=True) |
|
1030 | ).tag(config=True) | |
1031 |
|
1031 | |||
1032 | @observe('limit_to__all__') |
|
1032 | @observe('limit_to__all__') | |
1033 | def _limit_to_all_changed(self, change): |
|
1033 | def _limit_to_all_changed(self, change): | |
1034 | warnings.warn('`IPython.core.IPCompleter.limit_to__all__` configuration ' |
|
1034 | warnings.warn('`IPython.core.IPCompleter.limit_to__all__` configuration ' | |
1035 | 'value has been deprecated since IPython 5.0, will be made to have ' |
|
1035 | 'value has been deprecated since IPython 5.0, will be made to have ' | |
1036 | 'no effects and then removed in future version of IPython.', |
|
1036 | 'no effects and then removed in future version of IPython.', | |
1037 | UserWarning) |
|
1037 | UserWarning) | |
1038 |
|
1038 | |||
1039 | def __init__(self, shell=None, namespace=None, global_namespace=None, |
|
1039 | def __init__(self, shell=None, namespace=None, global_namespace=None, | |
1040 | use_readline=_deprecation_readline_sentinel, config=None, **kwargs): |
|
1040 | use_readline=_deprecation_readline_sentinel, config=None, **kwargs): | |
1041 | """IPCompleter() -> completer |
|
1041 | """IPCompleter() -> completer | |
1042 |
|
1042 | |||
1043 | Return a completer object. |
|
1043 | Return a completer object. | |
1044 |
|
1044 | |||
1045 | Parameters |
|
1045 | Parameters | |
1046 | ---------- |
|
1046 | ---------- | |
1047 |
|
1047 | |||
1048 | shell |
|
1048 | shell | |
1049 | a pointer to the ipython shell itself. This is needed |
|
1049 | a pointer to the ipython shell itself. This is needed | |
1050 | because this completer knows about magic functions, and those can |
|
1050 | because this completer knows about magic functions, and those can | |
1051 | only be accessed via the ipython instance. |
|
1051 | only be accessed via the ipython instance. | |
1052 |
|
1052 | |||
1053 | namespace : dict, optional |
|
1053 | namespace : dict, optional | |
1054 | an optional dict where completions are performed. |
|
1054 | an optional dict where completions are performed. | |
1055 |
|
1055 | |||
1056 | global_namespace : dict, optional |
|
1056 | global_namespace : dict, optional | |
1057 | secondary optional dict for completions, to |
|
1057 | secondary optional dict for completions, to | |
1058 | handle cases (such as IPython embedded inside functions) where |
|
1058 | handle cases (such as IPython embedded inside functions) where | |
1059 | both Python scopes are visible. |
|
1059 | both Python scopes are visible. | |
1060 |
|
1060 | |||
1061 | use_readline : bool, optional |
|
1061 | use_readline : bool, optional | |
1062 | DEPRECATED, ignored since IPython 6.0, will have no effects |
|
1062 | DEPRECATED, ignored since IPython 6.0, will have no effects | |
1063 | """ |
|
1063 | """ | |
1064 |
|
1064 | |||
1065 | self.magic_escape = ESC_MAGIC |
|
1065 | self.magic_escape = ESC_MAGIC | |
1066 | self.splitter = CompletionSplitter() |
|
1066 | self.splitter = CompletionSplitter() | |
1067 |
|
1067 | |||
1068 | if use_readline is not _deprecation_readline_sentinel: |
|
1068 | if use_readline is not _deprecation_readline_sentinel: | |
1069 | warnings.warn('The `use_readline` parameter is deprecated and ignored since IPython 6.0.', |
|
1069 | warnings.warn('The `use_readline` parameter is deprecated and ignored since IPython 6.0.', | |
1070 | DeprecationWarning, stacklevel=2) |
|
1070 | DeprecationWarning, stacklevel=2) | |
1071 |
|
1071 | |||
1072 | # _greedy_changed() depends on splitter and readline being defined: |
|
1072 | # _greedy_changed() depends on splitter and readline being defined: | |
1073 | Completer.__init__(self, namespace=namespace, global_namespace=global_namespace, |
|
1073 | Completer.__init__(self, namespace=namespace, global_namespace=global_namespace, | |
1074 | config=config, **kwargs) |
|
1074 | config=config, **kwargs) | |
1075 |
|
1075 | |||
1076 | # List where completion matches will be stored |
|
1076 | # List where completion matches will be stored | |
1077 | self.matches = [] |
|
1077 | self.matches = [] | |
1078 | self.shell = shell |
|
1078 | self.shell = shell | |
1079 | # Regexp to split filenames with spaces in them |
|
1079 | # Regexp to split filenames with spaces in them | |
1080 | self.space_name_re = re.compile(r'([^\\] )') |
|
1080 | self.space_name_re = re.compile(r'([^\\] )') | |
1081 | # Hold a local ref. to glob.glob for speed |
|
1081 | # Hold a local ref. to glob.glob for speed | |
1082 | self.glob = glob.glob |
|
1082 | self.glob = glob.glob | |
1083 |
|
1083 | |||
1084 | # Determine if we are running on 'dumb' terminals, like (X)Emacs |
|
1084 | # Determine if we are running on 'dumb' terminals, like (X)Emacs | |
1085 | # buffers, to avoid completion problems. |
|
1085 | # buffers, to avoid completion problems. | |
1086 | term = os.environ.get('TERM','xterm') |
|
1086 | term = os.environ.get('TERM','xterm') | |
1087 | self.dumb_terminal = term in ['dumb','emacs'] |
|
1087 | self.dumb_terminal = term in ['dumb','emacs'] | |
1088 |
|
1088 | |||
1089 | # Special handling of backslashes needed in win32 platforms |
|
1089 | # Special handling of backslashes needed in win32 platforms | |
1090 | if sys.platform == "win32": |
|
1090 | if sys.platform == "win32": | |
1091 | self.clean_glob = self._clean_glob_win32 |
|
1091 | self.clean_glob = self._clean_glob_win32 | |
1092 | else: |
|
1092 | else: | |
1093 | self.clean_glob = self._clean_glob |
|
1093 | self.clean_glob = self._clean_glob | |
1094 |
|
1094 | |||
1095 | #regexp to parse docstring for function signature |
|
1095 | #regexp to parse docstring for function signature | |
1096 | self.docstring_sig_re = re.compile(r'^[\w|\s.]+\(([^)]*)\).*') |
|
1096 | self.docstring_sig_re = re.compile(r'^[\w|\s.]+\(([^)]*)\).*') | |
1097 | self.docstring_kwd_re = re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)') |
|
1097 | self.docstring_kwd_re = re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)') | |
1098 | #use this if positional argument name is also needed |
|
1098 | #use this if positional argument name is also needed | |
1099 | #= re.compile(r'[\s|\[]*(\w+)(?:\s*=?\s*.*)') |
|
1099 | #= re.compile(r'[\s|\[]*(\w+)(?:\s*=?\s*.*)') | |
1100 |
|
1100 | |||
1101 | # All active matcher routines for completion |
|
1101 | # All active matcher routines for completion | |
1102 | self.matchers = [ |
|
1102 | self.matchers = [ | |
1103 | self.python_matches, |
|
1103 | self.python_matches, | |
1104 | self.file_matches, |
|
1104 | self.file_matches, | |
1105 | self.magic_matches, |
|
1105 | self.magic_matches, | |
1106 | self.python_func_kw_matches, |
|
1106 | self.python_func_kw_matches, | |
1107 | self.dict_key_matches, |
|
1107 | self.dict_key_matches, | |
1108 | ] |
|
1108 | ] | |
1109 | self.magic_arg_matchers = [ |
|
1109 | self.magic_arg_matchers = [ | |
1110 | self.magic_config_matches, |
|
1110 | self.magic_config_matches, | |
1111 | self.magic_color_matches, |
|
1111 | self.magic_color_matches, | |
1112 | ] |
|
1112 | ] | |
1113 |
|
1113 | |||
1114 | # This is set externally by InteractiveShell |
|
1114 | # This is set externally by InteractiveShell | |
1115 | self.custom_completers = None |
|
1115 | self.custom_completers = None | |
1116 |
|
1116 | |||
1117 | def all_completions(self, text): |
|
1117 | def all_completions(self, text): | |
1118 | """ |
|
1118 | """ | |
1119 | Wrapper around the complete method for the benefit of emacs. |
|
1119 | Wrapper around the complete method for the benefit of emacs. | |
1120 | """ |
|
1120 | """ | |
1121 | return self.complete(text)[1] |
|
1121 | return self.complete(text)[1] | |
1122 |
|
1122 | |||
1123 | def _clean_glob(self, text): |
|
1123 | def _clean_glob(self, text): | |
1124 | return self.glob("%s*" % text) |
|
1124 | return self.glob("%s*" % text) | |
1125 |
|
1125 | |||
1126 | def _clean_glob_win32(self,text): |
|
1126 | def _clean_glob_win32(self,text): | |
1127 | return [f.replace("\\","/") |
|
1127 | return [f.replace("\\","/") | |
1128 | for f in self.glob("%s*" % text)] |
|
1128 | for f in self.glob("%s*" % text)] | |
1129 |
|
1129 | |||
1130 | def file_matches(self, text): |
|
1130 | def file_matches(self, text): | |
1131 | """Match filenames, expanding ~USER type strings. |
|
1131 | """Match filenames, expanding ~USER type strings. | |
1132 |
|
1132 | |||
1133 | Most of the seemingly convoluted logic in this completer is an |
|
1133 | Most of the seemingly convoluted logic in this completer is an | |
1134 | attempt to handle filenames with spaces in them. And yet it's not |
|
1134 | attempt to handle filenames with spaces in them. And yet it's not | |
1135 | quite perfect, because Python's readline doesn't expose all of the |
|
1135 | quite perfect, because Python's readline doesn't expose all of the | |
1136 | GNU readline details needed for this to be done correctly. |
|
1136 | GNU readline details needed for this to be done correctly. | |
1137 |
|
1137 | |||
1138 | For a filename with a space in it, the printed completions will be |
|
1138 | For a filename with a space in it, the printed completions will be | |
1139 | only the parts after what's already been typed (instead of the |
|
1139 | only the parts after what's already been typed (instead of the | |
1140 | full completions, as is normally done). I don't think with the |
|
1140 | full completions, as is normally done). I don't think with the | |
1141 | current (as of Python 2.3) Python readline it's possible to do |
|
1141 | current (as of Python 2.3) Python readline it's possible to do | |
1142 | better.""" |
|
1142 | better.""" | |
1143 |
|
1143 | |||
1144 | # chars that require escaping with backslash - i.e. chars |
|
1144 | # chars that require escaping with backslash - i.e. chars | |
1145 | # that readline treats incorrectly as delimiters, but we |
|
1145 | # that readline treats incorrectly as delimiters, but we | |
1146 | # don't want to treat as delimiters in filename matching |
|
1146 | # don't want to treat as delimiters in filename matching | |
1147 | # when escaped with backslash |
|
1147 | # when escaped with backslash | |
1148 | if text.startswith('!'): |
|
1148 | if text.startswith('!'): | |
1149 | text = text[1:] |
|
1149 | text = text[1:] | |
1150 | text_prefix = u'!' |
|
1150 | text_prefix = u'!' | |
1151 | else: |
|
1151 | else: | |
1152 | text_prefix = u'' |
|
1152 | text_prefix = u'' | |
1153 |
|
1153 | |||
1154 | text_until_cursor = self.text_until_cursor |
|
1154 | text_until_cursor = self.text_until_cursor | |
1155 | # track strings with open quotes |
|
1155 | # track strings with open quotes | |
1156 | open_quotes = has_open_quotes(text_until_cursor) |
|
1156 | open_quotes = has_open_quotes(text_until_cursor) | |
1157 |
|
1157 | |||
1158 | if '(' in text_until_cursor or '[' in text_until_cursor: |
|
1158 | if '(' in text_until_cursor or '[' in text_until_cursor: | |
1159 | lsplit = text |
|
1159 | lsplit = text | |
1160 | else: |
|
1160 | else: | |
1161 | try: |
|
1161 | try: | |
1162 | # arg_split ~ shlex.split, but with unicode bugs fixed by us |
|
1162 | # arg_split ~ shlex.split, but with unicode bugs fixed by us | |
1163 | lsplit = arg_split(text_until_cursor)[-1] |
|
1163 | lsplit = arg_split(text_until_cursor)[-1] | |
1164 | except ValueError: |
|
1164 | except ValueError: | |
1165 | # typically an unmatched ", or backslash without escaped char. |
|
1165 | # typically an unmatched ", or backslash without escaped char. | |
1166 | if open_quotes: |
|
1166 | if open_quotes: | |
1167 | lsplit = text_until_cursor.split(open_quotes)[-1] |
|
1167 | lsplit = text_until_cursor.split(open_quotes)[-1] | |
1168 | else: |
|
1168 | else: | |
1169 | return [] |
|
1169 | return [] | |
1170 | except IndexError: |
|
1170 | except IndexError: | |
1171 | # tab pressed on empty line |
|
1171 | # tab pressed on empty line | |
1172 | lsplit = "" |
|
1172 | lsplit = "" | |
1173 |
|
1173 | |||
1174 | if not open_quotes and lsplit != protect_filename(lsplit): |
|
1174 | if not open_quotes and lsplit != protect_filename(lsplit): | |
1175 | # if protectables are found, do matching on the whole escaped name |
|
1175 | # if protectables are found, do matching on the whole escaped name | |
1176 | has_protectables = True |
|
1176 | has_protectables = True | |
1177 | text0,text = text,lsplit |
|
1177 | text0,text = text,lsplit | |
1178 | else: |
|
1178 | else: | |
1179 | has_protectables = False |
|
1179 | has_protectables = False | |
1180 | text = os.path.expanduser(text) |
|
1180 | text = os.path.expanduser(text) | |
1181 |
|
1181 | |||
1182 | if text == "": |
|
1182 | if text == "": | |
1183 | return [text_prefix + protect_filename(f) for f in self.glob("*")] |
|
1183 | return [text_prefix + protect_filename(f) for f in self.glob("*")] | |
1184 |
|
1184 | |||
1185 | # Compute the matches from the filesystem |
|
1185 | # Compute the matches from the filesystem | |
1186 | if sys.platform == 'win32': |
|
1186 | if sys.platform == 'win32': | |
1187 | m0 = self.clean_glob(text) |
|
1187 | m0 = self.clean_glob(text) | |
1188 | else: |
|
1188 | else: | |
1189 | m0 = self.clean_glob(text.replace('\\', '')) |
|
1189 | m0 = self.clean_glob(text.replace('\\', '')) | |
1190 |
|
1190 | |||
1191 | if has_protectables: |
|
1191 | if has_protectables: | |
1192 | # If we had protectables, we need to revert our changes to the |
|
1192 | # If we had protectables, we need to revert our changes to the | |
1193 | # beginning of filename so that we don't double-write the part |
|
1193 | # beginning of filename so that we don't double-write the part | |
1194 | # of the filename we have so far |
|
1194 | # of the filename we have so far | |
1195 | len_lsplit = len(lsplit) |
|
1195 | len_lsplit = len(lsplit) | |
1196 | matches = [text_prefix + text0 + |
|
1196 | matches = [text_prefix + text0 + | |
1197 | protect_filename(f[len_lsplit:]) for f in m0] |
|
1197 | protect_filename(f[len_lsplit:]) for f in m0] | |
1198 | else: |
|
1198 | else: | |
1199 | if open_quotes: |
|
1199 | if open_quotes: | |
1200 | # if we have a string with an open quote, we don't need to |
|
1200 | # if we have a string with an open quote, we don't need to | |
1201 | # protect the names beyond the quote (and we _shouldn't_, as |
|
1201 | # protect the names beyond the quote (and we _shouldn't_, as | |
1202 | # it would cause bugs when the filesystem call is made). |
|
1202 | # it would cause bugs when the filesystem call is made). | |
1203 | matches = m0 if sys.platform == "win32" else\ |
|
1203 | matches = m0 if sys.platform == "win32" else\ | |
1204 | [protect_filename(f, open_quotes) for f in m0] |
|
1204 | [protect_filename(f, open_quotes) for f in m0] | |
1205 | else: |
|
1205 | else: | |
1206 | matches = [text_prefix + |
|
1206 | matches = [text_prefix + | |
1207 | protect_filename(f) for f in m0] |
|
1207 | protect_filename(f) for f in m0] | |
1208 |
|
1208 | |||
1209 | # Mark directories in input list by appending '/' to their names. |
|
1209 | # Mark directories in input list by appending '/' to their names. | |
1210 | return [x+'/' if os.path.isdir(x) else x for x in matches] |
|
1210 | return [x+'/' if os.path.isdir(x) else x for x in matches] | |
1211 |
|
1211 | |||
1212 | def magic_matches(self, text): |
|
1212 | def magic_matches(self, text): | |
1213 | """Match magics""" |
|
1213 | """Match magics""" | |
1214 | # Get all shell magics now rather than statically, so magics loaded at |
|
1214 | # Get all shell magics now rather than statically, so magics loaded at | |
1215 | # runtime show up too. |
|
1215 | # runtime show up too. | |
1216 | lsm = self.shell.magics_manager.lsmagic() |
|
1216 | lsm = self.shell.magics_manager.lsmagic() | |
1217 | line_magics = lsm['line'] |
|
1217 | line_magics = lsm['line'] | |
1218 | cell_magics = lsm['cell'] |
|
1218 | cell_magics = lsm['cell'] | |
1219 | pre = self.magic_escape |
|
1219 | pre = self.magic_escape | |
1220 | pre2 = pre+pre |
|
1220 | pre2 = pre+pre | |
1221 |
|
1221 | |||
1222 | # Completion logic: |
|
1222 | # Completion logic: | |
1223 | # - user gives %%: only do cell magics |
|
1223 | # - user gives %%: only do cell magics | |
1224 | # - user gives %: do both line and cell magics |
|
1224 | # - user gives %: do both line and cell magics | |
1225 | # - no prefix: do both |
|
1225 | # - no prefix: do both | |
1226 | # In other words, line magics are skipped if the user gives %% explicitly |
|
1226 | # In other words, line magics are skipped if the user gives %% explicitly | |
1227 | # |
|
1227 | # | |
1228 | # We also exclude magics that match any currently visible names: |
|
1228 | # We also exclude magics that match any currently visible names: | |
1229 | # https://github.com/ipython/ipython/issues/4877 |
|
1229 | # https://github.com/ipython/ipython/issues/4877 | |
1230 | bare_text = text.lstrip(pre) |
|
1230 | bare_text = text.lstrip(pre) | |
1231 | global_matches = self.global_matches(bare_text) |
|
1231 | global_matches = self.global_matches(bare_text) | |
1232 | matches = lambda magic: magic.startswith(bare_text) \ |
|
1232 | matches = lambda magic: magic.startswith(bare_text) \ | |
1233 | and magic not in global_matches |
|
1233 | and magic not in global_matches | |
1234 | comp = [ pre2+m for m in cell_magics if matches(m)] |
|
1234 | comp = [ pre2+m for m in cell_magics if matches(m)] | |
1235 | if not text.startswith(pre2): |
|
1235 | if not text.startswith(pre2): | |
1236 | comp += [ pre+m for m in line_magics if matches(m)] |
|
1236 | comp += [ pre+m for m in line_magics if matches(m)] | |
1237 |
|
1237 | |||
1238 | return comp |
|
1238 | return comp | |
1239 |
|
1239 | |||
1240 | def magic_config_matches(self, text:str) -> List[str]: |
|
1240 | def magic_config_matches(self, text:str) -> List[str]: | |
1241 | """ Match class names and attributes for %config magic """ |
|
1241 | """ Match class names and attributes for %config magic """ | |
1242 | texts = text.strip().split() |
|
1242 | texts = text.strip().split() | |
1243 |
|
1243 | |||
1244 | if len(texts) > 0 and (texts[0] == 'config' or texts[0] == '%config'): |
|
1244 | if len(texts) > 0 and (texts[0] == 'config' or texts[0] == '%config'): | |
1245 | # get all configuration classes |
|
1245 | # get all configuration classes | |
1246 | classes = sorted(set([ c for c in self.shell.configurables |
|
1246 | classes = sorted(set([ c for c in self.shell.configurables | |
1247 | if c.__class__.class_traits(config=True) |
|
1247 | if c.__class__.class_traits(config=True) | |
1248 | ]), key=lambda x: x.__class__.__name__) |
|
1248 | ]), key=lambda x: x.__class__.__name__) | |
1249 | classnames = [ c.__class__.__name__ for c in classes ] |
|
1249 | classnames = [ c.__class__.__name__ for c in classes ] | |
1250 |
|
1250 | |||
1251 | # return all classnames if config or %config is given |
|
1251 | # return all classnames if config or %config is given | |
1252 | if len(texts) == 1: |
|
1252 | if len(texts) == 1: | |
1253 | return classnames |
|
1253 | return classnames | |
1254 |
|
1254 | |||
1255 | # match classname |
|
1255 | # match classname | |
1256 | classname_texts = texts[1].split('.') |
|
1256 | classname_texts = texts[1].split('.') | |
1257 | classname = classname_texts[0] |
|
1257 | classname = classname_texts[0] | |
1258 | classname_matches = [ c for c in classnames |
|
1258 | classname_matches = [ c for c in classnames | |
1259 | if c.startswith(classname) ] |
|
1259 | if c.startswith(classname) ] | |
1260 |
|
1260 | |||
1261 | # return matched classes or the matched class with attributes |
|
1261 | # return matched classes or the matched class with attributes | |
1262 | if texts[1].find('.') < 0: |
|
1262 | if texts[1].find('.') < 0: | |
1263 | return classname_matches |
|
1263 | return classname_matches | |
1264 | elif len(classname_matches) == 1 and \ |
|
1264 | elif len(classname_matches) == 1 and \ | |
1265 | classname_matches[0] == classname: |
|
1265 | classname_matches[0] == classname: | |
1266 | cls = classes[classnames.index(classname)].__class__ |
|
1266 | cls = classes[classnames.index(classname)].__class__ | |
1267 | help = cls.class_get_help() |
|
1267 | help = cls.class_get_help() | |
1268 | # strip leading '--' from cl-args: |
|
1268 | # strip leading '--' from cl-args: | |
1269 | help = re.sub(re.compile(r'^--', re.MULTILINE), '', help) |
|
1269 | help = re.sub(re.compile(r'^--', re.MULTILINE), '', help) | |
1270 | return [ attr.split('=')[0] |
|
1270 | return [ attr.split('=')[0] | |
1271 | for attr in help.strip().splitlines() |
|
1271 | for attr in help.strip().splitlines() | |
1272 | if attr.startswith(texts[1]) ] |
|
1272 | if attr.startswith(texts[1]) ] | |
1273 | return [] |
|
1273 | return [] | |
1274 |
|
1274 | |||
1275 | def magic_color_matches(self, text:str) -> List[str] : |
|
1275 | def magic_color_matches(self, text:str) -> List[str] : | |
1276 | """ Match color schemes for %colors magic""" |
|
1276 | """ Match color schemes for %colors magic""" | |
1277 | texts = text.strip().split() |
|
1277 | texts = text.strip().split() | |
1278 |
|
1278 | |||
1279 | if len(texts) > 0 and (texts[0] == 'colors' or texts[0] == '%colors'): |
|
1279 | if len(texts) > 0 and (texts[0] == 'colors' or texts[0] == '%colors'): | |
1280 | prefix = texts[1] if len(texts) > 1 else '' |
|
1280 | prefix = texts[1] if len(texts) > 1 else '' | |
1281 | return [ color for color in InspectColors.keys() |
|
1281 | return [ color for color in InspectColors.keys() | |
1282 | if color.startswith(prefix) ] |
|
1282 | if color.startswith(prefix) ] | |
1283 | return [] |
|
1283 | return [] | |
1284 |
|
1284 | |||
1285 | def _jedi_matches(self, cursor_column:int, cursor_line:int, text:str): |
|
1285 | def _jedi_matches(self, cursor_column:int, cursor_line:int, text:str): | |
1286 | """ |
|
1286 | """ | |
1287 |
|
1287 | |||
1288 | Return a list of :any:`jedi.api.Completions` object from a ``text`` and |
|
1288 | Return a list of :any:`jedi.api.Completions` object from a ``text`` and | |
1289 | cursor position. |
|
1289 | cursor position. | |
1290 |
|
1290 | |||
1291 | Parameters |
|
1291 | Parameters | |
1292 | ---------- |
|
1292 | ---------- | |
1293 | cursor_column : int |
|
1293 | cursor_column : int | |
1294 | column position of the cursor in ``text``, 0-indexed. |
|
1294 | column position of the cursor in ``text``, 0-indexed. | |
1295 | cursor_line : int |
|
1295 | cursor_line : int | |
1296 | line position of the cursor in ``text``, 0-indexed |
|
1296 | line position of the cursor in ``text``, 0-indexed | |
1297 | text : str |
|
1297 | text : str | |
1298 | text to complete |
|
1298 | text to complete | |
1299 |
|
1299 | |||
1300 | Debugging |
|
1300 | Debugging | |
1301 | --------- |
|
1301 | --------- | |
1302 |
|
1302 | |||
1303 | If ``IPCompleter.debug`` is ``True`` may return a :any:`_FakeJediCompletion` |
|
1303 | If ``IPCompleter.debug`` is ``True`` may return a :any:`_FakeJediCompletion` | |
1304 | object containing a string with the Jedi debug information attached. |
|
1304 | object containing a string with the Jedi debug information attached. | |
1305 | """ |
|
1305 | """ | |
1306 | namespaces = [self.namespace] |
|
1306 | namespaces = [self.namespace] | |
1307 | if self.global_namespace is not None: |
|
1307 | if self.global_namespace is not None: | |
1308 | namespaces.append(self.global_namespace) |
|
1308 | namespaces.append(self.global_namespace) | |
1309 |
|
1309 | |||
1310 | completion_filter = lambda x:x |
|
1310 | completion_filter = lambda x:x | |
1311 | # cursor_pos is an it, jedi wants line and column |
|
1311 | # cursor_pos is an it, jedi wants line and column | |
1312 | offset = cursor_to_position(text, cursor_line, cursor_column) |
|
1312 | offset = cursor_to_position(text, cursor_line, cursor_column) | |
1313 | # filter output if we are completing for object members |
|
1313 | # filter output if we are completing for object members | |
1314 | if offset: |
|
1314 | if offset: | |
1315 | pre = text[offset-1] |
|
1315 | pre = text[offset-1] | |
1316 | if pre == '.': |
|
1316 | if pre == '.': | |
1317 | if self.omit__names == 2: |
|
1317 | if self.omit__names == 2: | |
1318 | completion_filter = lambda c:not c.name.startswith('_') |
|
1318 | completion_filter = lambda c:not c.name.startswith('_') | |
1319 | elif self.omit__names == 1: |
|
1319 | elif self.omit__names == 1: | |
1320 | completion_filter = lambda c:not (c.name.startswith('__') and c.name.endswith('__')) |
|
1320 | completion_filter = lambda c:not (c.name.startswith('__') and c.name.endswith('__')) | |
1321 | elif self.omit__names == 0: |
|
1321 | elif self.omit__names == 0: | |
1322 | completion_filter = lambda x:x |
|
1322 | completion_filter = lambda x:x | |
1323 | else: |
|
1323 | else: | |
1324 | raise ValueError("Don't understand self.omit__names == {}".format(self.omit__names)) |
|
1324 | raise ValueError("Don't understand self.omit__names == {}".format(self.omit__names)) | |
1325 |
|
1325 | |||
1326 | interpreter = jedi.Interpreter( |
|
1326 | interpreter = jedi.Interpreter( | |
1327 | text, namespaces, column=cursor_column, line=cursor_line + 1) |
|
1327 | text, namespaces, column=cursor_column, line=cursor_line + 1) | |
1328 |
|
1328 | |||
1329 | try_jedi = False |
|
1329 | try_jedi = False | |
1330 |
|
1330 | |||
1331 | try: |
|
1331 | try: | |
1332 | # should we check the type of the node is Error ? |
|
1332 | # should we check the type of the node is Error ? | |
1333 | from jedi.parser.tree import ErrorLeaf |
|
1333 | from jedi.parser.tree import ErrorLeaf | |
1334 | next_to_last_tree = interpreter._get_module().tree_node.children[-2] |
|
1334 | next_to_last_tree = interpreter._get_module().tree_node.children[-2] | |
1335 | completing_string = False |
|
1335 | completing_string = False | |
1336 | if isinstance(next_to_last_tree, ErrorLeaf): |
|
1336 | if isinstance(next_to_last_tree, ErrorLeaf): | |
1337 | completing_string = interpreter._get_module().tree_node.children[-2].value[0] in {'"', "'"} |
|
1337 | completing_string = interpreter._get_module().tree_node.children[-2].value[0] in {'"', "'"} | |
1338 | # if we are in a string jedi is likely not the right candidate for |
|
1338 | # if we are in a string jedi is likely not the right candidate for | |
1339 | # now. Skip it. |
|
1339 | # now. Skip it. | |
1340 | try_jedi = not completing_string |
|
1340 | try_jedi = not completing_string | |
1341 | except Exception as e: |
|
1341 | except Exception as e: | |
1342 | # many of things can go wrong, we are using private API just don't crash. |
|
1342 | # many of things can go wrong, we are using private API just don't crash. | |
1343 | if self.debug: |
|
1343 | if self.debug: | |
1344 | print("Error detecting if completing a non-finished string :", e, '|') |
|
1344 | print("Error detecting if completing a non-finished string :", e, '|') | |
1345 |
|
1345 | |||
1346 | if not try_jedi: |
|
1346 | if not try_jedi: | |
1347 | return [] |
|
1347 | return [] | |
1348 | try: |
|
1348 | try: | |
1349 | return filter(completion_filter, interpreter.completions()) |
|
1349 | return filter(completion_filter, interpreter.completions()) | |
1350 | except Exception as e: |
|
1350 | except Exception as e: | |
1351 | if self.debug: |
|
1351 | if self.debug: | |
1352 | return [_FakeJediCompletion('Oops Jedi has crashed, please report a bug with the following:\n"""\n%s\ns"""' % (e))] |
|
1352 | return [_FakeJediCompletion('Oops Jedi has crashed, please report a bug with the following:\n"""\n%s\ns"""' % (e))] | |
1353 | else: |
|
1353 | else: | |
1354 | return [] |
|
1354 | return [] | |
1355 |
|
1355 | |||
1356 | def python_matches(self, text): |
|
1356 | def python_matches(self, text): | |
1357 | """Match attributes or global python names""" |
|
1357 | """Match attributes or global python names""" | |
1358 | if "." in text: |
|
1358 | if "." in text: | |
1359 | try: |
|
1359 | try: | |
1360 | matches = self.attr_matches(text) |
|
1360 | matches = self.attr_matches(text) | |
1361 | if text.endswith('.') and self.omit__names: |
|
1361 | if text.endswith('.') and self.omit__names: | |
1362 | if self.omit__names == 1: |
|
1362 | if self.omit__names == 1: | |
1363 | # true if txt is _not_ a __ name, false otherwise: |
|
1363 | # true if txt is _not_ a __ name, false otherwise: | |
1364 | no__name = (lambda txt: |
|
1364 | no__name = (lambda txt: | |
1365 | re.match(r'.*\.__.*?__',txt) is None) |
|
1365 | re.match(r'.*\.__.*?__',txt) is None) | |
1366 | else: |
|
1366 | else: | |
1367 | # true if txt is _not_ a _ name, false otherwise: |
|
1367 | # true if txt is _not_ a _ name, false otherwise: | |
1368 | no__name = (lambda txt: |
|
1368 | no__name = (lambda txt: | |
1369 | re.match(r'\._.*?',txt[txt.rindex('.'):]) is None) |
|
1369 | re.match(r'\._.*?',txt[txt.rindex('.'):]) is None) | |
1370 | matches = filter(no__name, matches) |
|
1370 | matches = filter(no__name, matches) | |
1371 | except NameError: |
|
1371 | except NameError: | |
1372 | # catches <undefined attributes>.<tab> |
|
1372 | # catches <undefined attributes>.<tab> | |
1373 | matches = [] |
|
1373 | matches = [] | |
1374 | else: |
|
1374 | else: | |
1375 | matches = self.global_matches(text) |
|
1375 | matches = self.global_matches(text) | |
1376 | return matches |
|
1376 | return matches | |
1377 |
|
1377 | |||
1378 | def _default_arguments_from_docstring(self, doc): |
|
1378 | def _default_arguments_from_docstring(self, doc): | |
1379 | """Parse the first line of docstring for call signature. |
|
1379 | """Parse the first line of docstring for call signature. | |
1380 |
|
1380 | |||
1381 | Docstring should be of the form 'min(iterable[, key=func])\n'. |
|
1381 | Docstring should be of the form 'min(iterable[, key=func])\n'. | |
1382 | It can also parse cython docstring of the form |
|
1382 | It can also parse cython docstring of the form | |
1383 | 'Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)'. |
|
1383 | 'Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)'. | |
1384 | """ |
|
1384 | """ | |
1385 | if doc is None: |
|
1385 | if doc is None: | |
1386 | return [] |
|
1386 | return [] | |
1387 |
|
1387 | |||
1388 | #care only the firstline |
|
1388 | #care only the firstline | |
1389 | line = doc.lstrip().splitlines()[0] |
|
1389 | line = doc.lstrip().splitlines()[0] | |
1390 |
|
1390 | |||
1391 | #p = re.compile(r'^[\w|\s.]+\(([^)]*)\).*') |
|
1391 | #p = re.compile(r'^[\w|\s.]+\(([^)]*)\).*') | |
1392 | #'min(iterable[, key=func])\n' -> 'iterable[, key=func]' |
|
1392 | #'min(iterable[, key=func])\n' -> 'iterable[, key=func]' | |
1393 | sig = self.docstring_sig_re.search(line) |
|
1393 | sig = self.docstring_sig_re.search(line) | |
1394 | if sig is None: |
|
1394 | if sig is None: | |
1395 | return [] |
|
1395 | return [] | |
1396 | # iterable[, key=func]' -> ['iterable[' ,' key=func]'] |
|
1396 | # iterable[, key=func]' -> ['iterable[' ,' key=func]'] | |
1397 | sig = sig.groups()[0].split(',') |
|
1397 | sig = sig.groups()[0].split(',') | |
1398 | ret = [] |
|
1398 | ret = [] | |
1399 | for s in sig: |
|
1399 | for s in sig: | |
1400 | #re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)') |
|
1400 | #re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)') | |
1401 | ret += self.docstring_kwd_re.findall(s) |
|
1401 | ret += self.docstring_kwd_re.findall(s) | |
1402 | return ret |
|
1402 | return ret | |
1403 |
|
1403 | |||
1404 | def _default_arguments(self, obj): |
|
1404 | def _default_arguments(self, obj): | |
1405 | """Return the list of default arguments of obj if it is callable, |
|
1405 | """Return the list of default arguments of obj if it is callable, | |
1406 | or empty list otherwise.""" |
|
1406 | or empty list otherwise.""" | |
1407 | call_obj = obj |
|
1407 | call_obj = obj | |
1408 | ret = [] |
|
1408 | ret = [] | |
1409 | if inspect.isbuiltin(obj): |
|
1409 | if inspect.isbuiltin(obj): | |
1410 | pass |
|
1410 | pass | |
1411 | elif not (inspect.isfunction(obj) or inspect.ismethod(obj)): |
|
1411 | elif not (inspect.isfunction(obj) or inspect.ismethod(obj)): | |
1412 | if inspect.isclass(obj): |
|
1412 | if inspect.isclass(obj): | |
1413 | #for cython embededsignature=True the constructor docstring |
|
1413 | #for cython embeddedsignature=True the constructor docstring | |
1414 | #belongs to the object itself not __init__ |
|
1414 | #belongs to the object itself not __init__ | |
1415 | ret += self._default_arguments_from_docstring( |
|
1415 | ret += self._default_arguments_from_docstring( | |
1416 | getattr(obj, '__doc__', '')) |
|
1416 | getattr(obj, '__doc__', '')) | |
1417 | # for classes, check for __init__,__new__ |
|
1417 | # for classes, check for __init__,__new__ | |
1418 | call_obj = (getattr(obj, '__init__', None) or |
|
1418 | call_obj = (getattr(obj, '__init__', None) or | |
1419 | getattr(obj, '__new__', None)) |
|
1419 | getattr(obj, '__new__', None)) | |
1420 | # for all others, check if they are __call__able |
|
1420 | # for all others, check if they are __call__able | |
1421 | elif hasattr(obj, '__call__'): |
|
1421 | elif hasattr(obj, '__call__'): | |
1422 | call_obj = obj.__call__ |
|
1422 | call_obj = obj.__call__ | |
1423 | ret += self._default_arguments_from_docstring( |
|
1423 | ret += self._default_arguments_from_docstring( | |
1424 | getattr(call_obj, '__doc__', '')) |
|
1424 | getattr(call_obj, '__doc__', '')) | |
1425 |
|
1425 | |||
1426 | _keeps = (inspect.Parameter.KEYWORD_ONLY, |
|
1426 | _keeps = (inspect.Parameter.KEYWORD_ONLY, | |
1427 | inspect.Parameter.POSITIONAL_OR_KEYWORD) |
|
1427 | inspect.Parameter.POSITIONAL_OR_KEYWORD) | |
1428 |
|
1428 | |||
1429 | try: |
|
1429 | try: | |
1430 | sig = inspect.signature(call_obj) |
|
1430 | sig = inspect.signature(call_obj) | |
1431 | ret.extend(k for k, v in sig.parameters.items() if |
|
1431 | ret.extend(k for k, v in sig.parameters.items() if | |
1432 | v.kind in _keeps) |
|
1432 | v.kind in _keeps) | |
1433 | except ValueError: |
|
1433 | except ValueError: | |
1434 | pass |
|
1434 | pass | |
1435 |
|
1435 | |||
1436 | return list(set(ret)) |
|
1436 | return list(set(ret)) | |
1437 |
|
1437 | |||
1438 | def python_func_kw_matches(self,text): |
|
1438 | def python_func_kw_matches(self,text): | |
1439 | """Match named parameters (kwargs) of the last open function""" |
|
1439 | """Match named parameters (kwargs) of the last open function""" | |
1440 |
|
1440 | |||
1441 | if "." in text: # a parameter cannot be dotted |
|
1441 | if "." in text: # a parameter cannot be dotted | |
1442 | return [] |
|
1442 | return [] | |
1443 | try: regexp = self.__funcParamsRegex |
|
1443 | try: regexp = self.__funcParamsRegex | |
1444 | except AttributeError: |
|
1444 | except AttributeError: | |
1445 | regexp = self.__funcParamsRegex = re.compile(r''' |
|
1445 | regexp = self.__funcParamsRegex = re.compile(r''' | |
1446 | '.*?(?<!\\)' | # single quoted strings or |
|
1446 | '.*?(?<!\\)' | # single quoted strings or | |
1447 | ".*?(?<!\\)" | # double quoted strings or |
|
1447 | ".*?(?<!\\)" | # double quoted strings or | |
1448 | \w+ | # identifier |
|
1448 | \w+ | # identifier | |
1449 | \S # other characters |
|
1449 | \S # other characters | |
1450 | ''', re.VERBOSE | re.DOTALL) |
|
1450 | ''', re.VERBOSE | re.DOTALL) | |
1451 | # 1. find the nearest identifier that comes before an unclosed |
|
1451 | # 1. find the nearest identifier that comes before an unclosed | |
1452 | # parenthesis before the cursor |
|
1452 | # parenthesis before the cursor | |
1453 | # e.g. for "foo (1+bar(x), pa<cursor>,a=1)", the candidate is "foo" |
|
1453 | # e.g. for "foo (1+bar(x), pa<cursor>,a=1)", the candidate is "foo" | |
1454 | tokens = regexp.findall(self.text_until_cursor) |
|
1454 | tokens = regexp.findall(self.text_until_cursor) | |
1455 | iterTokens = reversed(tokens); openPar = 0 |
|
1455 | iterTokens = reversed(tokens); openPar = 0 | |
1456 |
|
1456 | |||
1457 | for token in iterTokens: |
|
1457 | for token in iterTokens: | |
1458 | if token == ')': |
|
1458 | if token == ')': | |
1459 | openPar -= 1 |
|
1459 | openPar -= 1 | |
1460 | elif token == '(': |
|
1460 | elif token == '(': | |
1461 | openPar += 1 |
|
1461 | openPar += 1 | |
1462 | if openPar > 0: |
|
1462 | if openPar > 0: | |
1463 | # found the last unclosed parenthesis |
|
1463 | # found the last unclosed parenthesis | |
1464 | break |
|
1464 | break | |
1465 | else: |
|
1465 | else: | |
1466 | return [] |
|
1466 | return [] | |
1467 | # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" ) |
|
1467 | # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" ) | |
1468 | ids = [] |
|
1468 | ids = [] | |
1469 | isId = re.compile(r'\w+$').match |
|
1469 | isId = re.compile(r'\w+$').match | |
1470 |
|
1470 | |||
1471 | while True: |
|
1471 | while True: | |
1472 | try: |
|
1472 | try: | |
1473 | ids.append(next(iterTokens)) |
|
1473 | ids.append(next(iterTokens)) | |
1474 | if not isId(ids[-1]): |
|
1474 | if not isId(ids[-1]): | |
1475 | ids.pop(); break |
|
1475 | ids.pop(); break | |
1476 | if not next(iterTokens) == '.': |
|
1476 | if not next(iterTokens) == '.': | |
1477 | break |
|
1477 | break | |
1478 | except StopIteration: |
|
1478 | except StopIteration: | |
1479 | break |
|
1479 | break | |
1480 |
|
1480 | |||
1481 | # Find all named arguments already assigned to, as to avoid suggesting |
|
1481 | # Find all named arguments already assigned to, as to avoid suggesting | |
1482 | # them again |
|
1482 | # them again | |
1483 | usedNamedArgs = set() |
|
1483 | usedNamedArgs = set() | |
1484 | par_level = -1 |
|
1484 | par_level = -1 | |
1485 | for token, next_token in zip(tokens, tokens[1:]): |
|
1485 | for token, next_token in zip(tokens, tokens[1:]): | |
1486 | if token == '(': |
|
1486 | if token == '(': | |
1487 | par_level += 1 |
|
1487 | par_level += 1 | |
1488 | elif token == ')': |
|
1488 | elif token == ')': | |
1489 | par_level -= 1 |
|
1489 | par_level -= 1 | |
1490 |
|
1490 | |||
1491 | if par_level != 0: |
|
1491 | if par_level != 0: | |
1492 | continue |
|
1492 | continue | |
1493 |
|
1493 | |||
1494 | if next_token != '=': |
|
1494 | if next_token != '=': | |
1495 | continue |
|
1495 | continue | |
1496 |
|
1496 | |||
1497 | usedNamedArgs.add(token) |
|
1497 | usedNamedArgs.add(token) | |
1498 |
|
1498 | |||
1499 | # lookup the candidate callable matches either using global_matches |
|
1499 | # lookup the candidate callable matches either using global_matches | |
1500 | # or attr_matches for dotted names |
|
1500 | # or attr_matches for dotted names | |
1501 | if len(ids) == 1: |
|
1501 | if len(ids) == 1: | |
1502 | callableMatches = self.global_matches(ids[0]) |
|
1502 | callableMatches = self.global_matches(ids[0]) | |
1503 | else: |
|
1503 | else: | |
1504 | callableMatches = self.attr_matches('.'.join(ids[::-1])) |
|
1504 | callableMatches = self.attr_matches('.'.join(ids[::-1])) | |
1505 | argMatches = [] |
|
1505 | argMatches = [] | |
1506 | for callableMatch in callableMatches: |
|
1506 | for callableMatch in callableMatches: | |
1507 | try: |
|
1507 | try: | |
1508 | namedArgs = self._default_arguments(eval(callableMatch, |
|
1508 | namedArgs = self._default_arguments(eval(callableMatch, | |
1509 | self.namespace)) |
|
1509 | self.namespace)) | |
1510 | except: |
|
1510 | except: | |
1511 | continue |
|
1511 | continue | |
1512 |
|
1512 | |||
1513 | # Remove used named arguments from the list, no need to show twice |
|
1513 | # Remove used named arguments from the list, no need to show twice | |
1514 | for namedArg in set(namedArgs) - usedNamedArgs: |
|
1514 | for namedArg in set(namedArgs) - usedNamedArgs: | |
1515 | if namedArg.startswith(text): |
|
1515 | if namedArg.startswith(text): | |
1516 | argMatches.append(u"%s=" %namedArg) |
|
1516 | argMatches.append(u"%s=" %namedArg) | |
1517 | return argMatches |
|
1517 | return argMatches | |
1518 |
|
1518 | |||
1519 | def dict_key_matches(self, text): |
|
1519 | def dict_key_matches(self, text): | |
1520 | "Match string keys in a dictionary, after e.g. 'foo[' " |
|
1520 | "Match string keys in a dictionary, after e.g. 'foo[' " | |
1521 | def get_keys(obj): |
|
1521 | def get_keys(obj): | |
1522 | # Objects can define their own completions by defining an |
|
1522 | # Objects can define their own completions by defining an | |
1523 | # _ipy_key_completions_() method. |
|
1523 | # _ipy_key_completions_() method. | |
1524 | method = get_real_method(obj, '_ipython_key_completions_') |
|
1524 | method = get_real_method(obj, '_ipython_key_completions_') | |
1525 | if method is not None: |
|
1525 | if method is not None: | |
1526 | return method() |
|
1526 | return method() | |
1527 |
|
1527 | |||
1528 | # Special case some common in-memory dict-like types |
|
1528 | # Special case some common in-memory dict-like types | |
1529 | if isinstance(obj, dict) or\ |
|
1529 | if isinstance(obj, dict) or\ | |
1530 | _safe_isinstance(obj, 'pandas', 'DataFrame'): |
|
1530 | _safe_isinstance(obj, 'pandas', 'DataFrame'): | |
1531 | try: |
|
1531 | try: | |
1532 | return list(obj.keys()) |
|
1532 | return list(obj.keys()) | |
1533 | except Exception: |
|
1533 | except Exception: | |
1534 | return [] |
|
1534 | return [] | |
1535 | elif _safe_isinstance(obj, 'numpy', 'ndarray') or\ |
|
1535 | elif _safe_isinstance(obj, 'numpy', 'ndarray') or\ | |
1536 | _safe_isinstance(obj, 'numpy', 'void'): |
|
1536 | _safe_isinstance(obj, 'numpy', 'void'): | |
1537 | return obj.dtype.names or [] |
|
1537 | return obj.dtype.names or [] | |
1538 | return [] |
|
1538 | return [] | |
1539 |
|
1539 | |||
1540 | try: |
|
1540 | try: | |
1541 | regexps = self.__dict_key_regexps |
|
1541 | regexps = self.__dict_key_regexps | |
1542 | except AttributeError: |
|
1542 | except AttributeError: | |
1543 | dict_key_re_fmt = r'''(?x) |
|
1543 | dict_key_re_fmt = r'''(?x) | |
1544 | ( # match dict-referring expression wrt greedy setting |
|
1544 | ( # match dict-referring expression wrt greedy setting | |
1545 | %s |
|
1545 | %s | |
1546 | ) |
|
1546 | ) | |
1547 | \[ # open bracket |
|
1547 | \[ # open bracket | |
1548 | \s* # and optional whitespace |
|
1548 | \s* # and optional whitespace | |
1549 | ([uUbB]? # string prefix (r not handled) |
|
1549 | ([uUbB]? # string prefix (r not handled) | |
1550 | (?: # unclosed string |
|
1550 | (?: # unclosed string | |
1551 | '(?:[^']|(?<!\\)\\')* |
|
1551 | '(?:[^']|(?<!\\)\\')* | |
1552 | | |
|
1552 | | | |
1553 | "(?:[^"]|(?<!\\)\\")* |
|
1553 | "(?:[^"]|(?<!\\)\\")* | |
1554 | ) |
|
1554 | ) | |
1555 | )? |
|
1555 | )? | |
1556 | $ |
|
1556 | $ | |
1557 | ''' |
|
1557 | ''' | |
1558 | regexps = self.__dict_key_regexps = { |
|
1558 | regexps = self.__dict_key_regexps = { | |
1559 | False: re.compile(dict_key_re_fmt % ''' |
|
1559 | False: re.compile(dict_key_re_fmt % ''' | |
1560 | # identifiers separated by . |
|
1560 | # identifiers separated by . | |
1561 | (?!\d)\w+ |
|
1561 | (?!\d)\w+ | |
1562 | (?:\.(?!\d)\w+)* |
|
1562 | (?:\.(?!\d)\w+)* | |
1563 | '''), |
|
1563 | '''), | |
1564 | True: re.compile(dict_key_re_fmt % ''' |
|
1564 | True: re.compile(dict_key_re_fmt % ''' | |
1565 | .+ |
|
1565 | .+ | |
1566 | ''') |
|
1566 | ''') | |
1567 | } |
|
1567 | } | |
1568 |
|
1568 | |||
1569 | match = regexps[self.greedy].search(self.text_until_cursor) |
|
1569 | match = regexps[self.greedy].search(self.text_until_cursor) | |
1570 | if match is None: |
|
1570 | if match is None: | |
1571 | return [] |
|
1571 | return [] | |
1572 |
|
1572 | |||
1573 | expr, prefix = match.groups() |
|
1573 | expr, prefix = match.groups() | |
1574 | try: |
|
1574 | try: | |
1575 | obj = eval(expr, self.namespace) |
|
1575 | obj = eval(expr, self.namespace) | |
1576 | except Exception: |
|
1576 | except Exception: | |
1577 | try: |
|
1577 | try: | |
1578 | obj = eval(expr, self.global_namespace) |
|
1578 | obj = eval(expr, self.global_namespace) | |
1579 | except Exception: |
|
1579 | except Exception: | |
1580 | return [] |
|
1580 | return [] | |
1581 |
|
1581 | |||
1582 | keys = get_keys(obj) |
|
1582 | keys = get_keys(obj) | |
1583 | if not keys: |
|
1583 | if not keys: | |
1584 | return keys |
|
1584 | return keys | |
1585 | closing_quote, token_offset, matches = match_dict_keys(keys, prefix, self.splitter.delims) |
|
1585 | closing_quote, token_offset, matches = match_dict_keys(keys, prefix, self.splitter.delims) | |
1586 | if not matches: |
|
1586 | if not matches: | |
1587 | return matches |
|
1587 | return matches | |
1588 |
|
1588 | |||
1589 | # get the cursor position of |
|
1589 | # get the cursor position of | |
1590 | # - the text being completed |
|
1590 | # - the text being completed | |
1591 | # - the start of the key text |
|
1591 | # - the start of the key text | |
1592 | # - the start of the completion |
|
1592 | # - the start of the completion | |
1593 | text_start = len(self.text_until_cursor) - len(text) |
|
1593 | text_start = len(self.text_until_cursor) - len(text) | |
1594 | if prefix: |
|
1594 | if prefix: | |
1595 | key_start = match.start(2) |
|
1595 | key_start = match.start(2) | |
1596 | completion_start = key_start + token_offset |
|
1596 | completion_start = key_start + token_offset | |
1597 | else: |
|
1597 | else: | |
1598 | key_start = completion_start = match.end() |
|
1598 | key_start = completion_start = match.end() | |
1599 |
|
1599 | |||
1600 | # grab the leading prefix, to make sure all completions start with `text` |
|
1600 | # grab the leading prefix, to make sure all completions start with `text` | |
1601 | if text_start > key_start: |
|
1601 | if text_start > key_start: | |
1602 | leading = '' |
|
1602 | leading = '' | |
1603 | else: |
|
1603 | else: | |
1604 | leading = text[text_start:completion_start] |
|
1604 | leading = text[text_start:completion_start] | |
1605 |
|
1605 | |||
1606 | # the index of the `[` character |
|
1606 | # the index of the `[` character | |
1607 | bracket_idx = match.end(1) |
|
1607 | bracket_idx = match.end(1) | |
1608 |
|
1608 | |||
1609 | # append closing quote and bracket as appropriate |
|
1609 | # append closing quote and bracket as appropriate | |
1610 | # this is *not* appropriate if the opening quote or bracket is outside |
|
1610 | # this is *not* appropriate if the opening quote or bracket is outside | |
1611 | # the text given to this method |
|
1611 | # the text given to this method | |
1612 | suf = '' |
|
1612 | suf = '' | |
1613 | continuation = self.line_buffer[len(self.text_until_cursor):] |
|
1613 | continuation = self.line_buffer[len(self.text_until_cursor):] | |
1614 | if key_start > text_start and closing_quote: |
|
1614 | if key_start > text_start and closing_quote: | |
1615 | # quotes were opened inside text, maybe close them |
|
1615 | # quotes were opened inside text, maybe close them | |
1616 | if continuation.startswith(closing_quote): |
|
1616 | if continuation.startswith(closing_quote): | |
1617 | continuation = continuation[len(closing_quote):] |
|
1617 | continuation = continuation[len(closing_quote):] | |
1618 | else: |
|
1618 | else: | |
1619 | suf += closing_quote |
|
1619 | suf += closing_quote | |
1620 | if bracket_idx > text_start: |
|
1620 | if bracket_idx > text_start: | |
1621 | # brackets were opened inside text, maybe close them |
|
1621 | # brackets were opened inside text, maybe close them | |
1622 | if not continuation.startswith(']'): |
|
1622 | if not continuation.startswith(']'): | |
1623 | suf += ']' |
|
1623 | suf += ']' | |
1624 |
|
1624 | |||
1625 | return [leading + k + suf for k in matches] |
|
1625 | return [leading + k + suf for k in matches] | |
1626 |
|
1626 | |||
1627 | def unicode_name_matches(self, text): |
|
1627 | def unicode_name_matches(self, text): | |
1628 | u"""Match Latex-like syntax for unicode characters base |
|
1628 | u"""Match Latex-like syntax for unicode characters base | |
1629 | on the name of the character. |
|
1629 | on the name of the character. | |
1630 |
|
1630 | |||
1631 | This does ``\\GREEK SMALL LETTER ETA`` -> ``Ξ·`` |
|
1631 | This does ``\\GREEK SMALL LETTER ETA`` -> ``Ξ·`` | |
1632 |
|
1632 | |||
1633 | Works only on valid python 3 identifier, or on combining characters that |
|
1633 | Works only on valid python 3 identifier, or on combining characters that | |
1634 | will combine to form a valid identifier. |
|
1634 | will combine to form a valid identifier. | |
1635 |
|
1635 | |||
1636 | Used on Python 3 only. |
|
1636 | Used on Python 3 only. | |
1637 | """ |
|
1637 | """ | |
1638 | slashpos = text.rfind('\\') |
|
1638 | slashpos = text.rfind('\\') | |
1639 | if slashpos > -1: |
|
1639 | if slashpos > -1: | |
1640 | s = text[slashpos+1:] |
|
1640 | s = text[slashpos+1:] | |
1641 | try : |
|
1641 | try : | |
1642 | unic = unicodedata.lookup(s) |
|
1642 | unic = unicodedata.lookup(s) | |
1643 | # allow combining chars |
|
1643 | # allow combining chars | |
1644 | if ('a'+unic).isidentifier(): |
|
1644 | if ('a'+unic).isidentifier(): | |
1645 | return '\\'+s,[unic] |
|
1645 | return '\\'+s,[unic] | |
1646 | except KeyError: |
|
1646 | except KeyError: | |
1647 | pass |
|
1647 | pass | |
1648 | return u'', [] |
|
1648 | return u'', [] | |
1649 |
|
1649 | |||
1650 |
|
1650 | |||
1651 | def latex_matches(self, text): |
|
1651 | def latex_matches(self, text): | |
1652 | u"""Match Latex syntax for unicode characters. |
|
1652 | u"""Match Latex syntax for unicode characters. | |
1653 |
|
1653 | |||
1654 | This does both ``\\alp`` -> ``\\alpha`` and ``\\alpha`` -> ``Ξ±`` |
|
1654 | This does both ``\\alp`` -> ``\\alpha`` and ``\\alpha`` -> ``Ξ±`` | |
1655 |
|
1655 | |||
1656 | Used on Python 3 only. |
|
1656 | Used on Python 3 only. | |
1657 | """ |
|
1657 | """ | |
1658 | slashpos = text.rfind('\\') |
|
1658 | slashpos = text.rfind('\\') | |
1659 | if slashpos > -1: |
|
1659 | if slashpos > -1: | |
1660 | s = text[slashpos:] |
|
1660 | s = text[slashpos:] | |
1661 | if s in latex_symbols: |
|
1661 | if s in latex_symbols: | |
1662 | # Try to complete a full latex symbol to unicode |
|
1662 | # Try to complete a full latex symbol to unicode | |
1663 | # \\alpha -> Ξ± |
|
1663 | # \\alpha -> Ξ± | |
1664 | return s, [latex_symbols[s]] |
|
1664 | return s, [latex_symbols[s]] | |
1665 | else: |
|
1665 | else: | |
1666 | # If a user has partially typed a latex symbol, give them |
|
1666 | # If a user has partially typed a latex symbol, give them | |
1667 | # a full list of options \al -> [\aleph, \alpha] |
|
1667 | # a full list of options \al -> [\aleph, \alpha] | |
1668 | matches = [k for k in latex_symbols if k.startswith(s)] |
|
1668 | matches = [k for k in latex_symbols if k.startswith(s)] | |
1669 | return s, matches |
|
1669 | return s, matches | |
1670 | return u'', [] |
|
1670 | return u'', [] | |
1671 |
|
1671 | |||
1672 | def dispatch_custom_completer(self, text): |
|
1672 | def dispatch_custom_completer(self, text): | |
1673 | if not self.custom_completers: |
|
1673 | if not self.custom_completers: | |
1674 | return |
|
1674 | return | |
1675 |
|
1675 | |||
1676 | line = self.line_buffer |
|
1676 | line = self.line_buffer | |
1677 | if not line.strip(): |
|
1677 | if not line.strip(): | |
1678 | return None |
|
1678 | return None | |
1679 |
|
1679 | |||
1680 | # Create a little structure to pass all the relevant information about |
|
1680 | # Create a little structure to pass all the relevant information about | |
1681 | # the current completion to any custom completer. |
|
1681 | # the current completion to any custom completer. | |
1682 | event = SimpleNamespace() |
|
1682 | event = SimpleNamespace() | |
1683 | event.line = line |
|
1683 | event.line = line | |
1684 | event.symbol = text |
|
1684 | event.symbol = text | |
1685 | cmd = line.split(None,1)[0] |
|
1685 | cmd = line.split(None,1)[0] | |
1686 | event.command = cmd |
|
1686 | event.command = cmd | |
1687 | event.text_until_cursor = self.text_until_cursor |
|
1687 | event.text_until_cursor = self.text_until_cursor | |
1688 |
|
1688 | |||
1689 | # for foo etc, try also to find completer for %foo |
|
1689 | # for foo etc, try also to find completer for %foo | |
1690 | if not cmd.startswith(self.magic_escape): |
|
1690 | if not cmd.startswith(self.magic_escape): | |
1691 | try_magic = self.custom_completers.s_matches( |
|
1691 | try_magic = self.custom_completers.s_matches( | |
1692 | self.magic_escape + cmd) |
|
1692 | self.magic_escape + cmd) | |
1693 | else: |
|
1693 | else: | |
1694 | try_magic = [] |
|
1694 | try_magic = [] | |
1695 |
|
1695 | |||
1696 | for c in itertools.chain(self.custom_completers.s_matches(cmd), |
|
1696 | for c in itertools.chain(self.custom_completers.s_matches(cmd), | |
1697 | try_magic, |
|
1697 | try_magic, | |
1698 | self.custom_completers.flat_matches(self.text_until_cursor)): |
|
1698 | self.custom_completers.flat_matches(self.text_until_cursor)): | |
1699 | try: |
|
1699 | try: | |
1700 | res = c(event) |
|
1700 | res = c(event) | |
1701 | if res: |
|
1701 | if res: | |
1702 | # first, try case sensitive match |
|
1702 | # first, try case sensitive match | |
1703 | withcase = [r for r in res if r.startswith(text)] |
|
1703 | withcase = [r for r in res if r.startswith(text)] | |
1704 | if withcase: |
|
1704 | if withcase: | |
1705 | return withcase |
|
1705 | return withcase | |
1706 | # if none, then case insensitive ones are ok too |
|
1706 | # if none, then case insensitive ones are ok too | |
1707 | text_low = text.lower() |
|
1707 | text_low = text.lower() | |
1708 | return [r for r in res if r.lower().startswith(text_low)] |
|
1708 | return [r for r in res if r.lower().startswith(text_low)] | |
1709 | except TryNext: |
|
1709 | except TryNext: | |
1710 | pass |
|
1710 | pass | |
1711 |
|
1711 | |||
1712 | return None |
|
1712 | return None | |
1713 |
|
1713 | |||
1714 | def completions(self, text: str, offset: int)->Iterator[Completion]: |
|
1714 | def completions(self, text: str, offset: int)->Iterator[Completion]: | |
1715 | """ |
|
1715 | """ | |
1716 | Returns an iterator over the possible completions |
|
1716 | Returns an iterator over the possible completions | |
1717 |
|
1717 | |||
1718 | .. warning:: Unstable |
|
1718 | .. warning:: Unstable | |
1719 |
|
1719 | |||
1720 | This function is unstable, API may change without warning. |
|
1720 | This function is unstable, API may change without warning. | |
1721 | It will also raise unless use in proper context manager. |
|
1721 | It will also raise unless use in proper context manager. | |
1722 |
|
1722 | |||
1723 | Parameters |
|
1723 | Parameters | |
1724 | ---------- |
|
1724 | ---------- | |
1725 |
|
1725 | |||
1726 | text:str |
|
1726 | text:str | |
1727 | Full text of the current input, multi line string. |
|
1727 | Full text of the current input, multi line string. | |
1728 | offset:int |
|
1728 | offset:int | |
1729 | Integer representing the position of the cursor in ``text``. Offset |
|
1729 | Integer representing the position of the cursor in ``text``. Offset | |
1730 | is 0-based indexed. |
|
1730 | is 0-based indexed. | |
1731 |
|
1731 | |||
1732 | Yields |
|
1732 | Yields | |
1733 | ------ |
|
1733 | ------ | |
1734 | :any:`Completion` object |
|
1734 | :any:`Completion` object | |
1735 |
|
1735 | |||
1736 |
|
1736 | |||
1737 | The cursor on a text can either be seen as being "in between" |
|
1737 | The cursor on a text can either be seen as being "in between" | |
1738 | characters or "On" a character depending on the interface visible to |
|
1738 | characters or "On" a character depending on the interface visible to | |
1739 | the user. For consistency the cursor being on "in between" characters X |
|
1739 | the user. For consistency the cursor being on "in between" characters X | |
1740 | and Y is equivalent to the cursor being "on" character Y, that is to say |
|
1740 | and Y is equivalent to the cursor being "on" character Y, that is to say | |
1741 | the character the cursor is on is considered as being after the cursor. |
|
1741 | the character the cursor is on is considered as being after the cursor. | |
1742 |
|
1742 | |||
1743 | Combining characters may span more that one position in the |
|
1743 | Combining characters may span more that one position in the | |
1744 | text. |
|
1744 | text. | |
1745 |
|
1745 | |||
1746 |
|
1746 | |||
1747 | .. note:: |
|
1747 | .. note:: | |
1748 |
|
1748 | |||
1749 | If ``IPCompleter.debug`` is :any:`True` will yield a ``--jedi/ipython--`` |
|
1749 | If ``IPCompleter.debug`` is :any:`True` will yield a ``--jedi/ipython--`` | |
1750 | fake Completion token to distinguish completion returned by Jedi |
|
1750 | fake Completion token to distinguish completion returned by Jedi | |
1751 | and usual IPython completion. |
|
1751 | and usual IPython completion. | |
1752 |
|
1752 | |||
1753 | .. note:: |
|
1753 | .. note:: | |
1754 |
|
1754 | |||
1755 | Completions are not completely deduplicated yet. If identical |
|
1755 | Completions are not completely deduplicated yet. If identical | |
1756 | completions are coming from different sources this function does not |
|
1756 | completions are coming from different sources this function does not | |
1757 | ensure that each completion object will only be present once. |
|
1757 | ensure that each completion object will only be present once. | |
1758 | """ |
|
1758 | """ | |
1759 | warnings.warn("_complete is a provisional API (as of IPython 6.0). " |
|
1759 | warnings.warn("_complete is a provisional API (as of IPython 6.0). " | |
1760 | "It may change without warnings. " |
|
1760 | "It may change without warnings. " | |
1761 | "Use in corresponding context manager.", |
|
1761 | "Use in corresponding context manager.", | |
1762 | category=ProvisionalCompleterWarning, stacklevel=2) |
|
1762 | category=ProvisionalCompleterWarning, stacklevel=2) | |
1763 |
|
1763 | |||
1764 | seen = set() |
|
1764 | seen = set() | |
1765 | for c in self._completions(text, offset, _timeout=self.jedi_compute_type_timeout/1000): |
|
1765 | for c in self._completions(text, offset, _timeout=self.jedi_compute_type_timeout/1000): | |
1766 | if c and (c in seen): |
|
1766 | if c and (c in seen): | |
1767 | continue |
|
1767 | continue | |
1768 | yield c |
|
1768 | yield c | |
1769 | seen.add(c) |
|
1769 | seen.add(c) | |
1770 |
|
1770 | |||
1771 | def _completions(self, full_text: str, offset: int, *, _timeout)->Iterator[Completion]: |
|
1771 | def _completions(self, full_text: str, offset: int, *, _timeout)->Iterator[Completion]: | |
1772 | """ |
|
1772 | """ | |
1773 | Core completion module.Same signature as :any:`completions`, with the |
|
1773 | Core completion module.Same signature as :any:`completions`, with the | |
1774 | extra `timeout` parameter (in seconds). |
|
1774 | extra `timeout` parameter (in seconds). | |
1775 |
|
1775 | |||
1776 |
|
1776 | |||
1777 | Computing jedi's completion ``.type`` can be quite expensive (it is a |
|
1777 | Computing jedi's completion ``.type`` can be quite expensive (it is a | |
1778 | lazy property) and can require some warm-up, more warm up than just |
|
1778 | lazy property) and can require some warm-up, more warm up than just | |
1779 | computing the ``name`` of a completion. The warm-up can be : |
|
1779 | computing the ``name`` of a completion. The warm-up can be : | |
1780 |
|
1780 | |||
1781 | - Long warm-up the first time a module is encountered after |
|
1781 | - Long warm-up the first time a module is encountered after | |
1782 | install/update: actually build parse/inference tree. |
|
1782 | install/update: actually build parse/inference tree. | |
1783 |
|
1783 | |||
1784 | - first time the module is encountered in a session: load tree from |
|
1784 | - first time the module is encountered in a session: load tree from | |
1785 | disk. |
|
1785 | disk. | |
1786 |
|
1786 | |||
1787 | We don't want to block completions for tens of seconds so we give the |
|
1787 | We don't want to block completions for tens of seconds so we give the | |
1788 | completer a "budget" of ``_timeout`` seconds per invocation to compute |
|
1788 | completer a "budget" of ``_timeout`` seconds per invocation to compute | |
1789 | completions types, the completions that have not yet been computed will |
|
1789 | completions types, the completions that have not yet been computed will | |
1790 | be marked as "unknown" an will have a chance to be computed next round |
|
1790 | be marked as "unknown" an will have a chance to be computed next round | |
1791 | are things get cached. |
|
1791 | are things get cached. | |
1792 |
|
1792 | |||
1793 | Keep in mind that Jedi is not the only thing treating the completion so |
|
1793 | Keep in mind that Jedi is not the only thing treating the completion so | |
1794 | keep the timeout short-ish as if we take more than 0.3 second we still |
|
1794 | keep the timeout short-ish as if we take more than 0.3 second we still | |
1795 | have lots of processing to do. |
|
1795 | have lots of processing to do. | |
1796 |
|
1796 | |||
1797 | """ |
|
1797 | """ | |
1798 | deadline = time.monotonic() + _timeout |
|
1798 | deadline = time.monotonic() + _timeout | |
1799 |
|
1799 | |||
1800 |
|
1800 | |||
1801 | before = full_text[:offset] |
|
1801 | before = full_text[:offset] | |
1802 | cursor_line, cursor_column = position_to_cursor(full_text, offset) |
|
1802 | cursor_line, cursor_column = position_to_cursor(full_text, offset) | |
1803 |
|
1803 | |||
1804 | matched_text, matches, matches_origin, jedi_matches = self._complete( |
|
1804 | matched_text, matches, matches_origin, jedi_matches = self._complete( | |
1805 | full_text=full_text, cursor_line=cursor_line, cursor_pos=cursor_column) |
|
1805 | full_text=full_text, cursor_line=cursor_line, cursor_pos=cursor_column) | |
1806 |
|
1806 | |||
1807 | iter_jm = iter(jedi_matches) |
|
1807 | iter_jm = iter(jedi_matches) | |
1808 | if _timeout: |
|
1808 | if _timeout: | |
1809 | for jm in iter_jm: |
|
1809 | for jm in iter_jm: | |
1810 | try: |
|
1810 | try: | |
1811 | type_ = jm.type |
|
1811 | type_ = jm.type | |
1812 | except Exception: |
|
1812 | except Exception: | |
1813 | if self.debug: |
|
1813 | if self.debug: | |
1814 | print("Error in Jedi getting type of ", jm) |
|
1814 | print("Error in Jedi getting type of ", jm) | |
1815 | type_ = None |
|
1815 | type_ = None | |
1816 | delta = len(jm.name_with_symbols) - len(jm.complete) |
|
1816 | delta = len(jm.name_with_symbols) - len(jm.complete) | |
1817 | if type_ == 'function': |
|
1817 | if type_ == 'function': | |
1818 | signature = _make_signature(jm) |
|
1818 | signature = _make_signature(jm) | |
1819 | else: |
|
1819 | else: | |
1820 | signature = '' |
|
1820 | signature = '' | |
1821 | yield Completion(start=offset - delta, |
|
1821 | yield Completion(start=offset - delta, | |
1822 | end=offset, |
|
1822 | end=offset, | |
1823 | text=jm.name_with_symbols, |
|
1823 | text=jm.name_with_symbols, | |
1824 | type=type_, |
|
1824 | type=type_, | |
1825 | signature=signature, |
|
1825 | signature=signature, | |
1826 | _origin='jedi') |
|
1826 | _origin='jedi') | |
1827 |
|
1827 | |||
1828 | if time.monotonic() > deadline: |
|
1828 | if time.monotonic() > deadline: | |
1829 | break |
|
1829 | break | |
1830 |
|
1830 | |||
1831 | for jm in iter_jm: |
|
1831 | for jm in iter_jm: | |
1832 | delta = len(jm.name_with_symbols) - len(jm.complete) |
|
1832 | delta = len(jm.name_with_symbols) - len(jm.complete) | |
1833 | yield Completion(start=offset - delta, |
|
1833 | yield Completion(start=offset - delta, | |
1834 | end=offset, |
|
1834 | end=offset, | |
1835 | text=jm.name_with_symbols, |
|
1835 | text=jm.name_with_symbols, | |
1836 | type='<unknown>', # don't compute type for speed |
|
1836 | type='<unknown>', # don't compute type for speed | |
1837 | _origin='jedi', |
|
1837 | _origin='jedi', | |
1838 | signature='') |
|
1838 | signature='') | |
1839 |
|
1839 | |||
1840 |
|
1840 | |||
1841 | start_offset = before.rfind(matched_text) |
|
1841 | start_offset = before.rfind(matched_text) | |
1842 |
|
1842 | |||
1843 | # TODO: |
|
1843 | # TODO: | |
1844 | # Supress this, right now just for debug. |
|
1844 | # Supress this, right now just for debug. | |
1845 | if jedi_matches and matches and self.debug: |
|
1845 | if jedi_matches and matches and self.debug: | |
1846 | yield Completion(start=start_offset, end=offset, text='--jedi/ipython--', |
|
1846 | yield Completion(start=start_offset, end=offset, text='--jedi/ipython--', | |
1847 | _origin='debug', type='none', signature='') |
|
1847 | _origin='debug', type='none', signature='') | |
1848 |
|
1848 | |||
1849 | # I'm unsure if this is always true, so let's assert and see if it |
|
1849 | # I'm unsure if this is always true, so let's assert and see if it | |
1850 | # crash |
|
1850 | # crash | |
1851 | assert before.endswith(matched_text) |
|
1851 | assert before.endswith(matched_text) | |
1852 | for m, t in zip(matches, matches_origin): |
|
1852 | for m, t in zip(matches, matches_origin): | |
1853 | yield Completion(start=start_offset, end=offset, text=m, _origin=t, signature='', type='<unknown>') |
|
1853 | yield Completion(start=start_offset, end=offset, text=m, _origin=t, signature='', type='<unknown>') | |
1854 |
|
1854 | |||
1855 |
|
1855 | |||
1856 | def complete(self, text=None, line_buffer=None, cursor_pos=None): |
|
1856 | def complete(self, text=None, line_buffer=None, cursor_pos=None): | |
1857 | """Find completions for the given text and line context. |
|
1857 | """Find completions for the given text and line context. | |
1858 |
|
1858 | |||
1859 | Note that both the text and the line_buffer are optional, but at least |
|
1859 | Note that both the text and the line_buffer are optional, but at least | |
1860 | one of them must be given. |
|
1860 | one of them must be given. | |
1861 |
|
1861 | |||
1862 | Parameters |
|
1862 | Parameters | |
1863 | ---------- |
|
1863 | ---------- | |
1864 | text : string, optional |
|
1864 | text : string, optional | |
1865 | Text to perform the completion on. If not given, the line buffer |
|
1865 | Text to perform the completion on. If not given, the line buffer | |
1866 | is split using the instance's CompletionSplitter object. |
|
1866 | is split using the instance's CompletionSplitter object. | |
1867 |
|
1867 | |||
1868 | line_buffer : string, optional |
|
1868 | line_buffer : string, optional | |
1869 | If not given, the completer attempts to obtain the current line |
|
1869 | If not given, the completer attempts to obtain the current line | |
1870 | buffer via readline. This keyword allows clients which are |
|
1870 | buffer via readline. This keyword allows clients which are | |
1871 | requesting for text completions in non-readline contexts to inform |
|
1871 | requesting for text completions in non-readline contexts to inform | |
1872 | the completer of the entire text. |
|
1872 | the completer of the entire text. | |
1873 |
|
1873 | |||
1874 | cursor_pos : int, optional |
|
1874 | cursor_pos : int, optional | |
1875 | Index of the cursor in the full line buffer. Should be provided by |
|
1875 | Index of the cursor in the full line buffer. Should be provided by | |
1876 | remote frontends where kernel has no access to frontend state. |
|
1876 | remote frontends where kernel has no access to frontend state. | |
1877 |
|
1877 | |||
1878 | Returns |
|
1878 | Returns | |
1879 | ------- |
|
1879 | ------- | |
1880 | text : str |
|
1880 | text : str | |
1881 | Text that was actually used in the completion. |
|
1881 | Text that was actually used in the completion. | |
1882 |
|
1882 | |||
1883 | matches : list |
|
1883 | matches : list | |
1884 | A list of completion matches. |
|
1884 | A list of completion matches. | |
1885 |
|
1885 | |||
1886 |
|
1886 | |||
1887 | .. note:: |
|
1887 | .. note:: | |
1888 |
|
1888 | |||
1889 | This API is likely to be deprecated and replaced by |
|
1889 | This API is likely to be deprecated and replaced by | |
1890 | :any:`IPCompleter.completions` in the future. |
|
1890 | :any:`IPCompleter.completions` in the future. | |
1891 |
|
1891 | |||
1892 |
|
1892 | |||
1893 | """ |
|
1893 | """ | |
1894 | warnings.warn('`Completer.complete` is pending deprecation since ' |
|
1894 | warnings.warn('`Completer.complete` is pending deprecation since ' | |
1895 | 'IPython 6.0 and will be replaced by `Completer.completions`.', |
|
1895 | 'IPython 6.0 and will be replaced by `Completer.completions`.', | |
1896 | PendingDeprecationWarning) |
|
1896 | PendingDeprecationWarning) | |
1897 | # potential todo, FOLD the 3rd throw away argument of _complete |
|
1897 | # potential todo, FOLD the 3rd throw away argument of _complete | |
1898 | # into the first 2 one. |
|
1898 | # into the first 2 one. | |
1899 | return self._complete(line_buffer=line_buffer, cursor_pos=cursor_pos, text=text, cursor_line=0)[:2] |
|
1899 | return self._complete(line_buffer=line_buffer, cursor_pos=cursor_pos, text=text, cursor_line=0)[:2] | |
1900 |
|
1900 | |||
1901 | def _complete(self, *, cursor_line, cursor_pos, line_buffer=None, text=None, |
|
1901 | def _complete(self, *, cursor_line, cursor_pos, line_buffer=None, text=None, | |
1902 | full_text=None, return_jedi_results=True) -> Tuple[str, List[str], List[str], Iterable[_FakeJediCompletion]]: |
|
1902 | full_text=None, return_jedi_results=True) -> Tuple[str, List[str], List[str], Iterable[_FakeJediCompletion]]: | |
1903 | """ |
|
1903 | """ | |
1904 |
|
1904 | |||
1905 | Like complete but can also returns raw jedi completions as well as the |
|
1905 | Like complete but can also returns raw jedi completions as well as the | |
1906 | origin of the completion text. This could (and should) be made much |
|
1906 | origin of the completion text. This could (and should) be made much | |
1907 | cleaner but that will be simpler once we drop the old (and stateful) |
|
1907 | cleaner but that will be simpler once we drop the old (and stateful) | |
1908 | :any:`complete` API. |
|
1908 | :any:`complete` API. | |
1909 |
|
1909 | |||
1910 |
|
1910 | |||
1911 | With current provisional API, cursor_pos act both (depending on the |
|
1911 | With current provisional API, cursor_pos act both (depending on the | |
1912 | caller) as the offset in the ``text`` or ``line_buffer``, or as the |
|
1912 | caller) as the offset in the ``text`` or ``line_buffer``, or as the | |
1913 | ``column`` when passing multiline strings this could/should be renamed |
|
1913 | ``column`` when passing multiline strings this could/should be renamed | |
1914 | but would add extra noise. |
|
1914 | but would add extra noise. | |
1915 | """ |
|
1915 | """ | |
1916 |
|
1916 | |||
1917 | # if the cursor position isn't given, the only sane assumption we can |
|
1917 | # if the cursor position isn't given, the only sane assumption we can | |
1918 | # make is that it's at the end of the line (the common case) |
|
1918 | # make is that it's at the end of the line (the common case) | |
1919 | if cursor_pos is None: |
|
1919 | if cursor_pos is None: | |
1920 | cursor_pos = len(line_buffer) if text is None else len(text) |
|
1920 | cursor_pos = len(line_buffer) if text is None else len(text) | |
1921 |
|
1921 | |||
1922 | if self.use_main_ns: |
|
1922 | if self.use_main_ns: | |
1923 | self.namespace = __main__.__dict__ |
|
1923 | self.namespace = __main__.__dict__ | |
1924 |
|
1924 | |||
1925 | # if text is either None or an empty string, rely on the line buffer |
|
1925 | # if text is either None or an empty string, rely on the line buffer | |
1926 | if (not line_buffer) and full_text: |
|
1926 | if (not line_buffer) and full_text: | |
1927 | line_buffer = full_text.split('\n')[cursor_line] |
|
1927 | line_buffer = full_text.split('\n')[cursor_line] | |
1928 | if not text: |
|
1928 | if not text: | |
1929 | text = self.splitter.split_line(line_buffer, cursor_pos) |
|
1929 | text = self.splitter.split_line(line_buffer, cursor_pos) | |
1930 |
|
1930 | |||
1931 | if self.backslash_combining_completions: |
|
1931 | if self.backslash_combining_completions: | |
1932 | # allow deactivation of these on windows. |
|
1932 | # allow deactivation of these on windows. | |
1933 | base_text = text if not line_buffer else line_buffer[:cursor_pos] |
|
1933 | base_text = text if not line_buffer else line_buffer[:cursor_pos] | |
1934 | latex_text, latex_matches = self.latex_matches(base_text) |
|
1934 | latex_text, latex_matches = self.latex_matches(base_text) | |
1935 | if latex_matches: |
|
1935 | if latex_matches: | |
1936 | return latex_text, latex_matches, ['latex_matches']*len(latex_matches), () |
|
1936 | return latex_text, latex_matches, ['latex_matches']*len(latex_matches), () | |
1937 | name_text = '' |
|
1937 | name_text = '' | |
1938 | name_matches = [] |
|
1938 | name_matches = [] | |
1939 | for meth in (self.unicode_name_matches, back_latex_name_matches, back_unicode_name_matches): |
|
1939 | for meth in (self.unicode_name_matches, back_latex_name_matches, back_unicode_name_matches): | |
1940 | name_text, name_matches = meth(base_text) |
|
1940 | name_text, name_matches = meth(base_text) | |
1941 | if name_text: |
|
1941 | if name_text: | |
1942 | return name_text, name_matches, [meth.__qualname__]*len(name_matches), () |
|
1942 | return name_text, name_matches, [meth.__qualname__]*len(name_matches), () | |
1943 |
|
1943 | |||
1944 |
|
1944 | |||
1945 | # If no line buffer is given, assume the input text is all there was |
|
1945 | # If no line buffer is given, assume the input text is all there was | |
1946 | if line_buffer is None: |
|
1946 | if line_buffer is None: | |
1947 | line_buffer = text |
|
1947 | line_buffer = text | |
1948 |
|
1948 | |||
1949 | self.line_buffer = line_buffer |
|
1949 | self.line_buffer = line_buffer | |
1950 | self.text_until_cursor = self.line_buffer[:cursor_pos] |
|
1950 | self.text_until_cursor = self.line_buffer[:cursor_pos] | |
1951 |
|
1951 | |||
1952 | # Do magic arg matches |
|
1952 | # Do magic arg matches | |
1953 | for matcher in self.magic_arg_matchers: |
|
1953 | for matcher in self.magic_arg_matchers: | |
1954 | matches = [(m, matcher.__qualname__) for m in matcher(line_buffer)] |
|
1954 | matches = [(m, matcher.__qualname__) for m in matcher(line_buffer)] | |
1955 | if matches: |
|
1955 | if matches: | |
1956 | matches2 = [m[0] for m in matches] |
|
1956 | matches2 = [m[0] for m in matches] | |
1957 | origins = [m[1] for m in matches] |
|
1957 | origins = [m[1] for m in matches] | |
1958 | return text, matches2, origins, () |
|
1958 | return text, matches2, origins, () | |
1959 |
|
1959 | |||
1960 | # Start with a clean slate of completions |
|
1960 | # Start with a clean slate of completions | |
1961 | matches = [] |
|
1961 | matches = [] | |
1962 | custom_res = self.dispatch_custom_completer(text) |
|
1962 | custom_res = self.dispatch_custom_completer(text) | |
1963 | # FIXME: we should extend our api to return a dict with completions for |
|
1963 | # FIXME: we should extend our api to return a dict with completions for | |
1964 | # different types of objects. The rlcomplete() method could then |
|
1964 | # different types of objects. The rlcomplete() method could then | |
1965 | # simply collapse the dict into a list for readline, but we'd have |
|
1965 | # simply collapse the dict into a list for readline, but we'd have | |
1966 | # richer completion semantics in other evironments. |
|
1966 | # richer completion semantics in other evironments. | |
1967 | completions = () |
|
1967 | completions = () | |
1968 | if self.use_jedi and return_jedi_results: |
|
1968 | if self.use_jedi and return_jedi_results: | |
1969 | if not full_text: |
|
1969 | if not full_text: | |
1970 | full_text = line_buffer |
|
1970 | full_text = line_buffer | |
1971 | completions = self._jedi_matches( |
|
1971 | completions = self._jedi_matches( | |
1972 | cursor_pos, cursor_line, full_text) |
|
1972 | cursor_pos, cursor_line, full_text) | |
1973 | if custom_res is not None: |
|
1973 | if custom_res is not None: | |
1974 | # did custom completers produce something? |
|
1974 | # did custom completers produce something? | |
1975 | matches = [(m, 'custom') for m in custom_res] |
|
1975 | matches = [(m, 'custom') for m in custom_res] | |
1976 | else: |
|
1976 | else: | |
1977 | # Extend the list of completions with the results of each |
|
1977 | # Extend the list of completions with the results of each | |
1978 | # matcher, so we return results to the user from all |
|
1978 | # matcher, so we return results to the user from all | |
1979 | # namespaces. |
|
1979 | # namespaces. | |
1980 | if self.merge_completions: |
|
1980 | if self.merge_completions: | |
1981 | matches = [] |
|
1981 | matches = [] | |
1982 | for matcher in self.matchers: |
|
1982 | for matcher in self.matchers: | |
1983 | try: |
|
1983 | try: | |
1984 | matches.extend([(m, matcher.__qualname__) |
|
1984 | matches.extend([(m, matcher.__qualname__) | |
1985 | for m in matcher(text)]) |
|
1985 | for m in matcher(text)]) | |
1986 | except: |
|
1986 | except: | |
1987 | # Show the ugly traceback if the matcher causes an |
|
1987 | # Show the ugly traceback if the matcher causes an | |
1988 | # exception, but do NOT crash the kernel! |
|
1988 | # exception, but do NOT crash the kernel! | |
1989 | sys.excepthook(*sys.exc_info()) |
|
1989 | sys.excepthook(*sys.exc_info()) | |
1990 | else: |
|
1990 | else: | |
1991 | for matcher in self.matchers: |
|
1991 | for matcher in self.matchers: | |
1992 | matches = [(m, matcher.__qualname__) |
|
1992 | matches = [(m, matcher.__qualname__) | |
1993 | for m in matcher(text)] |
|
1993 | for m in matcher(text)] | |
1994 | if matches: |
|
1994 | if matches: | |
1995 | break |
|
1995 | break | |
1996 | seen = set() |
|
1996 | seen = set() | |
1997 | filtered_matches = set() |
|
1997 | filtered_matches = set() | |
1998 | for m in matches: |
|
1998 | for m in matches: | |
1999 | t, c = m |
|
1999 | t, c = m | |
2000 | if t not in seen: |
|
2000 | if t not in seen: | |
2001 | filtered_matches.add(m) |
|
2001 | filtered_matches.add(m) | |
2002 | seen.add(t) |
|
2002 | seen.add(t) | |
2003 |
|
2003 | |||
2004 | _filtered_matches = sorted( |
|
2004 | _filtered_matches = sorted( | |
2005 | set(filtered_matches), key=lambda x: completions_sorting_key(x[0])) |
|
2005 | set(filtered_matches), key=lambda x: completions_sorting_key(x[0])) | |
2006 |
|
2006 | |||
2007 | _matches = [m[0] for m in _filtered_matches] |
|
2007 | _matches = [m[0] for m in _filtered_matches] | |
2008 | origins = [m[1] for m in _filtered_matches] |
|
2008 | origins = [m[1] for m in _filtered_matches] | |
2009 |
|
2009 | |||
2010 | self.matches = _matches |
|
2010 | self.matches = _matches | |
2011 |
|
2011 | |||
2012 | return text, _matches, origins, completions |
|
2012 | return text, _matches, origins, completions |
@@ -1,1178 +1,1178 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 | """ |
|
2 | """ | |
3 | Sphinx directive to support embedded IPython code. |
|
3 | Sphinx directive to support embedded IPython code. | |
4 |
|
4 | |||
5 | This directive allows pasting of entire interactive IPython sessions, prompts |
|
5 | This directive allows pasting of entire interactive IPython sessions, prompts | |
6 | and all, and their code will actually get re-executed at doc build time, with |
|
6 | and all, and their code will actually get re-executed at doc build time, with | |
7 | all prompts renumbered sequentially. It also allows you to input code as a pure |
|
7 | all prompts renumbered sequentially. It also allows you to input code as a pure | |
8 | python input by giving the argument python to the directive. The output looks |
|
8 | python input by giving the argument python to the directive. The output looks | |
9 | like an interactive ipython section. |
|
9 | like an interactive ipython section. | |
10 |
|
10 | |||
11 | To enable this directive, simply list it in your Sphinx ``conf.py`` file |
|
11 | To enable this directive, simply list it in your Sphinx ``conf.py`` file | |
12 | (making sure the directory where you placed it is visible to sphinx, as is |
|
12 | (making sure the directory where you placed it is visible to sphinx, as is | |
13 | needed for all Sphinx directives). For example, to enable syntax highlighting |
|
13 | needed for all Sphinx directives). For example, to enable syntax highlighting | |
14 | and the IPython directive:: |
|
14 | and the IPython directive:: | |
15 |
|
15 | |||
16 | extensions = ['IPython.sphinxext.ipython_console_highlighting', |
|
16 | extensions = ['IPython.sphinxext.ipython_console_highlighting', | |
17 | 'IPython.sphinxext.ipython_directive'] |
|
17 | 'IPython.sphinxext.ipython_directive'] | |
18 |
|
18 | |||
19 | The IPython directive outputs code-blocks with the language 'ipython'. So |
|
19 | The IPython directive outputs code-blocks with the language 'ipython'. So | |
20 | if you do not have the syntax highlighting extension enabled as well, then |
|
20 | if you do not have the syntax highlighting extension enabled as well, then | |
21 | all rendered code-blocks will be uncolored. By default this directive assumes |
|
21 | all rendered code-blocks will be uncolored. By default this directive assumes | |
22 | that your prompts are unchanged IPython ones, but this can be customized. |
|
22 | that your prompts are unchanged IPython ones, but this can be customized. | |
23 | The configurable options that can be placed in conf.py are: |
|
23 | The configurable options that can be placed in conf.py are: | |
24 |
|
24 | |||
25 | ipython_savefig_dir: |
|
25 | ipython_savefig_dir: | |
26 | The directory in which to save the figures. This is relative to the |
|
26 | The directory in which to save the figures. This is relative to the | |
27 | Sphinx source directory. The default is `html_static_path`. |
|
27 | Sphinx source directory. The default is `html_static_path`. | |
28 | ipython_rgxin: |
|
28 | ipython_rgxin: | |
29 | The compiled regular expression to denote the start of IPython input |
|
29 | The compiled regular expression to denote the start of IPython input | |
30 | lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You |
|
30 | lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You | |
31 | shouldn't need to change this. |
|
31 | shouldn't need to change this. | |
32 | ipython_rgxout: |
|
32 | ipython_rgxout: | |
33 | The compiled regular expression to denote the start of IPython output |
|
33 | The compiled regular expression to denote the start of IPython output | |
34 | lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You |
|
34 | lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You | |
35 | shouldn't need to change this. |
|
35 | shouldn't need to change this. | |
36 | ipython_promptin: |
|
36 | ipython_promptin: | |
37 | The string to represent the IPython input prompt in the generated ReST. |
|
37 | The string to represent the IPython input prompt in the generated ReST. | |
38 | The default is 'In [%d]:'. This expects that the line numbers are used |
|
38 | The default is 'In [%d]:'. This expects that the line numbers are used | |
39 | in the prompt. |
|
39 | in the prompt. | |
40 | ipython_promptout: |
|
40 | ipython_promptout: | |
41 | The string to represent the IPython prompt in the generated ReST. The |
|
41 | The string to represent the IPython prompt in the generated ReST. The | |
42 | default is 'Out [%d]:'. This expects that the line numbers are used |
|
42 | default is 'Out [%d]:'. This expects that the line numbers are used | |
43 | in the prompt. |
|
43 | in the prompt. | |
44 | ipython_mplbackend: |
|
44 | ipython_mplbackend: | |
45 | The string which specifies if the embedded Sphinx shell should import |
|
45 | The string which specifies if the embedded Sphinx shell should import | |
46 | Matplotlib and set the backend. The value specifies a backend that is |
|
46 | Matplotlib and set the backend. The value specifies a backend that is | |
47 | passed to `matplotlib.use()` before any lines in `ipython_execlines` are |
|
47 | passed to `matplotlib.use()` before any lines in `ipython_execlines` are | |
48 | executed. If not specified in conf.py, then the default value of 'agg' is |
|
48 | executed. If not specified in conf.py, then the default value of 'agg' is | |
49 | used. To use the IPython directive without matplotlib as a dependency, set |
|
49 | used. To use the IPython directive without matplotlib as a dependency, set | |
50 | the value to `None`. It may end up that matplotlib is still imported |
|
50 | the value to `None`. It may end up that matplotlib is still imported | |
51 | if the user specifies so in `ipython_execlines` or makes use of the |
|
51 | if the user specifies so in `ipython_execlines` or makes use of the | |
52 | @savefig pseudo decorator. |
|
52 | @savefig pseudo decorator. | |
53 | ipython_execlines: |
|
53 | ipython_execlines: | |
54 | A list of strings to be exec'd in the embedded Sphinx shell. Typical |
|
54 | A list of strings to be exec'd in the embedded Sphinx shell. Typical | |
55 | usage is to make certain packages always available. Set this to an empty |
|
55 | usage is to make certain packages always available. Set this to an empty | |
56 | list if you wish to have no imports always available. If specified in |
|
56 | list if you wish to have no imports always available. If specified in | |
57 | conf.py as `None`, then it has the effect of making no imports available. |
|
57 | conf.py as `None`, then it has the effect of making no imports available. | |
58 | If omitted from conf.py altogether, then the default value of |
|
58 | If omitted from conf.py altogether, then the default value of | |
59 | ['import numpy as np', 'import matplotlib.pyplot as plt'] is used. |
|
59 | ['import numpy as np', 'import matplotlib.pyplot as plt'] is used. | |
60 | ipython_holdcount |
|
60 | ipython_holdcount | |
61 | When the @suppress pseudo-decorator is used, the execution count can be |
|
61 | When the @suppress pseudo-decorator is used, the execution count can be | |
62 | incremented or not. The default behavior is to hold the execution count, |
|
62 | incremented or not. The default behavior is to hold the execution count, | |
63 | corresponding to a value of `True`. Set this to `False` to increment |
|
63 | corresponding to a value of `True`. Set this to `False` to increment | |
64 | the execution count after each suppressed command. |
|
64 | the execution count after each suppressed command. | |
65 |
|
65 | |||
66 | As an example, to use the IPython directive when `matplotlib` is not available, |
|
66 | As an example, to use the IPython directive when `matplotlib` is not available, | |
67 | one sets the backend to `None`:: |
|
67 | one sets the backend to `None`:: | |
68 |
|
68 | |||
69 | ipython_mplbackend = None |
|
69 | ipython_mplbackend = None | |
70 |
|
70 | |||
71 | An example usage of the directive is: |
|
71 | An example usage of the directive is: | |
72 |
|
72 | |||
73 | .. code-block:: rst |
|
73 | .. code-block:: rst | |
74 |
|
74 | |||
75 | .. ipython:: |
|
75 | .. ipython:: | |
76 |
|
76 | |||
77 | In [1]: x = 1 |
|
77 | In [1]: x = 1 | |
78 |
|
78 | |||
79 | In [2]: y = x**2 |
|
79 | In [2]: y = x**2 | |
80 |
|
80 | |||
81 | In [3]: print(y) |
|
81 | In [3]: print(y) | |
82 |
|
82 | |||
83 | See http://matplotlib.org/sampledoc/ipython_directive.html for additional |
|
83 | See http://matplotlib.org/sampledoc/ipython_directive.html for additional | |
84 | documentation. |
|
84 | documentation. | |
85 |
|
85 | |||
86 | Pseudo-Decorators |
|
86 | Pseudo-Decorators | |
87 | ================= |
|
87 | ================= | |
88 |
|
88 | |||
89 | Note: Only one decorator is supported per input. If more than one decorator |
|
89 | Note: Only one decorator is supported per input. If more than one decorator | |
90 | is specified, then only the last one is used. |
|
90 | is specified, then only the last one is used. | |
91 |
|
91 | |||
92 | In addition to the Pseudo-Decorators/options described at the above link, |
|
92 | In addition to the Pseudo-Decorators/options described at the above link, | |
93 | several enhancements have been made. The directive will emit a message to the |
|
93 | several enhancements have been made. The directive will emit a message to the | |
94 | console at build-time if code-execution resulted in an exception or warning. |
|
94 | console at build-time if code-execution resulted in an exception or warning. | |
95 | You can suppress these on a per-block basis by specifying the :okexcept: |
|
95 | You can suppress these on a per-block basis by specifying the :okexcept: | |
96 | or :okwarning: options: |
|
96 | or :okwarning: options: | |
97 |
|
97 | |||
98 | .. code-block:: rst |
|
98 | .. code-block:: rst | |
99 |
|
99 | |||
100 | .. ipython:: |
|
100 | .. ipython:: | |
101 | :okexcept: |
|
101 | :okexcept: | |
102 | :okwarning: |
|
102 | :okwarning: | |
103 |
|
103 | |||
104 | In [1]: 1/0 |
|
104 | In [1]: 1/0 | |
105 | In [2]: # raise warning. |
|
105 | In [2]: # raise warning. | |
106 |
|
106 | |||
107 | ToDo |
|
107 | ToDo | |
108 | ---- |
|
108 | ---- | |
109 |
|
109 | |||
110 | - Turn the ad-hoc test() function into a real test suite. |
|
110 | - Turn the ad-hoc test() function into a real test suite. | |
111 | - Break up ipython-specific functionality from matplotlib stuff into better |
|
111 | - Break up ipython-specific functionality from matplotlib stuff into better | |
112 | separated code. |
|
112 | separated code. | |
113 |
|
113 | |||
114 | Authors |
|
114 | Authors | |
115 | ------- |
|
115 | ------- | |
116 |
|
116 | |||
117 | - John D Hunter: orignal author. |
|
117 | - John D Hunter: orignal author. | |
118 | - Fernando Perez: refactoring, documentation, cleanups, port to 0.11. |
|
118 | - Fernando Perez: refactoring, documentation, cleanups, port to 0.11. | |
119 | - VΓ‘clavΕ milauer <eudoxos-AT-arcig.cz>: Prompt generalizations. |
|
119 | - VΓ‘clavΕ milauer <eudoxos-AT-arcig.cz>: Prompt generalizations. | |
120 | - Skipper Seabold, refactoring, cleanups, pure python addition |
|
120 | - Skipper Seabold, refactoring, cleanups, pure python addition | |
121 | """ |
|
121 | """ | |
122 |
|
122 | |||
123 | #----------------------------------------------------------------------------- |
|
123 | #----------------------------------------------------------------------------- | |
124 | # Imports |
|
124 | # Imports | |
125 | #----------------------------------------------------------------------------- |
|
125 | #----------------------------------------------------------------------------- | |
126 |
|
126 | |||
127 | # Stdlib |
|
127 | # Stdlib | |
128 | import atexit |
|
128 | import atexit | |
129 | import errno |
|
129 | import errno | |
130 | import os |
|
130 | import os | |
131 | import re |
|
131 | import re | |
132 | import sys |
|
132 | import sys | |
133 | import tempfile |
|
133 | import tempfile | |
134 | import ast |
|
134 | import ast | |
135 | import warnings |
|
135 | import warnings | |
136 | import shutil |
|
136 | import shutil | |
137 | from io import StringIO |
|
137 | from io import StringIO | |
138 |
|
138 | |||
139 | # Third-party |
|
139 | # Third-party | |
140 | from docutils.parsers.rst import directives |
|
140 | from docutils.parsers.rst import directives | |
141 | from docutils.parsers.rst import Directive |
|
141 | from docutils.parsers.rst import Directive | |
142 |
|
142 | |||
143 | # Our own |
|
143 | # Our own | |
144 | from traitlets.config import Config |
|
144 | from traitlets.config import Config | |
145 | from IPython import InteractiveShell |
|
145 | from IPython import InteractiveShell | |
146 | from IPython.core.profiledir import ProfileDir |
|
146 | from IPython.core.profiledir import ProfileDir | |
147 |
|
147 | |||
148 | #----------------------------------------------------------------------------- |
|
148 | #----------------------------------------------------------------------------- | |
149 | # Globals |
|
149 | # Globals | |
150 | #----------------------------------------------------------------------------- |
|
150 | #----------------------------------------------------------------------------- | |
151 | # for tokenizing blocks |
|
151 | # for tokenizing blocks | |
152 | COMMENT, INPUT, OUTPUT = range(3) |
|
152 | COMMENT, INPUT, OUTPUT = range(3) | |
153 |
|
153 | |||
154 | #----------------------------------------------------------------------------- |
|
154 | #----------------------------------------------------------------------------- | |
155 | # Functions and class declarations |
|
155 | # Functions and class declarations | |
156 | #----------------------------------------------------------------------------- |
|
156 | #----------------------------------------------------------------------------- | |
157 |
|
157 | |||
158 | def block_parser(part, rgxin, rgxout, fmtin, fmtout): |
|
158 | def block_parser(part, rgxin, rgxout, fmtin, fmtout): | |
159 | """ |
|
159 | """ | |
160 | part is a string of ipython text, comprised of at most one |
|
160 | part is a string of ipython text, comprised of at most one | |
161 | input, one output, comments, and blank lines. The block parser |
|
161 | input, one output, comments, and blank lines. The block parser | |
162 | parses the text into a list of:: |
|
162 | parses the text into a list of:: | |
163 |
|
163 | |||
164 | blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...] |
|
164 | blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...] | |
165 |
|
165 | |||
166 | where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and |
|
166 | where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and | |
167 | data is, depending on the type of token:: |
|
167 | data is, depending on the type of token:: | |
168 |
|
168 | |||
169 | COMMENT : the comment string |
|
169 | COMMENT : the comment string | |
170 |
|
170 | |||
171 | INPUT: the (DECORATOR, INPUT_LINE, REST) where |
|
171 | INPUT: the (DECORATOR, INPUT_LINE, REST) where | |
172 | DECORATOR: the input decorator (or None) |
|
172 | DECORATOR: the input decorator (or None) | |
173 | INPUT_LINE: the input as string (possibly multi-line) |
|
173 | INPUT_LINE: the input as string (possibly multi-line) | |
174 | REST : any stdout generated by the input line (not OUTPUT) |
|
174 | REST : any stdout generated by the input line (not OUTPUT) | |
175 |
|
175 | |||
176 | OUTPUT: the output string, possibly multi-line |
|
176 | OUTPUT: the output string, possibly multi-line | |
177 |
|
177 | |||
178 | """ |
|
178 | """ | |
179 | block = [] |
|
179 | block = [] | |
180 | lines = part.split('\n') |
|
180 | lines = part.split('\n') | |
181 | N = len(lines) |
|
181 | N = len(lines) | |
182 | i = 0 |
|
182 | i = 0 | |
183 | decorator = None |
|
183 | decorator = None | |
184 | while 1: |
|
184 | while 1: | |
185 |
|
185 | |||
186 | if i==N: |
|
186 | if i==N: | |
187 | # nothing left to parse -- the last line |
|
187 | # nothing left to parse -- the last line | |
188 | break |
|
188 | break | |
189 |
|
189 | |||
190 | line = lines[i] |
|
190 | line = lines[i] | |
191 | i += 1 |
|
191 | i += 1 | |
192 | line_stripped = line.strip() |
|
192 | line_stripped = line.strip() | |
193 | if line_stripped.startswith('#'): |
|
193 | if line_stripped.startswith('#'): | |
194 | block.append((COMMENT, line)) |
|
194 | block.append((COMMENT, line)) | |
195 | continue |
|
195 | continue | |
196 |
|
196 | |||
197 | if line_stripped.startswith('@'): |
|
197 | if line_stripped.startswith('@'): | |
198 | # Here is where we assume there is, at most, one decorator. |
|
198 | # Here is where we assume there is, at most, one decorator. | |
199 | # Might need to rethink this. |
|
199 | # Might need to rethink this. | |
200 | decorator = line_stripped |
|
200 | decorator = line_stripped | |
201 | continue |
|
201 | continue | |
202 |
|
202 | |||
203 | # does this look like an input line? |
|
203 | # does this look like an input line? | |
204 | matchin = rgxin.match(line) |
|
204 | matchin = rgxin.match(line) | |
205 | if matchin: |
|
205 | if matchin: | |
206 | lineno, inputline = int(matchin.group(1)), matchin.group(2) |
|
206 | lineno, inputline = int(matchin.group(1)), matchin.group(2) | |
207 |
|
207 | |||
208 | # the ....: continuation string |
|
208 | # the ....: continuation string | |
209 | continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2)) |
|
209 | continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2)) | |
210 | Nc = len(continuation) |
|
210 | Nc = len(continuation) | |
211 | # input lines can continue on for more than one line, if |
|
211 | # input lines can continue on for more than one line, if | |
212 | # we have a '\' line continuation char or a function call |
|
212 | # we have a '\' line continuation char or a function call | |
213 | # echo line 'print'. The input line can only be |
|
213 | # echo line 'print'. The input line can only be | |
214 | # terminated by the end of the block or an output line, so |
|
214 | # terminated by the end of the block or an output line, so | |
215 | # we parse out the rest of the input line if it is |
|
215 | # we parse out the rest of the input line if it is | |
216 | # multiline as well as any echo text |
|
216 | # multiline as well as any echo text | |
217 |
|
217 | |||
218 | rest = [] |
|
218 | rest = [] | |
219 | while i<N: |
|
219 | while i<N: | |
220 |
|
220 | |||
221 | # look ahead; if the next line is blank, or a comment, or |
|
221 | # look ahead; if the next line is blank, or a comment, or | |
222 | # an output line, we're done |
|
222 | # an output line, we're done | |
223 |
|
223 | |||
224 | nextline = lines[i] |
|
224 | nextline = lines[i] | |
225 | matchout = rgxout.match(nextline) |
|
225 | matchout = rgxout.match(nextline) | |
226 | #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation)) |
|
226 | #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation)) | |
227 | if matchout or nextline.startswith('#'): |
|
227 | if matchout or nextline.startswith('#'): | |
228 | break |
|
228 | break | |
229 | elif nextline.startswith(continuation): |
|
229 | elif nextline.startswith(continuation): | |
230 | # The default ipython_rgx* treat the space following the colon as optional. |
|
230 | # The default ipython_rgx* treat the space following the colon as optional. | |
231 | # However, If the space is there we must consume it or code |
|
231 | # However, If the space is there we must consume it or code | |
232 | # employing the cython_magic extension will fail to execute. |
|
232 | # employing the cython_magic extension will fail to execute. | |
233 | # |
|
233 | # | |
234 | # This works with the default ipython_rgx* patterns, |
|
234 | # This works with the default ipython_rgx* patterns, | |
235 | # If you modify them, YMMV. |
|
235 | # If you modify them, YMMV. | |
236 | nextline = nextline[Nc:] |
|
236 | nextline = nextline[Nc:] | |
237 | if nextline and nextline[0] == ' ': |
|
237 | if nextline and nextline[0] == ' ': | |
238 | nextline = nextline[1:] |
|
238 | nextline = nextline[1:] | |
239 |
|
239 | |||
240 | inputline += '\n' + nextline |
|
240 | inputline += '\n' + nextline | |
241 | else: |
|
241 | else: | |
242 | rest.append(nextline) |
|
242 | rest.append(nextline) | |
243 | i+= 1 |
|
243 | i+= 1 | |
244 |
|
244 | |||
245 | block.append((INPUT, (decorator, inputline, '\n'.join(rest)))) |
|
245 | block.append((INPUT, (decorator, inputline, '\n'.join(rest)))) | |
246 | continue |
|
246 | continue | |
247 |
|
247 | |||
248 | # if it looks like an output line grab all the text to the end |
|
248 | # if it looks like an output line grab all the text to the end | |
249 | # of the block |
|
249 | # of the block | |
250 | matchout = rgxout.match(line) |
|
250 | matchout = rgxout.match(line) | |
251 | if matchout: |
|
251 | if matchout: | |
252 | lineno, output = int(matchout.group(1)), matchout.group(2) |
|
252 | lineno, output = int(matchout.group(1)), matchout.group(2) | |
253 | if i<N-1: |
|
253 | if i<N-1: | |
254 | output = '\n'.join([output] + lines[i:]) |
|
254 | output = '\n'.join([output] + lines[i:]) | |
255 |
|
255 | |||
256 | block.append((OUTPUT, output)) |
|
256 | block.append((OUTPUT, output)) | |
257 | break |
|
257 | break | |
258 |
|
258 | |||
259 | return block |
|
259 | return block | |
260 |
|
260 | |||
261 |
|
261 | |||
262 | class EmbeddedSphinxShell(object): |
|
262 | class EmbeddedSphinxShell(object): | |
263 | """An embedded IPython instance to run inside Sphinx""" |
|
263 | """An embedded IPython instance to run inside Sphinx""" | |
264 |
|
264 | |||
265 | def __init__(self, exec_lines=None): |
|
265 | def __init__(self, exec_lines=None): | |
266 |
|
266 | |||
267 | self.cout = StringIO() |
|
267 | self.cout = StringIO() | |
268 |
|
268 | |||
269 | if exec_lines is None: |
|
269 | if exec_lines is None: | |
270 | exec_lines = [] |
|
270 | exec_lines = [] | |
271 |
|
271 | |||
272 | # Create config object for IPython |
|
272 | # Create config object for IPython | |
273 | config = Config() |
|
273 | config = Config() | |
274 | config.HistoryManager.hist_file = ':memory:' |
|
274 | config.HistoryManager.hist_file = ':memory:' | |
275 | config.InteractiveShell.autocall = False |
|
275 | config.InteractiveShell.autocall = False | |
276 | config.InteractiveShell.autoindent = False |
|
276 | config.InteractiveShell.autoindent = False | |
277 | config.InteractiveShell.colors = 'NoColor' |
|
277 | config.InteractiveShell.colors = 'NoColor' | |
278 |
|
278 | |||
279 | # create a profile so instance history isn't saved |
|
279 | # create a profile so instance history isn't saved | |
280 | tmp_profile_dir = tempfile.mkdtemp(prefix='profile_') |
|
280 | tmp_profile_dir = tempfile.mkdtemp(prefix='profile_') | |
281 | profname = 'auto_profile_sphinx_build' |
|
281 | profname = 'auto_profile_sphinx_build' | |
282 | pdir = os.path.join(tmp_profile_dir,profname) |
|
282 | pdir = os.path.join(tmp_profile_dir,profname) | |
283 | profile = ProfileDir.create_profile_dir(pdir) |
|
283 | profile = ProfileDir.create_profile_dir(pdir) | |
284 |
|
284 | |||
285 | # Create and initialize global ipython, but don't start its mainloop. |
|
285 | # Create and initialize global ipython, but don't start its mainloop. | |
286 | # This will persist across different EmbededSphinxShell instances. |
|
286 | # This will persist across different EmbeddedSphinxShell instances. | |
287 | IP = InteractiveShell.instance(config=config, profile_dir=profile) |
|
287 | IP = InteractiveShell.instance(config=config, profile_dir=profile) | |
288 | atexit.register(self.cleanup) |
|
288 | atexit.register(self.cleanup) | |
289 |
|
289 | |||
290 | sys.stdout = self.cout |
|
290 | sys.stdout = self.cout | |
291 | sys.stderr = self.cout |
|
291 | sys.stderr = self.cout | |
292 |
|
292 | |||
293 | # For debugging, so we can see normal output, use this: |
|
293 | # For debugging, so we can see normal output, use this: | |
294 | #from IPython.utils.io import Tee |
|
294 | #from IPython.utils.io import Tee | |
295 | #sys.stdout = Tee(self.cout, channel='stdout') # dbg |
|
295 | #sys.stdout = Tee(self.cout, channel='stdout') # dbg | |
296 | #sys.stderr = Tee(self.cout, channel='stderr') # dbg |
|
296 | #sys.stderr = Tee(self.cout, channel='stderr') # dbg | |
297 |
|
297 | |||
298 | # Store a few parts of IPython we'll need. |
|
298 | # Store a few parts of IPython we'll need. | |
299 | self.IP = IP |
|
299 | self.IP = IP | |
300 | self.user_ns = self.IP.user_ns |
|
300 | self.user_ns = self.IP.user_ns | |
301 | self.user_global_ns = self.IP.user_global_ns |
|
301 | self.user_global_ns = self.IP.user_global_ns | |
302 |
|
302 | |||
303 | self.input = '' |
|
303 | self.input = '' | |
304 | self.output = '' |
|
304 | self.output = '' | |
305 | self.tmp_profile_dir = tmp_profile_dir |
|
305 | self.tmp_profile_dir = tmp_profile_dir | |
306 |
|
306 | |||
307 | self.is_verbatim = False |
|
307 | self.is_verbatim = False | |
308 | self.is_doctest = False |
|
308 | self.is_doctest = False | |
309 | self.is_suppress = False |
|
309 | self.is_suppress = False | |
310 |
|
310 | |||
311 | # Optionally, provide more detailed information to shell. |
|
311 | # Optionally, provide more detailed information to shell. | |
312 | # this is assigned by the SetUp method of IPythonDirective |
|
312 | # this is assigned by the SetUp method of IPythonDirective | |
313 | # to point at itself. |
|
313 | # to point at itself. | |
314 | # |
|
314 | # | |
315 | # So, you can access handy things at self.directive.state |
|
315 | # So, you can access handy things at self.directive.state | |
316 | self.directive = None |
|
316 | self.directive = None | |
317 |
|
317 | |||
318 | # on the first call to the savefig decorator, we'll import |
|
318 | # on the first call to the savefig decorator, we'll import | |
319 | # pyplot as plt so we can make a call to the plt.gcf().savefig |
|
319 | # pyplot as plt so we can make a call to the plt.gcf().savefig | |
320 | self._pyplot_imported = False |
|
320 | self._pyplot_imported = False | |
321 |
|
321 | |||
322 | # Prepopulate the namespace. |
|
322 | # Prepopulate the namespace. | |
323 | for line in exec_lines: |
|
323 | for line in exec_lines: | |
324 | self.process_input_line(line, store_history=False) |
|
324 | self.process_input_line(line, store_history=False) | |
325 |
|
325 | |||
326 | def cleanup(self): |
|
326 | def cleanup(self): | |
327 | shutil.rmtree(self.tmp_profile_dir, ignore_errors=True) |
|
327 | shutil.rmtree(self.tmp_profile_dir, ignore_errors=True) | |
328 |
|
328 | |||
329 | def clear_cout(self): |
|
329 | def clear_cout(self): | |
330 | self.cout.seek(0) |
|
330 | self.cout.seek(0) | |
331 | self.cout.truncate(0) |
|
331 | self.cout.truncate(0) | |
332 |
|
332 | |||
333 | def process_input_line(self, line, store_history=True): |
|
333 | def process_input_line(self, line, store_history=True): | |
334 | """process the input, capturing stdout""" |
|
334 | """process the input, capturing stdout""" | |
335 |
|
335 | |||
336 | stdout = sys.stdout |
|
336 | stdout = sys.stdout | |
337 | splitter = self.IP.input_splitter |
|
337 | splitter = self.IP.input_splitter | |
338 | try: |
|
338 | try: | |
339 | sys.stdout = self.cout |
|
339 | sys.stdout = self.cout | |
340 | splitter.push(line) |
|
340 | splitter.push(line) | |
341 | more = splitter.push_accepts_more() |
|
341 | more = splitter.push_accepts_more() | |
342 | if not more: |
|
342 | if not more: | |
343 | source_raw = splitter.raw_reset() |
|
343 | source_raw = splitter.raw_reset() | |
344 | self.IP.run_cell(source_raw, store_history=store_history) |
|
344 | self.IP.run_cell(source_raw, store_history=store_history) | |
345 | finally: |
|
345 | finally: | |
346 | sys.stdout = stdout |
|
346 | sys.stdout = stdout | |
347 |
|
347 | |||
348 | def process_image(self, decorator): |
|
348 | def process_image(self, decorator): | |
349 | """ |
|
349 | """ | |
350 | # build out an image directive like |
|
350 | # build out an image directive like | |
351 | # .. image:: somefile.png |
|
351 | # .. image:: somefile.png | |
352 | # :width 4in |
|
352 | # :width 4in | |
353 | # |
|
353 | # | |
354 | # from an input like |
|
354 | # from an input like | |
355 | # savefig somefile.png width=4in |
|
355 | # savefig somefile.png width=4in | |
356 | """ |
|
356 | """ | |
357 | savefig_dir = self.savefig_dir |
|
357 | savefig_dir = self.savefig_dir | |
358 | source_dir = self.source_dir |
|
358 | source_dir = self.source_dir | |
359 | saveargs = decorator.split(' ') |
|
359 | saveargs = decorator.split(' ') | |
360 | filename = saveargs[1] |
|
360 | filename = saveargs[1] | |
361 | # insert relative path to image file in source (as absolute path for Sphinx) |
|
361 | # insert relative path to image file in source (as absolute path for Sphinx) | |
362 | outfile = '/' + os.path.relpath(os.path.join(savefig_dir,filename), |
|
362 | outfile = '/' + os.path.relpath(os.path.join(savefig_dir,filename), | |
363 | source_dir) |
|
363 | source_dir) | |
364 |
|
364 | |||
365 | imagerows = ['.. image:: %s'%outfile] |
|
365 | imagerows = ['.. image:: %s'%outfile] | |
366 |
|
366 | |||
367 | for kwarg in saveargs[2:]: |
|
367 | for kwarg in saveargs[2:]: | |
368 | arg, val = kwarg.split('=') |
|
368 | arg, val = kwarg.split('=') | |
369 | arg = arg.strip() |
|
369 | arg = arg.strip() | |
370 | val = val.strip() |
|
370 | val = val.strip() | |
371 | imagerows.append(' :%s: %s'%(arg, val)) |
|
371 | imagerows.append(' :%s: %s'%(arg, val)) | |
372 |
|
372 | |||
373 | image_file = os.path.basename(outfile) # only return file name |
|
373 | image_file = os.path.basename(outfile) # only return file name | |
374 | image_directive = '\n'.join(imagerows) |
|
374 | image_directive = '\n'.join(imagerows) | |
375 | return image_file, image_directive |
|
375 | return image_file, image_directive | |
376 |
|
376 | |||
377 | # Callbacks for each type of token |
|
377 | # Callbacks for each type of token | |
378 | def process_input(self, data, input_prompt, lineno): |
|
378 | def process_input(self, data, input_prompt, lineno): | |
379 | """ |
|
379 | """ | |
380 | Process data block for INPUT token. |
|
380 | Process data block for INPUT token. | |
381 |
|
381 | |||
382 | """ |
|
382 | """ | |
383 | decorator, input, rest = data |
|
383 | decorator, input, rest = data | |
384 | image_file = None |
|
384 | image_file = None | |
385 | image_directive = None |
|
385 | image_directive = None | |
386 |
|
386 | |||
387 | is_verbatim = decorator=='@verbatim' or self.is_verbatim |
|
387 | is_verbatim = decorator=='@verbatim' or self.is_verbatim | |
388 | is_doctest = (decorator is not None and \ |
|
388 | is_doctest = (decorator is not None and \ | |
389 | decorator.startswith('@doctest')) or self.is_doctest |
|
389 | decorator.startswith('@doctest')) or self.is_doctest | |
390 | is_suppress = decorator=='@suppress' or self.is_suppress |
|
390 | is_suppress = decorator=='@suppress' or self.is_suppress | |
391 | is_okexcept = decorator=='@okexcept' or self.is_okexcept |
|
391 | is_okexcept = decorator=='@okexcept' or self.is_okexcept | |
392 | is_okwarning = decorator=='@okwarning' or self.is_okwarning |
|
392 | is_okwarning = decorator=='@okwarning' or self.is_okwarning | |
393 | is_savefig = decorator is not None and \ |
|
393 | is_savefig = decorator is not None and \ | |
394 | decorator.startswith('@savefig') |
|
394 | decorator.startswith('@savefig') | |
395 |
|
395 | |||
396 | input_lines = input.split('\n') |
|
396 | input_lines = input.split('\n') | |
397 | if len(input_lines) > 1: |
|
397 | if len(input_lines) > 1: | |
398 | if input_lines[-1] != "": |
|
398 | if input_lines[-1] != "": | |
399 | input_lines.append('') # make sure there's a blank line |
|
399 | input_lines.append('') # make sure there's a blank line | |
400 | # so splitter buffer gets reset |
|
400 | # so splitter buffer gets reset | |
401 |
|
401 | |||
402 | continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2)) |
|
402 | continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2)) | |
403 |
|
403 | |||
404 | if is_savefig: |
|
404 | if is_savefig: | |
405 | image_file, image_directive = self.process_image(decorator) |
|
405 | image_file, image_directive = self.process_image(decorator) | |
406 |
|
406 | |||
407 | ret = [] |
|
407 | ret = [] | |
408 | is_semicolon = False |
|
408 | is_semicolon = False | |
409 |
|
409 | |||
410 | # Hold the execution count, if requested to do so. |
|
410 | # Hold the execution count, if requested to do so. | |
411 | if is_suppress and self.hold_count: |
|
411 | if is_suppress and self.hold_count: | |
412 | store_history = False |
|
412 | store_history = False | |
413 | else: |
|
413 | else: | |
414 | store_history = True |
|
414 | store_history = True | |
415 |
|
415 | |||
416 | # Note: catch_warnings is not thread safe |
|
416 | # Note: catch_warnings is not thread safe | |
417 | with warnings.catch_warnings(record=True) as ws: |
|
417 | with warnings.catch_warnings(record=True) as ws: | |
418 | for i, line in enumerate(input_lines): |
|
418 | for i, line in enumerate(input_lines): | |
419 | if line.endswith(';'): |
|
419 | if line.endswith(';'): | |
420 | is_semicolon = True |
|
420 | is_semicolon = True | |
421 |
|
421 | |||
422 | if i == 0: |
|
422 | if i == 0: | |
423 | # process the first input line |
|
423 | # process the first input line | |
424 | if is_verbatim: |
|
424 | if is_verbatim: | |
425 | self.process_input_line('') |
|
425 | self.process_input_line('') | |
426 | self.IP.execution_count += 1 # increment it anyway |
|
426 | self.IP.execution_count += 1 # increment it anyway | |
427 | else: |
|
427 | else: | |
428 | # only submit the line in non-verbatim mode |
|
428 | # only submit the line in non-verbatim mode | |
429 | self.process_input_line(line, store_history=store_history) |
|
429 | self.process_input_line(line, store_history=store_history) | |
430 | formatted_line = '%s %s'%(input_prompt, line) |
|
430 | formatted_line = '%s %s'%(input_prompt, line) | |
431 | else: |
|
431 | else: | |
432 | # process a continuation line |
|
432 | # process a continuation line | |
433 | if not is_verbatim: |
|
433 | if not is_verbatim: | |
434 | self.process_input_line(line, store_history=store_history) |
|
434 | self.process_input_line(line, store_history=store_history) | |
435 |
|
435 | |||
436 | formatted_line = '%s %s'%(continuation, line) |
|
436 | formatted_line = '%s %s'%(continuation, line) | |
437 |
|
437 | |||
438 | if not is_suppress: |
|
438 | if not is_suppress: | |
439 | ret.append(formatted_line) |
|
439 | ret.append(formatted_line) | |
440 |
|
440 | |||
441 | if not is_suppress and len(rest.strip()) and is_verbatim: |
|
441 | if not is_suppress and len(rest.strip()) and is_verbatim: | |
442 | # The "rest" is the standard output of the input. This needs to be |
|
442 | # The "rest" is the standard output of the input. This needs to be | |
443 | # added when in verbatim mode. If there is no "rest", then we don't |
|
443 | # added when in verbatim mode. If there is no "rest", then we don't | |
444 | # add it, as the new line will be added by the processed output. |
|
444 | # add it, as the new line will be added by the processed output. | |
445 | ret.append(rest) |
|
445 | ret.append(rest) | |
446 |
|
446 | |||
447 | # Fetch the processed output. (This is not the submitted output.) |
|
447 | # Fetch the processed output. (This is not the submitted output.) | |
448 | self.cout.seek(0) |
|
448 | self.cout.seek(0) | |
449 | processed_output = self.cout.read() |
|
449 | processed_output = self.cout.read() | |
450 | if not is_suppress and not is_semicolon: |
|
450 | if not is_suppress and not is_semicolon: | |
451 | # |
|
451 | # | |
452 | # In IPythonDirective.run, the elements of `ret` are eventually |
|
452 | # In IPythonDirective.run, the elements of `ret` are eventually | |
453 | # combined such that '' entries correspond to newlines. So if |
|
453 | # combined such that '' entries correspond to newlines. So if | |
454 | # `processed_output` is equal to '', then the adding it to `ret` |
|
454 | # `processed_output` is equal to '', then the adding it to `ret` | |
455 | # ensures that there is a blank line between consecutive inputs |
|
455 | # ensures that there is a blank line between consecutive inputs | |
456 | # that have no outputs, as in: |
|
456 | # that have no outputs, as in: | |
457 | # |
|
457 | # | |
458 | # In [1]: x = 4 |
|
458 | # In [1]: x = 4 | |
459 | # |
|
459 | # | |
460 | # In [2]: x = 5 |
|
460 | # In [2]: x = 5 | |
461 | # |
|
461 | # | |
462 | # When there is processed output, it has a '\n' at the tail end. So |
|
462 | # When there is processed output, it has a '\n' at the tail end. So | |
463 | # adding the output to `ret` will provide the necessary spacing |
|
463 | # adding the output to `ret` will provide the necessary spacing | |
464 | # between consecutive input/output blocks, as in: |
|
464 | # between consecutive input/output blocks, as in: | |
465 | # |
|
465 | # | |
466 | # In [1]: x |
|
466 | # In [1]: x | |
467 | # Out[1]: 5 |
|
467 | # Out[1]: 5 | |
468 | # |
|
468 | # | |
469 | # In [2]: x |
|
469 | # In [2]: x | |
470 | # Out[2]: 5 |
|
470 | # Out[2]: 5 | |
471 | # |
|
471 | # | |
472 | # When there is stdout from the input, it also has a '\n' at the |
|
472 | # When there is stdout from the input, it also has a '\n' at the | |
473 | # tail end, and so this ensures proper spacing as well. E.g.: |
|
473 | # tail end, and so this ensures proper spacing as well. E.g.: | |
474 | # |
|
474 | # | |
475 | # In [1]: print x |
|
475 | # In [1]: print x | |
476 | # 5 |
|
476 | # 5 | |
477 | # |
|
477 | # | |
478 | # In [2]: x = 5 |
|
478 | # In [2]: x = 5 | |
479 | # |
|
479 | # | |
480 | # When in verbatim mode, `processed_output` is empty (because |
|
480 | # When in verbatim mode, `processed_output` is empty (because | |
481 | # nothing was passed to IP. Sometimes the submitted code block has |
|
481 | # nothing was passed to IP. Sometimes the submitted code block has | |
482 | # an Out[] portion and sometimes it does not. When it does not, we |
|
482 | # an Out[] portion and sometimes it does not. When it does not, we | |
483 | # need to ensure proper spacing, so we have to add '' to `ret`. |
|
483 | # need to ensure proper spacing, so we have to add '' to `ret`. | |
484 | # However, if there is an Out[] in the submitted code, then we do |
|
484 | # However, if there is an Out[] in the submitted code, then we do | |
485 | # not want to add a newline as `process_output` has stuff to add. |
|
485 | # not want to add a newline as `process_output` has stuff to add. | |
486 | # The difficulty is that `process_input` doesn't know if |
|
486 | # The difficulty is that `process_input` doesn't know if | |
487 | # `process_output` will be called---so it doesn't know if there is |
|
487 | # `process_output` will be called---so it doesn't know if there is | |
488 | # Out[] in the code block. The requires that we include a hack in |
|
488 | # Out[] in the code block. The requires that we include a hack in | |
489 | # `process_block`. See the comments there. |
|
489 | # `process_block`. See the comments there. | |
490 | # |
|
490 | # | |
491 | ret.append(processed_output) |
|
491 | ret.append(processed_output) | |
492 | elif is_semicolon: |
|
492 | elif is_semicolon: | |
493 | # Make sure there is a newline after the semicolon. |
|
493 | # Make sure there is a newline after the semicolon. | |
494 | ret.append('') |
|
494 | ret.append('') | |
495 |
|
495 | |||
496 | # context information |
|
496 | # context information | |
497 | filename = "Unknown" |
|
497 | filename = "Unknown" | |
498 | lineno = 0 |
|
498 | lineno = 0 | |
499 | if self.directive.state: |
|
499 | if self.directive.state: | |
500 | filename = self.directive.state.document.current_source |
|
500 | filename = self.directive.state.document.current_source | |
501 | lineno = self.directive.state.document.current_line |
|
501 | lineno = self.directive.state.document.current_line | |
502 |
|
502 | |||
503 | # output any exceptions raised during execution to stdout |
|
503 | # output any exceptions raised during execution to stdout | |
504 | # unless :okexcept: has been specified. |
|
504 | # unless :okexcept: has been specified. | |
505 | if not is_okexcept and "Traceback" in processed_output: |
|
505 | if not is_okexcept and "Traceback" in processed_output: | |
506 | s = "\nException in %s at block ending on line %s\n" % (filename, lineno) |
|
506 | s = "\nException in %s at block ending on line %s\n" % (filename, lineno) | |
507 | s += "Specify :okexcept: as an option in the ipython:: block to suppress this message\n" |
|
507 | s += "Specify :okexcept: as an option in the ipython:: block to suppress this message\n" | |
508 | sys.stdout.write('\n\n>>>' + ('-' * 73)) |
|
508 | sys.stdout.write('\n\n>>>' + ('-' * 73)) | |
509 | sys.stdout.write(s) |
|
509 | sys.stdout.write(s) | |
510 | sys.stdout.write(processed_output) |
|
510 | sys.stdout.write(processed_output) | |
511 | sys.stdout.write('<<<' + ('-' * 73) + '\n\n') |
|
511 | sys.stdout.write('<<<' + ('-' * 73) + '\n\n') | |
512 |
|
512 | |||
513 | # output any warning raised during execution to stdout |
|
513 | # output any warning raised during execution to stdout | |
514 | # unless :okwarning: has been specified. |
|
514 | # unless :okwarning: has been specified. | |
515 | if not is_okwarning: |
|
515 | if not is_okwarning: | |
516 | for w in ws: |
|
516 | for w in ws: | |
517 | s = "\nWarning in %s at block ending on line %s\n" % (filename, lineno) |
|
517 | s = "\nWarning in %s at block ending on line %s\n" % (filename, lineno) | |
518 | s += "Specify :okwarning: as an option in the ipython:: block to suppress this message\n" |
|
518 | s += "Specify :okwarning: as an option in the ipython:: block to suppress this message\n" | |
519 | sys.stdout.write('\n\n>>>' + ('-' * 73)) |
|
519 | sys.stdout.write('\n\n>>>' + ('-' * 73)) | |
520 | sys.stdout.write(s) |
|
520 | sys.stdout.write(s) | |
521 | sys.stdout.write(('-' * 76) + '\n') |
|
521 | sys.stdout.write(('-' * 76) + '\n') | |
522 | s=warnings.formatwarning(w.message, w.category, |
|
522 | s=warnings.formatwarning(w.message, w.category, | |
523 | w.filename, w.lineno, w.line) |
|
523 | w.filename, w.lineno, w.line) | |
524 | sys.stdout.write(s) |
|
524 | sys.stdout.write(s) | |
525 | sys.stdout.write('<<<' + ('-' * 73) + '\n') |
|
525 | sys.stdout.write('<<<' + ('-' * 73) + '\n') | |
526 |
|
526 | |||
527 | self.cout.truncate(0) |
|
527 | self.cout.truncate(0) | |
528 |
|
528 | |||
529 | return (ret, input_lines, processed_output, |
|
529 | return (ret, input_lines, processed_output, | |
530 | is_doctest, decorator, image_file, image_directive) |
|
530 | is_doctest, decorator, image_file, image_directive) | |
531 |
|
531 | |||
532 |
|
532 | |||
533 | def process_output(self, data, output_prompt, input_lines, output, |
|
533 | def process_output(self, data, output_prompt, input_lines, output, | |
534 | is_doctest, decorator, image_file): |
|
534 | is_doctest, decorator, image_file): | |
535 | """ |
|
535 | """ | |
536 | Process data block for OUTPUT token. |
|
536 | Process data block for OUTPUT token. | |
537 |
|
537 | |||
538 | """ |
|
538 | """ | |
539 | # Recall: `data` is the submitted output, and `output` is the processed |
|
539 | # Recall: `data` is the submitted output, and `output` is the processed | |
540 | # output from `input_lines`. |
|
540 | # output from `input_lines`. | |
541 |
|
541 | |||
542 | TAB = ' ' * 4 |
|
542 | TAB = ' ' * 4 | |
543 |
|
543 | |||
544 | if is_doctest and output is not None: |
|
544 | if is_doctest and output is not None: | |
545 |
|
545 | |||
546 | found = output # This is the processed output |
|
546 | found = output # This is the processed output | |
547 | found = found.strip() |
|
547 | found = found.strip() | |
548 | submitted = data.strip() |
|
548 | submitted = data.strip() | |
549 |
|
549 | |||
550 | if self.directive is None: |
|
550 | if self.directive is None: | |
551 | source = 'Unavailable' |
|
551 | source = 'Unavailable' | |
552 | content = 'Unavailable' |
|
552 | content = 'Unavailable' | |
553 | else: |
|
553 | else: | |
554 | source = self.directive.state.document.current_source |
|
554 | source = self.directive.state.document.current_source | |
555 | content = self.directive.content |
|
555 | content = self.directive.content | |
556 | # Add tabs and join into a single string. |
|
556 | # Add tabs and join into a single string. | |
557 | content = '\n'.join([TAB + line for line in content]) |
|
557 | content = '\n'.join([TAB + line for line in content]) | |
558 |
|
558 | |||
559 | # Make sure the output contains the output prompt. |
|
559 | # Make sure the output contains the output prompt. | |
560 | ind = found.find(output_prompt) |
|
560 | ind = found.find(output_prompt) | |
561 | if ind < 0: |
|
561 | if ind < 0: | |
562 | e = ('output does not contain output prompt\n\n' |
|
562 | e = ('output does not contain output prompt\n\n' | |
563 | 'Document source: {0}\n\n' |
|
563 | 'Document source: {0}\n\n' | |
564 | 'Raw content: \n{1}\n\n' |
|
564 | 'Raw content: \n{1}\n\n' | |
565 | 'Input line(s):\n{TAB}{2}\n\n' |
|
565 | 'Input line(s):\n{TAB}{2}\n\n' | |
566 | 'Output line(s):\n{TAB}{3}\n\n') |
|
566 | 'Output line(s):\n{TAB}{3}\n\n') | |
567 | e = e.format(source, content, '\n'.join(input_lines), |
|
567 | e = e.format(source, content, '\n'.join(input_lines), | |
568 | repr(found), TAB=TAB) |
|
568 | repr(found), TAB=TAB) | |
569 | raise RuntimeError(e) |
|
569 | raise RuntimeError(e) | |
570 | found = found[len(output_prompt):].strip() |
|
570 | found = found[len(output_prompt):].strip() | |
571 |
|
571 | |||
572 | # Handle the actual doctest comparison. |
|
572 | # Handle the actual doctest comparison. | |
573 | if decorator.strip() == '@doctest': |
|
573 | if decorator.strip() == '@doctest': | |
574 | # Standard doctest |
|
574 | # Standard doctest | |
575 | if found != submitted: |
|
575 | if found != submitted: | |
576 | e = ('doctest failure\n\n' |
|
576 | e = ('doctest failure\n\n' | |
577 | 'Document source: {0}\n\n' |
|
577 | 'Document source: {0}\n\n' | |
578 | 'Raw content: \n{1}\n\n' |
|
578 | 'Raw content: \n{1}\n\n' | |
579 | 'On input line(s):\n{TAB}{2}\n\n' |
|
579 | 'On input line(s):\n{TAB}{2}\n\n' | |
580 | 'we found output:\n{TAB}{3}\n\n' |
|
580 | 'we found output:\n{TAB}{3}\n\n' | |
581 | 'instead of the expected:\n{TAB}{4}\n\n') |
|
581 | 'instead of the expected:\n{TAB}{4}\n\n') | |
582 | e = e.format(source, content, '\n'.join(input_lines), |
|
582 | e = e.format(source, content, '\n'.join(input_lines), | |
583 | repr(found), repr(submitted), TAB=TAB) |
|
583 | repr(found), repr(submitted), TAB=TAB) | |
584 | raise RuntimeError(e) |
|
584 | raise RuntimeError(e) | |
585 | else: |
|
585 | else: | |
586 | self.custom_doctest(decorator, input_lines, found, submitted) |
|
586 | self.custom_doctest(decorator, input_lines, found, submitted) | |
587 |
|
587 | |||
588 | # When in verbatim mode, this holds additional submitted output |
|
588 | # When in verbatim mode, this holds additional submitted output | |
589 | # to be written in the final Sphinx output. |
|
589 | # to be written in the final Sphinx output. | |
590 | # https://github.com/ipython/ipython/issues/5776 |
|
590 | # https://github.com/ipython/ipython/issues/5776 | |
591 | out_data = [] |
|
591 | out_data = [] | |
592 |
|
592 | |||
593 | is_verbatim = decorator=='@verbatim' or self.is_verbatim |
|
593 | is_verbatim = decorator=='@verbatim' or self.is_verbatim | |
594 | if is_verbatim and data.strip(): |
|
594 | if is_verbatim and data.strip(): | |
595 | # Note that `ret` in `process_block` has '' as its last element if |
|
595 | # Note that `ret` in `process_block` has '' as its last element if | |
596 | # the code block was in verbatim mode. So if there is no submitted |
|
596 | # the code block was in verbatim mode. So if there is no submitted | |
597 | # output, then we will have proper spacing only if we do not add |
|
597 | # output, then we will have proper spacing only if we do not add | |
598 | # an additional '' to `out_data`. This is why we condition on |
|
598 | # an additional '' to `out_data`. This is why we condition on | |
599 | # `and data.strip()`. |
|
599 | # `and data.strip()`. | |
600 |
|
600 | |||
601 | # The submitted output has no output prompt. If we want the |
|
601 | # The submitted output has no output prompt. If we want the | |
602 | # prompt and the code to appear, we need to join them now |
|
602 | # prompt and the code to appear, we need to join them now | |
603 | # instead of adding them separately---as this would create an |
|
603 | # instead of adding them separately---as this would create an | |
604 | # undesired newline. How we do this ultimately depends on the |
|
604 | # undesired newline. How we do this ultimately depends on the | |
605 | # format of the output regex. I'll do what works for the default |
|
605 | # format of the output regex. I'll do what works for the default | |
606 | # prompt for now, and we might have to adjust if it doesn't work |
|
606 | # prompt for now, and we might have to adjust if it doesn't work | |
607 | # in other cases. Finally, the submitted output does not have |
|
607 | # in other cases. Finally, the submitted output does not have | |
608 | # a trailing newline, so we must add it manually. |
|
608 | # a trailing newline, so we must add it manually. | |
609 | out_data.append("{0} {1}\n".format(output_prompt, data)) |
|
609 | out_data.append("{0} {1}\n".format(output_prompt, data)) | |
610 |
|
610 | |||
611 | return out_data |
|
611 | return out_data | |
612 |
|
612 | |||
613 | def process_comment(self, data): |
|
613 | def process_comment(self, data): | |
614 | """Process data fPblock for COMMENT token.""" |
|
614 | """Process data fPblock for COMMENT token.""" | |
615 | if not self.is_suppress: |
|
615 | if not self.is_suppress: | |
616 | return [data] |
|
616 | return [data] | |
617 |
|
617 | |||
618 | def save_image(self, image_file): |
|
618 | def save_image(self, image_file): | |
619 | """ |
|
619 | """ | |
620 | Saves the image file to disk. |
|
620 | Saves the image file to disk. | |
621 | """ |
|
621 | """ | |
622 | self.ensure_pyplot() |
|
622 | self.ensure_pyplot() | |
623 | command = 'plt.gcf().savefig("%s")'%image_file |
|
623 | command = 'plt.gcf().savefig("%s")'%image_file | |
624 | #print 'SAVEFIG', command # dbg |
|
624 | #print 'SAVEFIG', command # dbg | |
625 | self.process_input_line('bookmark ipy_thisdir', store_history=False) |
|
625 | self.process_input_line('bookmark ipy_thisdir', store_history=False) | |
626 | self.process_input_line('cd -b ipy_savedir', store_history=False) |
|
626 | self.process_input_line('cd -b ipy_savedir', store_history=False) | |
627 | self.process_input_line(command, store_history=False) |
|
627 | self.process_input_line(command, store_history=False) | |
628 | self.process_input_line('cd -b ipy_thisdir', store_history=False) |
|
628 | self.process_input_line('cd -b ipy_thisdir', store_history=False) | |
629 | self.process_input_line('bookmark -d ipy_thisdir', store_history=False) |
|
629 | self.process_input_line('bookmark -d ipy_thisdir', store_history=False) | |
630 | self.clear_cout() |
|
630 | self.clear_cout() | |
631 |
|
631 | |||
632 | def process_block(self, block): |
|
632 | def process_block(self, block): | |
633 | """ |
|
633 | """ | |
634 | process block from the block_parser and return a list of processed lines |
|
634 | process block from the block_parser and return a list of processed lines | |
635 | """ |
|
635 | """ | |
636 | ret = [] |
|
636 | ret = [] | |
637 | output = None |
|
637 | output = None | |
638 | input_lines = None |
|
638 | input_lines = None | |
639 | lineno = self.IP.execution_count |
|
639 | lineno = self.IP.execution_count | |
640 |
|
640 | |||
641 | input_prompt = self.promptin % lineno |
|
641 | input_prompt = self.promptin % lineno | |
642 | output_prompt = self.promptout % lineno |
|
642 | output_prompt = self.promptout % lineno | |
643 | image_file = None |
|
643 | image_file = None | |
644 | image_directive = None |
|
644 | image_directive = None | |
645 |
|
645 | |||
646 | found_input = False |
|
646 | found_input = False | |
647 | for token, data in block: |
|
647 | for token, data in block: | |
648 | if token == COMMENT: |
|
648 | if token == COMMENT: | |
649 | out_data = self.process_comment(data) |
|
649 | out_data = self.process_comment(data) | |
650 | elif token == INPUT: |
|
650 | elif token == INPUT: | |
651 | found_input = True |
|
651 | found_input = True | |
652 | (out_data, input_lines, output, is_doctest, |
|
652 | (out_data, input_lines, output, is_doctest, | |
653 | decorator, image_file, image_directive) = \ |
|
653 | decorator, image_file, image_directive) = \ | |
654 | self.process_input(data, input_prompt, lineno) |
|
654 | self.process_input(data, input_prompt, lineno) | |
655 | elif token == OUTPUT: |
|
655 | elif token == OUTPUT: | |
656 | if not found_input: |
|
656 | if not found_input: | |
657 |
|
657 | |||
658 | TAB = ' ' * 4 |
|
658 | TAB = ' ' * 4 | |
659 | linenumber = 0 |
|
659 | linenumber = 0 | |
660 | source = 'Unavailable' |
|
660 | source = 'Unavailable' | |
661 | content = 'Unavailable' |
|
661 | content = 'Unavailable' | |
662 | if self.directive: |
|
662 | if self.directive: | |
663 | linenumber = self.directive.state.document.current_line |
|
663 | linenumber = self.directive.state.document.current_line | |
664 | source = self.directive.state.document.current_source |
|
664 | source = self.directive.state.document.current_source | |
665 | content = self.directive.content |
|
665 | content = self.directive.content | |
666 | # Add tabs and join into a single string. |
|
666 | # Add tabs and join into a single string. | |
667 | content = '\n'.join([TAB + line for line in content]) |
|
667 | content = '\n'.join([TAB + line for line in content]) | |
668 |
|
668 | |||
669 | e = ('\n\nInvalid block: Block contains an output prompt ' |
|
669 | e = ('\n\nInvalid block: Block contains an output prompt ' | |
670 | 'without an input prompt.\n\n' |
|
670 | 'without an input prompt.\n\n' | |
671 | 'Document source: {0}\n\n' |
|
671 | 'Document source: {0}\n\n' | |
672 | 'Content begins at line {1}: \n\n{2}\n\n' |
|
672 | 'Content begins at line {1}: \n\n{2}\n\n' | |
673 | 'Problematic block within content: \n\n{TAB}{3}\n\n') |
|
673 | 'Problematic block within content: \n\n{TAB}{3}\n\n') | |
674 | e = e.format(source, linenumber, content, block, TAB=TAB) |
|
674 | e = e.format(source, linenumber, content, block, TAB=TAB) | |
675 |
|
675 | |||
676 | # Write, rather than include in exception, since Sphinx |
|
676 | # Write, rather than include in exception, since Sphinx | |
677 | # will truncate tracebacks. |
|
677 | # will truncate tracebacks. | |
678 | sys.stdout.write(e) |
|
678 | sys.stdout.write(e) | |
679 | raise RuntimeError('An invalid block was detected.') |
|
679 | raise RuntimeError('An invalid block was detected.') | |
680 |
|
680 | |||
681 | out_data = \ |
|
681 | out_data = \ | |
682 | self.process_output(data, output_prompt, input_lines, |
|
682 | self.process_output(data, output_prompt, input_lines, | |
683 | output, is_doctest, decorator, |
|
683 | output, is_doctest, decorator, | |
684 | image_file) |
|
684 | image_file) | |
685 | if out_data: |
|
685 | if out_data: | |
686 | # Then there was user submitted output in verbatim mode. |
|
686 | # Then there was user submitted output in verbatim mode. | |
687 | # We need to remove the last element of `ret` that was |
|
687 | # We need to remove the last element of `ret` that was | |
688 | # added in `process_input`, as it is '' and would introduce |
|
688 | # added in `process_input`, as it is '' and would introduce | |
689 | # an undesirable newline. |
|
689 | # an undesirable newline. | |
690 | assert(ret[-1] == '') |
|
690 | assert(ret[-1] == '') | |
691 | del ret[-1] |
|
691 | del ret[-1] | |
692 |
|
692 | |||
693 | if out_data: |
|
693 | if out_data: | |
694 | ret.extend(out_data) |
|
694 | ret.extend(out_data) | |
695 |
|
695 | |||
696 | # save the image files |
|
696 | # save the image files | |
697 | if image_file is not None: |
|
697 | if image_file is not None: | |
698 | self.save_image(image_file) |
|
698 | self.save_image(image_file) | |
699 |
|
699 | |||
700 | return ret, image_directive |
|
700 | return ret, image_directive | |
701 |
|
701 | |||
702 | def ensure_pyplot(self): |
|
702 | def ensure_pyplot(self): | |
703 | """ |
|
703 | """ | |
704 | Ensures that pyplot has been imported into the embedded IPython shell. |
|
704 | Ensures that pyplot has been imported into the embedded IPython shell. | |
705 |
|
705 | |||
706 | Also, makes sure to set the backend appropriately if not set already. |
|
706 | Also, makes sure to set the backend appropriately if not set already. | |
707 |
|
707 | |||
708 | """ |
|
708 | """ | |
709 | # We are here if the @figure pseudo decorator was used. Thus, it's |
|
709 | # We are here if the @figure pseudo decorator was used. Thus, it's | |
710 | # possible that we could be here even if python_mplbackend were set to |
|
710 | # possible that we could be here even if python_mplbackend were set to | |
711 | # `None`. That's also strange and perhaps worthy of raising an |
|
711 | # `None`. That's also strange and perhaps worthy of raising an | |
712 | # exception, but for now, we just set the backend to 'agg'. |
|
712 | # exception, but for now, we just set the backend to 'agg'. | |
713 |
|
713 | |||
714 | if not self._pyplot_imported: |
|
714 | if not self._pyplot_imported: | |
715 | if 'matplotlib.backends' not in sys.modules: |
|
715 | if 'matplotlib.backends' not in sys.modules: | |
716 | # Then ipython_matplotlib was set to None but there was a |
|
716 | # Then ipython_matplotlib was set to None but there was a | |
717 | # call to the @figure decorator (and ipython_execlines did |
|
717 | # call to the @figure decorator (and ipython_execlines did | |
718 | # not set a backend). |
|
718 | # not set a backend). | |
719 | #raise Exception("No backend was set, but @figure was used!") |
|
719 | #raise Exception("No backend was set, but @figure was used!") | |
720 | import matplotlib |
|
720 | import matplotlib | |
721 | matplotlib.use('agg') |
|
721 | matplotlib.use('agg') | |
722 |
|
722 | |||
723 | # Always import pyplot into embedded shell. |
|
723 | # Always import pyplot into embedded shell. | |
724 | self.process_input_line('import matplotlib.pyplot as plt', |
|
724 | self.process_input_line('import matplotlib.pyplot as plt', | |
725 | store_history=False) |
|
725 | store_history=False) | |
726 | self._pyplot_imported = True |
|
726 | self._pyplot_imported = True | |
727 |
|
727 | |||
728 | def process_pure_python(self, content): |
|
728 | def process_pure_python(self, content): | |
729 | """ |
|
729 | """ | |
730 | content is a list of strings. it is unedited directive content |
|
730 | content is a list of strings. it is unedited directive content | |
731 |
|
731 | |||
732 | This runs it line by line in the InteractiveShell, prepends |
|
732 | This runs it line by line in the InteractiveShell, prepends | |
733 | prompts as needed capturing stderr and stdout, then returns |
|
733 | prompts as needed capturing stderr and stdout, then returns | |
734 | the content as a list as if it were ipython code |
|
734 | the content as a list as if it were ipython code | |
735 | """ |
|
735 | """ | |
736 | output = [] |
|
736 | output = [] | |
737 | savefig = False # keep up with this to clear figure |
|
737 | savefig = False # keep up with this to clear figure | |
738 | multiline = False # to handle line continuation |
|
738 | multiline = False # to handle line continuation | |
739 | multiline_start = None |
|
739 | multiline_start = None | |
740 | fmtin = self.promptin |
|
740 | fmtin = self.promptin | |
741 |
|
741 | |||
742 | ct = 0 |
|
742 | ct = 0 | |
743 |
|
743 | |||
744 | for lineno, line in enumerate(content): |
|
744 | for lineno, line in enumerate(content): | |
745 |
|
745 | |||
746 | line_stripped = line.strip() |
|
746 | line_stripped = line.strip() | |
747 | if not len(line): |
|
747 | if not len(line): | |
748 | output.append(line) |
|
748 | output.append(line) | |
749 | continue |
|
749 | continue | |
750 |
|
750 | |||
751 | # handle decorators |
|
751 | # handle decorators | |
752 | if line_stripped.startswith('@'): |
|
752 | if line_stripped.startswith('@'): | |
753 | output.extend([line]) |
|
753 | output.extend([line]) | |
754 | if 'savefig' in line: |
|
754 | if 'savefig' in line: | |
755 | savefig = True # and need to clear figure |
|
755 | savefig = True # and need to clear figure | |
756 | continue |
|
756 | continue | |
757 |
|
757 | |||
758 | # handle comments |
|
758 | # handle comments | |
759 | if line_stripped.startswith('#'): |
|
759 | if line_stripped.startswith('#'): | |
760 | output.extend([line]) |
|
760 | output.extend([line]) | |
761 | continue |
|
761 | continue | |
762 |
|
762 | |||
763 | # deal with lines checking for multiline |
|
763 | # deal with lines checking for multiline | |
764 | continuation = u' %s:'% ''.join(['.']*(len(str(ct))+2)) |
|
764 | continuation = u' %s:'% ''.join(['.']*(len(str(ct))+2)) | |
765 | if not multiline: |
|
765 | if not multiline: | |
766 | modified = u"%s %s" % (fmtin % ct, line_stripped) |
|
766 | modified = u"%s %s" % (fmtin % ct, line_stripped) | |
767 | output.append(modified) |
|
767 | output.append(modified) | |
768 | ct += 1 |
|
768 | ct += 1 | |
769 | try: |
|
769 | try: | |
770 | ast.parse(line_stripped) |
|
770 | ast.parse(line_stripped) | |
771 | output.append(u'') |
|
771 | output.append(u'') | |
772 | except Exception: # on a multiline |
|
772 | except Exception: # on a multiline | |
773 | multiline = True |
|
773 | multiline = True | |
774 | multiline_start = lineno |
|
774 | multiline_start = lineno | |
775 | else: # still on a multiline |
|
775 | else: # still on a multiline | |
776 | modified = u'%s %s' % (continuation, line) |
|
776 | modified = u'%s %s' % (continuation, line) | |
777 | output.append(modified) |
|
777 | output.append(modified) | |
778 |
|
778 | |||
779 | # if the next line is indented, it should be part of multiline |
|
779 | # if the next line is indented, it should be part of multiline | |
780 | if len(content) > lineno + 1: |
|
780 | if len(content) > lineno + 1: | |
781 | nextline = content[lineno + 1] |
|
781 | nextline = content[lineno + 1] | |
782 | if len(nextline) - len(nextline.lstrip()) > 3: |
|
782 | if len(nextline) - len(nextline.lstrip()) > 3: | |
783 | continue |
|
783 | continue | |
784 | try: |
|
784 | try: | |
785 | mod = ast.parse( |
|
785 | mod = ast.parse( | |
786 | '\n'.join(content[multiline_start:lineno+1])) |
|
786 | '\n'.join(content[multiline_start:lineno+1])) | |
787 | if isinstance(mod.body[0], ast.FunctionDef): |
|
787 | if isinstance(mod.body[0], ast.FunctionDef): | |
788 | # check to see if we have the whole function |
|
788 | # check to see if we have the whole function | |
789 | for element in mod.body[0].body: |
|
789 | for element in mod.body[0].body: | |
790 | if isinstance(element, ast.Return): |
|
790 | if isinstance(element, ast.Return): | |
791 | multiline = False |
|
791 | multiline = False | |
792 | else: |
|
792 | else: | |
793 | output.append(u'') |
|
793 | output.append(u'') | |
794 | multiline = False |
|
794 | multiline = False | |
795 | except Exception: |
|
795 | except Exception: | |
796 | pass |
|
796 | pass | |
797 |
|
797 | |||
798 | if savefig: # clear figure if plotted |
|
798 | if savefig: # clear figure if plotted | |
799 | self.ensure_pyplot() |
|
799 | self.ensure_pyplot() | |
800 | self.process_input_line('plt.clf()', store_history=False) |
|
800 | self.process_input_line('plt.clf()', store_history=False) | |
801 | self.clear_cout() |
|
801 | self.clear_cout() | |
802 | savefig = False |
|
802 | savefig = False | |
803 |
|
803 | |||
804 | return output |
|
804 | return output | |
805 |
|
805 | |||
806 | def custom_doctest(self, decorator, input_lines, found, submitted): |
|
806 | def custom_doctest(self, decorator, input_lines, found, submitted): | |
807 | """ |
|
807 | """ | |
808 | Perform a specialized doctest. |
|
808 | Perform a specialized doctest. | |
809 |
|
809 | |||
810 | """ |
|
810 | """ | |
811 | from .custom_doctests import doctests |
|
811 | from .custom_doctests import doctests | |
812 |
|
812 | |||
813 | args = decorator.split() |
|
813 | args = decorator.split() | |
814 | doctest_type = args[1] |
|
814 | doctest_type = args[1] | |
815 | if doctest_type in doctests: |
|
815 | if doctest_type in doctests: | |
816 | doctests[doctest_type](self, args, input_lines, found, submitted) |
|
816 | doctests[doctest_type](self, args, input_lines, found, submitted) | |
817 | else: |
|
817 | else: | |
818 | e = "Invalid option to @doctest: {0}".format(doctest_type) |
|
818 | e = "Invalid option to @doctest: {0}".format(doctest_type) | |
819 | raise Exception(e) |
|
819 | raise Exception(e) | |
820 |
|
820 | |||
821 |
|
821 | |||
822 | class IPythonDirective(Directive): |
|
822 | class IPythonDirective(Directive): | |
823 |
|
823 | |||
824 | has_content = True |
|
824 | has_content = True | |
825 | required_arguments = 0 |
|
825 | required_arguments = 0 | |
826 | optional_arguments = 4 # python, suppress, verbatim, doctest |
|
826 | optional_arguments = 4 # python, suppress, verbatim, doctest | |
827 | final_argumuent_whitespace = True |
|
827 | final_argumuent_whitespace = True | |
828 | option_spec = { 'python': directives.unchanged, |
|
828 | option_spec = { 'python': directives.unchanged, | |
829 | 'suppress' : directives.flag, |
|
829 | 'suppress' : directives.flag, | |
830 | 'verbatim' : directives.flag, |
|
830 | 'verbatim' : directives.flag, | |
831 | 'doctest' : directives.flag, |
|
831 | 'doctest' : directives.flag, | |
832 | 'okexcept': directives.flag, |
|
832 | 'okexcept': directives.flag, | |
833 | 'okwarning': directives.flag |
|
833 | 'okwarning': directives.flag | |
834 | } |
|
834 | } | |
835 |
|
835 | |||
836 | shell = None |
|
836 | shell = None | |
837 |
|
837 | |||
838 | seen_docs = set() |
|
838 | seen_docs = set() | |
839 |
|
839 | |||
840 | def get_config_options(self): |
|
840 | def get_config_options(self): | |
841 | # contains sphinx configuration variables |
|
841 | # contains sphinx configuration variables | |
842 | config = self.state.document.settings.env.config |
|
842 | config = self.state.document.settings.env.config | |
843 |
|
843 | |||
844 | # get config variables to set figure output directory |
|
844 | # get config variables to set figure output directory | |
845 | savefig_dir = config.ipython_savefig_dir |
|
845 | savefig_dir = config.ipython_savefig_dir | |
846 | source_dir = self.state.document.settings.env.srcdir |
|
846 | source_dir = self.state.document.settings.env.srcdir | |
847 | savefig_dir = os.path.join(source_dir, savefig_dir) |
|
847 | savefig_dir = os.path.join(source_dir, savefig_dir) | |
848 |
|
848 | |||
849 | # get regex and prompt stuff |
|
849 | # get regex and prompt stuff | |
850 | rgxin = config.ipython_rgxin |
|
850 | rgxin = config.ipython_rgxin | |
851 | rgxout = config.ipython_rgxout |
|
851 | rgxout = config.ipython_rgxout | |
852 | promptin = config.ipython_promptin |
|
852 | promptin = config.ipython_promptin | |
853 | promptout = config.ipython_promptout |
|
853 | promptout = config.ipython_promptout | |
854 | mplbackend = config.ipython_mplbackend |
|
854 | mplbackend = config.ipython_mplbackend | |
855 | exec_lines = config.ipython_execlines |
|
855 | exec_lines = config.ipython_execlines | |
856 | hold_count = config.ipython_holdcount |
|
856 | hold_count = config.ipython_holdcount | |
857 |
|
857 | |||
858 | return (savefig_dir, source_dir, rgxin, rgxout, |
|
858 | return (savefig_dir, source_dir, rgxin, rgxout, | |
859 | promptin, promptout, mplbackend, exec_lines, hold_count) |
|
859 | promptin, promptout, mplbackend, exec_lines, hold_count) | |
860 |
|
860 | |||
861 | def setup(self): |
|
861 | def setup(self): | |
862 | # Get configuration values. |
|
862 | # Get configuration values. | |
863 | (savefig_dir, source_dir, rgxin, rgxout, promptin, promptout, |
|
863 | (savefig_dir, source_dir, rgxin, rgxout, promptin, promptout, | |
864 | mplbackend, exec_lines, hold_count) = self.get_config_options() |
|
864 | mplbackend, exec_lines, hold_count) = self.get_config_options() | |
865 |
|
865 | |||
866 | try: |
|
866 | try: | |
867 | os.makedirs(savefig_dir) |
|
867 | os.makedirs(savefig_dir) | |
868 | except OSError as e: |
|
868 | except OSError as e: | |
869 | if e.errno != errno.EEXIST: |
|
869 | if e.errno != errno.EEXIST: | |
870 | raise |
|
870 | raise | |
871 |
|
871 | |||
872 | if self.shell is None: |
|
872 | if self.shell is None: | |
873 | # We will be here many times. However, when the |
|
873 | # We will be here many times. However, when the | |
874 | # EmbeddedSphinxShell is created, its interactive shell member |
|
874 | # EmbeddedSphinxShell is created, its interactive shell member | |
875 | # is the same for each instance. |
|
875 | # is the same for each instance. | |
876 |
|
876 | |||
877 | if mplbackend and 'matplotlib.backends' not in sys.modules: |
|
877 | if mplbackend and 'matplotlib.backends' not in sys.modules: | |
878 | import matplotlib |
|
878 | import matplotlib | |
879 | matplotlib.use(mplbackend) |
|
879 | matplotlib.use(mplbackend) | |
880 |
|
880 | |||
881 | # Must be called after (potentially) importing matplotlib and |
|
881 | # Must be called after (potentially) importing matplotlib and | |
882 | # setting its backend since exec_lines might import pylab. |
|
882 | # setting its backend since exec_lines might import pylab. | |
883 | self.shell = EmbeddedSphinxShell(exec_lines) |
|
883 | self.shell = EmbeddedSphinxShell(exec_lines) | |
884 |
|
884 | |||
885 | # Store IPython directive to enable better error messages |
|
885 | # Store IPython directive to enable better error messages | |
886 | self.shell.directive = self |
|
886 | self.shell.directive = self | |
887 |
|
887 | |||
888 | # reset the execution count if we haven't processed this doc |
|
888 | # reset the execution count if we haven't processed this doc | |
889 | #NOTE: this may be borked if there are multiple seen_doc tmp files |
|
889 | #NOTE: this may be borked if there are multiple seen_doc tmp files | |
890 | #check time stamp? |
|
890 | #check time stamp? | |
891 | if not self.state.document.current_source in self.seen_docs: |
|
891 | if not self.state.document.current_source in self.seen_docs: | |
892 | self.shell.IP.history_manager.reset() |
|
892 | self.shell.IP.history_manager.reset() | |
893 | self.shell.IP.execution_count = 1 |
|
893 | self.shell.IP.execution_count = 1 | |
894 | self.seen_docs.add(self.state.document.current_source) |
|
894 | self.seen_docs.add(self.state.document.current_source) | |
895 |
|
895 | |||
896 | # and attach to shell so we don't have to pass them around |
|
896 | # and attach to shell so we don't have to pass them around | |
897 | self.shell.rgxin = rgxin |
|
897 | self.shell.rgxin = rgxin | |
898 | self.shell.rgxout = rgxout |
|
898 | self.shell.rgxout = rgxout | |
899 | self.shell.promptin = promptin |
|
899 | self.shell.promptin = promptin | |
900 | self.shell.promptout = promptout |
|
900 | self.shell.promptout = promptout | |
901 | self.shell.savefig_dir = savefig_dir |
|
901 | self.shell.savefig_dir = savefig_dir | |
902 | self.shell.source_dir = source_dir |
|
902 | self.shell.source_dir = source_dir | |
903 | self.shell.hold_count = hold_count |
|
903 | self.shell.hold_count = hold_count | |
904 |
|
904 | |||
905 | # setup bookmark for saving figures directory |
|
905 | # setup bookmark for saving figures directory | |
906 | self.shell.process_input_line('bookmark ipy_savedir %s'%savefig_dir, |
|
906 | self.shell.process_input_line('bookmark ipy_savedir %s'%savefig_dir, | |
907 | store_history=False) |
|
907 | store_history=False) | |
908 | self.shell.clear_cout() |
|
908 | self.shell.clear_cout() | |
909 |
|
909 | |||
910 | return rgxin, rgxout, promptin, promptout |
|
910 | return rgxin, rgxout, promptin, promptout | |
911 |
|
911 | |||
912 | def teardown(self): |
|
912 | def teardown(self): | |
913 | # delete last bookmark |
|
913 | # delete last bookmark | |
914 | self.shell.process_input_line('bookmark -d ipy_savedir', |
|
914 | self.shell.process_input_line('bookmark -d ipy_savedir', | |
915 | store_history=False) |
|
915 | store_history=False) | |
916 | self.shell.clear_cout() |
|
916 | self.shell.clear_cout() | |
917 |
|
917 | |||
918 | def run(self): |
|
918 | def run(self): | |
919 | debug = False |
|
919 | debug = False | |
920 |
|
920 | |||
921 | #TODO, any reason block_parser can't be a method of embeddable shell |
|
921 | #TODO, any reason block_parser can't be a method of embeddable shell | |
922 | # then we wouldn't have to carry these around |
|
922 | # then we wouldn't have to carry these around | |
923 | rgxin, rgxout, promptin, promptout = self.setup() |
|
923 | rgxin, rgxout, promptin, promptout = self.setup() | |
924 |
|
924 | |||
925 | options = self.options |
|
925 | options = self.options | |
926 | self.shell.is_suppress = 'suppress' in options |
|
926 | self.shell.is_suppress = 'suppress' in options | |
927 | self.shell.is_doctest = 'doctest' in options |
|
927 | self.shell.is_doctest = 'doctest' in options | |
928 | self.shell.is_verbatim = 'verbatim' in options |
|
928 | self.shell.is_verbatim = 'verbatim' in options | |
929 | self.shell.is_okexcept = 'okexcept' in options |
|
929 | self.shell.is_okexcept = 'okexcept' in options | |
930 | self.shell.is_okwarning = 'okwarning' in options |
|
930 | self.shell.is_okwarning = 'okwarning' in options | |
931 |
|
931 | |||
932 | # handle pure python code |
|
932 | # handle pure python code | |
933 | if 'python' in self.arguments: |
|
933 | if 'python' in self.arguments: | |
934 | content = self.content |
|
934 | content = self.content | |
935 | self.content = self.shell.process_pure_python(content) |
|
935 | self.content = self.shell.process_pure_python(content) | |
936 |
|
936 | |||
937 | # parts consists of all text within the ipython-block. |
|
937 | # parts consists of all text within the ipython-block. | |
938 | # Each part is an input/output block. |
|
938 | # Each part is an input/output block. | |
939 | parts = '\n'.join(self.content).split('\n\n') |
|
939 | parts = '\n'.join(self.content).split('\n\n') | |
940 |
|
940 | |||
941 | lines = ['.. code-block:: ipython', ''] |
|
941 | lines = ['.. code-block:: ipython', ''] | |
942 | figures = [] |
|
942 | figures = [] | |
943 |
|
943 | |||
944 | for part in parts: |
|
944 | for part in parts: | |
945 | block = block_parser(part, rgxin, rgxout, promptin, promptout) |
|
945 | block = block_parser(part, rgxin, rgxout, promptin, promptout) | |
946 | if len(block): |
|
946 | if len(block): | |
947 | rows, figure = self.shell.process_block(block) |
|
947 | rows, figure = self.shell.process_block(block) | |
948 | for row in rows: |
|
948 | for row in rows: | |
949 | lines.extend([' {0}'.format(line) |
|
949 | lines.extend([' {0}'.format(line) | |
950 | for line in row.split('\n')]) |
|
950 | for line in row.split('\n')]) | |
951 |
|
951 | |||
952 | if figure is not None: |
|
952 | if figure is not None: | |
953 | figures.append(figure) |
|
953 | figures.append(figure) | |
954 |
|
954 | |||
955 | for figure in figures: |
|
955 | for figure in figures: | |
956 | lines.append('') |
|
956 | lines.append('') | |
957 | lines.extend(figure.split('\n')) |
|
957 | lines.extend(figure.split('\n')) | |
958 | lines.append('') |
|
958 | lines.append('') | |
959 |
|
959 | |||
960 | if len(lines) > 2: |
|
960 | if len(lines) > 2: | |
961 | if debug: |
|
961 | if debug: | |
962 | print('\n'.join(lines)) |
|
962 | print('\n'.join(lines)) | |
963 | else: |
|
963 | else: | |
964 | # This has to do with input, not output. But if we comment |
|
964 | # This has to do with input, not output. But if we comment | |
965 | # these lines out, then no IPython code will appear in the |
|
965 | # these lines out, then no IPython code will appear in the | |
966 | # final output. |
|
966 | # final output. | |
967 | self.state_machine.insert_input( |
|
967 | self.state_machine.insert_input( | |
968 | lines, self.state_machine.input_lines.source(0)) |
|
968 | lines, self.state_machine.input_lines.source(0)) | |
969 |
|
969 | |||
970 | # cleanup |
|
970 | # cleanup | |
971 | self.teardown() |
|
971 | self.teardown() | |
972 |
|
972 | |||
973 | return [] |
|
973 | return [] | |
974 |
|
974 | |||
975 | # Enable as a proper Sphinx directive |
|
975 | # Enable as a proper Sphinx directive | |
976 | def setup(app): |
|
976 | def setup(app): | |
977 | setup.app = app |
|
977 | setup.app = app | |
978 |
|
978 | |||
979 | app.add_directive('ipython', IPythonDirective) |
|
979 | app.add_directive('ipython', IPythonDirective) | |
980 | app.add_config_value('ipython_savefig_dir', 'savefig', 'env') |
|
980 | app.add_config_value('ipython_savefig_dir', 'savefig', 'env') | |
981 | app.add_config_value('ipython_rgxin', |
|
981 | app.add_config_value('ipython_rgxin', | |
982 | re.compile('In \[(\d+)\]:\s?(.*)\s*'), 'env') |
|
982 | re.compile('In \[(\d+)\]:\s?(.*)\s*'), 'env') | |
983 | app.add_config_value('ipython_rgxout', |
|
983 | app.add_config_value('ipython_rgxout', | |
984 | re.compile('Out\[(\d+)\]:\s?(.*)\s*'), 'env') |
|
984 | re.compile('Out\[(\d+)\]:\s?(.*)\s*'), 'env') | |
985 | app.add_config_value('ipython_promptin', 'In [%d]:', 'env') |
|
985 | app.add_config_value('ipython_promptin', 'In [%d]:', 'env') | |
986 | app.add_config_value('ipython_promptout', 'Out[%d]:', 'env') |
|
986 | app.add_config_value('ipython_promptout', 'Out[%d]:', 'env') | |
987 |
|
987 | |||
988 | # We could just let matplotlib pick whatever is specified as the default |
|
988 | # We could just let matplotlib pick whatever is specified as the default | |
989 | # backend in the matplotlibrc file, but this would cause issues if the |
|
989 | # backend in the matplotlibrc file, but this would cause issues if the | |
990 | # backend didn't work in headless environments. For this reason, 'agg' |
|
990 | # backend didn't work in headless environments. For this reason, 'agg' | |
991 | # is a good default backend choice. |
|
991 | # is a good default backend choice. | |
992 | app.add_config_value('ipython_mplbackend', 'agg', 'env') |
|
992 | app.add_config_value('ipython_mplbackend', 'agg', 'env') | |
993 |
|
993 | |||
994 | # If the user sets this config value to `None`, then EmbeddedSphinxShell's |
|
994 | # If the user sets this config value to `None`, then EmbeddedSphinxShell's | |
995 | # __init__ method will treat it as []. |
|
995 | # __init__ method will treat it as []. | |
996 | execlines = ['import numpy as np', 'import matplotlib.pyplot as plt'] |
|
996 | execlines = ['import numpy as np', 'import matplotlib.pyplot as plt'] | |
997 | app.add_config_value('ipython_execlines', execlines, 'env') |
|
997 | app.add_config_value('ipython_execlines', execlines, 'env') | |
998 |
|
998 | |||
999 | app.add_config_value('ipython_holdcount', True, 'env') |
|
999 | app.add_config_value('ipython_holdcount', True, 'env') | |
1000 |
|
1000 | |||
1001 | metadata = {'parallel_read_safe': True, 'parallel_write_safe': True} |
|
1001 | metadata = {'parallel_read_safe': True, 'parallel_write_safe': True} | |
1002 | return metadata |
|
1002 | return metadata | |
1003 |
|
1003 | |||
1004 | # Simple smoke test, needs to be converted to a proper automatic test. |
|
1004 | # Simple smoke test, needs to be converted to a proper automatic test. | |
1005 | def test(): |
|
1005 | def test(): | |
1006 |
|
1006 | |||
1007 | examples = [ |
|
1007 | examples = [ | |
1008 | r""" |
|
1008 | r""" | |
1009 | In [9]: pwd |
|
1009 | In [9]: pwd | |
1010 | Out[9]: '/home/jdhunter/py4science/book' |
|
1010 | Out[9]: '/home/jdhunter/py4science/book' | |
1011 |
|
1011 | |||
1012 | In [10]: cd bookdata/ |
|
1012 | In [10]: cd bookdata/ | |
1013 | /home/jdhunter/py4science/book/bookdata |
|
1013 | /home/jdhunter/py4science/book/bookdata | |
1014 |
|
1014 | |||
1015 | In [2]: from pylab import * |
|
1015 | In [2]: from pylab import * | |
1016 |
|
1016 | |||
1017 | In [2]: ion() |
|
1017 | In [2]: ion() | |
1018 |
|
1018 | |||
1019 | In [3]: im = imread('stinkbug.png') |
|
1019 | In [3]: im = imread('stinkbug.png') | |
1020 |
|
1020 | |||
1021 | @savefig mystinkbug.png width=4in |
|
1021 | @savefig mystinkbug.png width=4in | |
1022 | In [4]: imshow(im) |
|
1022 | In [4]: imshow(im) | |
1023 | Out[4]: <matplotlib.image.AxesImage object at 0x39ea850> |
|
1023 | Out[4]: <matplotlib.image.AxesImage object at 0x39ea850> | |
1024 |
|
1024 | |||
1025 | """, |
|
1025 | """, | |
1026 | r""" |
|
1026 | r""" | |
1027 |
|
1027 | |||
1028 | In [1]: x = 'hello world' |
|
1028 | In [1]: x = 'hello world' | |
1029 |
|
1029 | |||
1030 | # string methods can be |
|
1030 | # string methods can be | |
1031 | # used to alter the string |
|
1031 | # used to alter the string | |
1032 | @doctest |
|
1032 | @doctest | |
1033 | In [2]: x.upper() |
|
1033 | In [2]: x.upper() | |
1034 | Out[2]: 'HELLO WORLD' |
|
1034 | Out[2]: 'HELLO WORLD' | |
1035 |
|
1035 | |||
1036 | @verbatim |
|
1036 | @verbatim | |
1037 | In [3]: x.st<TAB> |
|
1037 | In [3]: x.st<TAB> | |
1038 | x.startswith x.strip |
|
1038 | x.startswith x.strip | |
1039 | """, |
|
1039 | """, | |
1040 | r""" |
|
1040 | r""" | |
1041 |
|
1041 | |||
1042 | In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\ |
|
1042 | In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\ | |
1043 | .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv' |
|
1043 | .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv' | |
1044 |
|
1044 | |||
1045 | In [131]: print url.split('&') |
|
1045 | In [131]: print url.split('&') | |
1046 | ['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', 'f=2009', 'g=d', 'a=1', 'b=8', 'c=2006', 'ignore=.csv'] |
|
1046 | ['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', 'f=2009', 'g=d', 'a=1', 'b=8', 'c=2006', 'ignore=.csv'] | |
1047 |
|
1047 | |||
1048 | In [60]: import urllib |
|
1048 | In [60]: import urllib | |
1049 |
|
1049 | |||
1050 | """, |
|
1050 | """, | |
1051 | r"""\ |
|
1051 | r"""\ | |
1052 |
|
1052 | |||
1053 | In [133]: import numpy.random |
|
1053 | In [133]: import numpy.random | |
1054 |
|
1054 | |||
1055 | @suppress |
|
1055 | @suppress | |
1056 | In [134]: numpy.random.seed(2358) |
|
1056 | In [134]: numpy.random.seed(2358) | |
1057 |
|
1057 | |||
1058 | @doctest |
|
1058 | @doctest | |
1059 | In [135]: numpy.random.rand(10,2) |
|
1059 | In [135]: numpy.random.rand(10,2) | |
1060 | Out[135]: |
|
1060 | Out[135]: | |
1061 | array([[ 0.64524308, 0.59943846], |
|
1061 | array([[ 0.64524308, 0.59943846], | |
1062 | [ 0.47102322, 0.8715456 ], |
|
1062 | [ 0.47102322, 0.8715456 ], | |
1063 | [ 0.29370834, 0.74776844], |
|
1063 | [ 0.29370834, 0.74776844], | |
1064 | [ 0.99539577, 0.1313423 ], |
|
1064 | [ 0.99539577, 0.1313423 ], | |
1065 | [ 0.16250302, 0.21103583], |
|
1065 | [ 0.16250302, 0.21103583], | |
1066 | [ 0.81626524, 0.1312433 ], |
|
1066 | [ 0.81626524, 0.1312433 ], | |
1067 | [ 0.67338089, 0.72302393], |
|
1067 | [ 0.67338089, 0.72302393], | |
1068 | [ 0.7566368 , 0.07033696], |
|
1068 | [ 0.7566368 , 0.07033696], | |
1069 | [ 0.22591016, 0.77731835], |
|
1069 | [ 0.22591016, 0.77731835], | |
1070 | [ 0.0072729 , 0.34273127]]) |
|
1070 | [ 0.0072729 , 0.34273127]]) | |
1071 |
|
1071 | |||
1072 | """, |
|
1072 | """, | |
1073 |
|
1073 | |||
1074 | r""" |
|
1074 | r""" | |
1075 | In [106]: print x |
|
1075 | In [106]: print x | |
1076 | jdh |
|
1076 | jdh | |
1077 |
|
1077 | |||
1078 | In [109]: for i in range(10): |
|
1078 | In [109]: for i in range(10): | |
1079 | .....: print i |
|
1079 | .....: print i | |
1080 | .....: |
|
1080 | .....: | |
1081 | .....: |
|
1081 | .....: | |
1082 | 0 |
|
1082 | 0 | |
1083 | 1 |
|
1083 | 1 | |
1084 | 2 |
|
1084 | 2 | |
1085 | 3 |
|
1085 | 3 | |
1086 | 4 |
|
1086 | 4 | |
1087 | 5 |
|
1087 | 5 | |
1088 | 6 |
|
1088 | 6 | |
1089 | 7 |
|
1089 | 7 | |
1090 | 8 |
|
1090 | 8 | |
1091 | 9 |
|
1091 | 9 | |
1092 | """, |
|
1092 | """, | |
1093 |
|
1093 | |||
1094 | r""" |
|
1094 | r""" | |
1095 |
|
1095 | |||
1096 | In [144]: from pylab import * |
|
1096 | In [144]: from pylab import * | |
1097 |
|
1097 | |||
1098 | In [145]: ion() |
|
1098 | In [145]: ion() | |
1099 |
|
1099 | |||
1100 | # use a semicolon to suppress the output |
|
1100 | # use a semicolon to suppress the output | |
1101 | @savefig test_hist.png width=4in |
|
1101 | @savefig test_hist.png width=4in | |
1102 | In [151]: hist(np.random.randn(10000), 100); |
|
1102 | In [151]: hist(np.random.randn(10000), 100); | |
1103 |
|
1103 | |||
1104 |
|
1104 | |||
1105 | @savefig test_plot.png width=4in |
|
1105 | @savefig test_plot.png width=4in | |
1106 | In [151]: plot(np.random.randn(10000), 'o'); |
|
1106 | In [151]: plot(np.random.randn(10000), 'o'); | |
1107 | """, |
|
1107 | """, | |
1108 |
|
1108 | |||
1109 | r""" |
|
1109 | r""" | |
1110 | # use a semicolon to suppress the output |
|
1110 | # use a semicolon to suppress the output | |
1111 | In [151]: plt.clf() |
|
1111 | In [151]: plt.clf() | |
1112 |
|
1112 | |||
1113 | @savefig plot_simple.png width=4in |
|
1113 | @savefig plot_simple.png width=4in | |
1114 | In [151]: plot([1,2,3]) |
|
1114 | In [151]: plot([1,2,3]) | |
1115 |
|
1115 | |||
1116 | @savefig hist_simple.png width=4in |
|
1116 | @savefig hist_simple.png width=4in | |
1117 | In [151]: hist(np.random.randn(10000), 100); |
|
1117 | In [151]: hist(np.random.randn(10000), 100); | |
1118 |
|
1118 | |||
1119 | """, |
|
1119 | """, | |
1120 | r""" |
|
1120 | r""" | |
1121 | # update the current fig |
|
1121 | # update the current fig | |
1122 | In [151]: ylabel('number') |
|
1122 | In [151]: ylabel('number') | |
1123 |
|
1123 | |||
1124 | In [152]: title('normal distribution') |
|
1124 | In [152]: title('normal distribution') | |
1125 |
|
1125 | |||
1126 |
|
1126 | |||
1127 | @savefig hist_with_text.png |
|
1127 | @savefig hist_with_text.png | |
1128 | In [153]: grid(True) |
|
1128 | In [153]: grid(True) | |
1129 |
|
1129 | |||
1130 | @doctest float |
|
1130 | @doctest float | |
1131 | In [154]: 0.1 + 0.2 |
|
1131 | In [154]: 0.1 + 0.2 | |
1132 | Out[154]: 0.3 |
|
1132 | Out[154]: 0.3 | |
1133 |
|
1133 | |||
1134 | @doctest float |
|
1134 | @doctest float | |
1135 | In [155]: np.arange(16).reshape(4,4) |
|
1135 | In [155]: np.arange(16).reshape(4,4) | |
1136 | Out[155]: |
|
1136 | Out[155]: | |
1137 | array([[ 0, 1, 2, 3], |
|
1137 | array([[ 0, 1, 2, 3], | |
1138 | [ 4, 5, 6, 7], |
|
1138 | [ 4, 5, 6, 7], | |
1139 | [ 8, 9, 10, 11], |
|
1139 | [ 8, 9, 10, 11], | |
1140 | [12, 13, 14, 15]]) |
|
1140 | [12, 13, 14, 15]]) | |
1141 |
|
1141 | |||
1142 | In [1]: x = np.arange(16, dtype=float).reshape(4,4) |
|
1142 | In [1]: x = np.arange(16, dtype=float).reshape(4,4) | |
1143 |
|
1143 | |||
1144 | In [2]: x[0,0] = np.inf |
|
1144 | In [2]: x[0,0] = np.inf | |
1145 |
|
1145 | |||
1146 | In [3]: x[0,1] = np.nan |
|
1146 | In [3]: x[0,1] = np.nan | |
1147 |
|
1147 | |||
1148 | @doctest float |
|
1148 | @doctest float | |
1149 | In [4]: x |
|
1149 | In [4]: x | |
1150 | Out[4]: |
|
1150 | Out[4]: | |
1151 | array([[ inf, nan, 2., 3.], |
|
1151 | array([[ inf, nan, 2., 3.], | |
1152 | [ 4., 5., 6., 7.], |
|
1152 | [ 4., 5., 6., 7.], | |
1153 | [ 8., 9., 10., 11.], |
|
1153 | [ 8., 9., 10., 11.], | |
1154 | [ 12., 13., 14., 15.]]) |
|
1154 | [ 12., 13., 14., 15.]]) | |
1155 |
|
1155 | |||
1156 |
|
1156 | |||
1157 | """, |
|
1157 | """, | |
1158 | ] |
|
1158 | ] | |
1159 | # skip local-file depending first example: |
|
1159 | # skip local-file depending first example: | |
1160 | examples = examples[1:] |
|
1160 | examples = examples[1:] | |
1161 |
|
1161 | |||
1162 | #ipython_directive.DEBUG = True # dbg |
|
1162 | #ipython_directive.DEBUG = True # dbg | |
1163 | #options = dict(suppress=True) # dbg |
|
1163 | #options = dict(suppress=True) # dbg | |
1164 | options = {} |
|
1164 | options = {} | |
1165 | for example in examples: |
|
1165 | for example in examples: | |
1166 | content = example.split('\n') |
|
1166 | content = example.split('\n') | |
1167 | IPythonDirective('debug', arguments=None, options=options, |
|
1167 | IPythonDirective('debug', arguments=None, options=options, | |
1168 | content=content, lineno=0, |
|
1168 | content=content, lineno=0, | |
1169 | content_offset=None, block_text=None, |
|
1169 | content_offset=None, block_text=None, | |
1170 | state=None, state_machine=None, |
|
1170 | state=None, state_machine=None, | |
1171 | ) |
|
1171 | ) | |
1172 |
|
1172 | |||
1173 | # Run test suite as a script |
|
1173 | # Run test suite as a script | |
1174 | if __name__=='__main__': |
|
1174 | if __name__=='__main__': | |
1175 | if not os.path.isdir('_static'): |
|
1175 | if not os.path.isdir('_static'): | |
1176 | os.mkdir('_static') |
|
1176 | os.mkdir('_static') | |
1177 | test() |
|
1177 | test() | |
1178 | print('All OK? Check figures in _static/') |
|
1178 | print('All OK? Check figures in _static/') |
@@ -1,392 +1,392 b'' | |||||
1 | # encoding: utf-8 |
|
1 | # encoding: utf-8 | |
2 | """ |
|
2 | """ | |
3 | An embedded IPython shell. |
|
3 | An embedded IPython shell. | |
4 | """ |
|
4 | """ | |
5 | # Copyright (c) IPython Development Team. |
|
5 | # Copyright (c) IPython Development Team. | |
6 | # Distributed under the terms of the Modified BSD License. |
|
6 | # Distributed under the terms of the Modified BSD License. | |
7 |
|
7 | |||
8 |
|
8 | |||
9 | import sys |
|
9 | import sys | |
10 | import warnings |
|
10 | import warnings | |
11 |
|
11 | |||
12 | from IPython.core import ultratb, compilerop |
|
12 | from IPython.core import ultratb, compilerop | |
13 | from IPython.core import magic_arguments |
|
13 | from IPython.core import magic_arguments | |
14 | from IPython.core.magic import Magics, magics_class, line_magic |
|
14 | from IPython.core.magic import Magics, magics_class, line_magic | |
15 | from IPython.core.interactiveshell import DummyMod, InteractiveShell |
|
15 | from IPython.core.interactiveshell import DummyMod, InteractiveShell | |
16 | from IPython.terminal.interactiveshell import TerminalInteractiveShell |
|
16 | from IPython.terminal.interactiveshell import TerminalInteractiveShell | |
17 | from IPython.terminal.ipapp import load_default_config |
|
17 | from IPython.terminal.ipapp import load_default_config | |
18 |
|
18 | |||
19 | from traitlets import Bool, CBool, Unicode |
|
19 | from traitlets import Bool, CBool, Unicode | |
20 | from IPython.utils.io import ask_yes_no |
|
20 | from IPython.utils.io import ask_yes_no | |
21 |
|
21 | |||
22 | class KillEmbeded(Exception):pass |
|
22 | class KillEmbedded(Exception):pass | |
23 |
|
23 | |||
24 | # This is an additional magic that is exposed in embedded shells. |
|
24 | # This is an additional magic that is exposed in embedded shells. | |
25 | @magics_class |
|
25 | @magics_class | |
26 | class EmbeddedMagics(Magics): |
|
26 | class EmbeddedMagics(Magics): | |
27 |
|
27 | |||
28 | @line_magic |
|
28 | @line_magic | |
29 | @magic_arguments.magic_arguments() |
|
29 | @magic_arguments.magic_arguments() | |
30 | @magic_arguments.argument('-i', '--instance', action='store_true', |
|
30 | @magic_arguments.argument('-i', '--instance', action='store_true', | |
31 | help='Kill instance instead of call location') |
|
31 | help='Kill instance instead of call location') | |
32 | @magic_arguments.argument('-x', '--exit', action='store_true', |
|
32 | @magic_arguments.argument('-x', '--exit', action='store_true', | |
33 | help='Also exit the current session') |
|
33 | help='Also exit the current session') | |
34 | @magic_arguments.argument('-y', '--yes', action='store_true', |
|
34 | @magic_arguments.argument('-y', '--yes', action='store_true', | |
35 | help='Do not ask confirmation') |
|
35 | help='Do not ask confirmation') | |
36 | def kill_embedded(self, parameter_s=''): |
|
36 | def kill_embedded(self, parameter_s=''): | |
37 | """%kill_embedded : deactivate for good the current embedded IPython |
|
37 | """%kill_embedded : deactivate for good the current embedded IPython | |
38 |
|
38 | |||
39 | This function (after asking for confirmation) sets an internal flag so |
|
39 | This function (after asking for confirmation) sets an internal flag so | |
40 | that an embedded IPython will never activate again for the given call |
|
40 | that an embedded IPython will never activate again for the given call | |
41 | location. This is useful to permanently disable a shell that is being |
|
41 | location. This is useful to permanently disable a shell that is being | |
42 | called inside a loop: once you've figured out what you needed from it, |
|
42 | called inside a loop: once you've figured out what you needed from it, | |
43 | you may then kill it and the program will then continue to run without |
|
43 | you may then kill it and the program will then continue to run without | |
44 | the interactive shell interfering again. |
|
44 | the interactive shell interfering again. | |
45 |
|
45 | |||
46 |
|
46 | |||
47 | Kill Instance Option: |
|
47 | Kill Instance Option: | |
48 |
|
48 | |||
49 | If for some reasons you need to kill the location where the instance |
|
49 | If for some reasons you need to kill the location where the instance | |
50 | is created and not called, for example if you create a single |
|
50 | is created and not called, for example if you create a single | |
51 | instance in one place and debug in many locations, you can use the |
|
51 | instance in one place and debug in many locations, you can use the | |
52 | ``--instance`` option to kill this specific instance. Like for the |
|
52 | ``--instance`` option to kill this specific instance. Like for the | |
53 | ``call location`` killing an "instance" should work even if it is |
|
53 | ``call location`` killing an "instance" should work even if it is | |
54 | recreated within a loop. |
|
54 | recreated within a loop. | |
55 |
|
55 | |||
56 | .. note:: |
|
56 | .. note:: | |
57 |
|
57 | |||
58 | This was the default behavior before IPython 5.2 |
|
58 | This was the default behavior before IPython 5.2 | |
59 |
|
59 | |||
60 | """ |
|
60 | """ | |
61 |
|
61 | |||
62 | args = magic_arguments.parse_argstring(self.kill_embedded, parameter_s) |
|
62 | args = magic_arguments.parse_argstring(self.kill_embedded, parameter_s) | |
63 | print(args) |
|
63 | print(args) | |
64 | if args.instance: |
|
64 | if args.instance: | |
65 | # let no ask |
|
65 | # let no ask | |
66 | if not args.yes: |
|
66 | if not args.yes: | |
67 | kill = ask_yes_no( |
|
67 | kill = ask_yes_no( | |
68 | "Are you sure you want to kill this embedded instance? [y/N] ", 'n') |
|
68 | "Are you sure you want to kill this embedded instance? [y/N] ", 'n') | |
69 | else: |
|
69 | else: | |
70 | kill = True |
|
70 | kill = True | |
71 | if kill: |
|
71 | if kill: | |
72 | self.shell._disable_init_location() |
|
72 | self.shell._disable_init_location() | |
73 | print("This embedded IPython instance will not reactivate anymore " |
|
73 | print("This embedded IPython instance will not reactivate anymore " | |
74 | "once you exit.") |
|
74 | "once you exit.") | |
75 | else: |
|
75 | else: | |
76 | if not args.yes: |
|
76 | if not args.yes: | |
77 | kill = ask_yes_no( |
|
77 | kill = ask_yes_no( | |
78 | "Are you sure you want to kill this embedded call_location? [y/N] ", 'n') |
|
78 | "Are you sure you want to kill this embedded call_location? [y/N] ", 'n') | |
79 | else: |
|
79 | else: | |
80 | kill = True |
|
80 | kill = True | |
81 | if kill: |
|
81 | if kill: | |
82 | self.shell.embedded_active = False |
|
82 | self.shell.embedded_active = False | |
83 | print("This embedded IPython call location will not reactivate anymore " |
|
83 | print("This embedded IPython call location will not reactivate anymore " | |
84 | "once you exit.") |
|
84 | "once you exit.") | |
85 |
|
85 | |||
86 | if args.exit: |
|
86 | if args.exit: | |
87 | # Ask-exit does not really ask, it just set internals flags to exit |
|
87 | # Ask-exit does not really ask, it just set internals flags to exit | |
88 | # on next loop. |
|
88 | # on next loop. | |
89 | self.shell.ask_exit() |
|
89 | self.shell.ask_exit() | |
90 |
|
90 | |||
91 |
|
91 | |||
92 | @line_magic |
|
92 | @line_magic | |
93 | def exit_raise(self, parameter_s=''): |
|
93 | def exit_raise(self, parameter_s=''): | |
94 | """%exit_raise Make the current embedded kernel exit and raise and exception. |
|
94 | """%exit_raise Make the current embedded kernel exit and raise and exception. | |
95 |
|
95 | |||
96 | This function sets an internal flag so that an embedded IPython will |
|
96 | This function sets an internal flag so that an embedded IPython will | |
97 | raise a `IPython.terminal.embed.KillEmbeded` Exception on exit, and then exit the current I. This is |
|
97 | raise a `IPython.terminal.embed.KillEmbedded` Exception on exit, and then exit the current I. This is | |
98 | useful to permanently exit a loop that create IPython embed instance. |
|
98 | useful to permanently exit a loop that create IPython embed instance. | |
99 | """ |
|
99 | """ | |
100 |
|
100 | |||
101 | self.shell.should_raise = True |
|
101 | self.shell.should_raise = True | |
102 | self.shell.ask_exit() |
|
102 | self.shell.ask_exit() | |
103 |
|
103 | |||
104 |
|
104 | |||
105 |
|
105 | |||
106 | class InteractiveShellEmbed(TerminalInteractiveShell): |
|
106 | class InteractiveShellEmbed(TerminalInteractiveShell): | |
107 |
|
107 | |||
108 | dummy_mode = Bool(False) |
|
108 | dummy_mode = Bool(False) | |
109 | exit_msg = Unicode('') |
|
109 | exit_msg = Unicode('') | |
110 | embedded = CBool(True) |
|
110 | embedded = CBool(True) | |
111 | should_raise = CBool(False) |
|
111 | should_raise = CBool(False) | |
112 | # Like the base class display_banner is not configurable, but here it |
|
112 | # Like the base class display_banner is not configurable, but here it | |
113 | # is True by default. |
|
113 | # is True by default. | |
114 | display_banner = CBool(True) |
|
114 | display_banner = CBool(True) | |
115 | exit_msg = Unicode() |
|
115 | exit_msg = Unicode() | |
116 |
|
116 | |||
117 | # When embedding, by default we don't change the terminal title |
|
117 | # When embedding, by default we don't change the terminal title | |
118 | term_title = Bool(False, |
|
118 | term_title = Bool(False, | |
119 | help="Automatically set the terminal title" |
|
119 | help="Automatically set the terminal title" | |
120 | ).tag(config=True) |
|
120 | ).tag(config=True) | |
121 |
|
121 | |||
122 | _inactive_locations = set() |
|
122 | _inactive_locations = set() | |
123 |
|
123 | |||
124 | @property |
|
124 | @property | |
125 | def embedded_active(self): |
|
125 | def embedded_active(self): | |
126 | return (self._call_location_id not in InteractiveShellEmbed._inactive_locations)\ |
|
126 | return (self._call_location_id not in InteractiveShellEmbed._inactive_locations)\ | |
127 | and (self._init_location_id not in InteractiveShellEmbed._inactive_locations) |
|
127 | and (self._init_location_id not in InteractiveShellEmbed._inactive_locations) | |
128 |
|
128 | |||
129 | def _disable_init_location(self): |
|
129 | def _disable_init_location(self): | |
130 | """Disable the current Instance creation location""" |
|
130 | """Disable the current Instance creation location""" | |
131 | InteractiveShellEmbed._inactive_locations.add(self._init_location_id) |
|
131 | InteractiveShellEmbed._inactive_locations.add(self._init_location_id) | |
132 |
|
132 | |||
133 | @embedded_active.setter |
|
133 | @embedded_active.setter | |
134 | def embedded_active(self, value): |
|
134 | def embedded_active(self, value): | |
135 | if value: |
|
135 | if value: | |
136 | InteractiveShellEmbed._inactive_locations.discard( |
|
136 | InteractiveShellEmbed._inactive_locations.discard( | |
137 | self._call_location_id) |
|
137 | self._call_location_id) | |
138 | InteractiveShellEmbed._inactive_locations.discard( |
|
138 | InteractiveShellEmbed._inactive_locations.discard( | |
139 | self._init_location_id) |
|
139 | self._init_location_id) | |
140 | else: |
|
140 | else: | |
141 | InteractiveShellEmbed._inactive_locations.add( |
|
141 | InteractiveShellEmbed._inactive_locations.add( | |
142 | self._call_location_id) |
|
142 | self._call_location_id) | |
143 |
|
143 | |||
144 | def __init__(self, **kw): |
|
144 | def __init__(self, **kw): | |
145 | if kw.get('user_global_ns', None) is not None: |
|
145 | if kw.get('user_global_ns', None) is not None: | |
146 | raise DeprecationWarning( |
|
146 | raise DeprecationWarning( | |
147 | "Key word argument `user_global_ns` has been replaced by `user_module` since IPython 4.0.") |
|
147 | "Key word argument `user_global_ns` has been replaced by `user_module` since IPython 4.0.") | |
148 |
|
148 | |||
149 | clid = kw.pop('_init_location_id', None) |
|
149 | clid = kw.pop('_init_location_id', None) | |
150 | if not clid: |
|
150 | if not clid: | |
151 | frame = sys._getframe(1) |
|
151 | frame = sys._getframe(1) | |
152 | clid = '%s:%s' % (frame.f_code.co_filename, frame.f_lineno) |
|
152 | clid = '%s:%s' % (frame.f_code.co_filename, frame.f_lineno) | |
153 | self._init_location_id = clid |
|
153 | self._init_location_id = clid | |
154 |
|
154 | |||
155 | super(InteractiveShellEmbed,self).__init__(**kw) |
|
155 | super(InteractiveShellEmbed,self).__init__(**kw) | |
156 |
|
156 | |||
157 | # don't use the ipython crash handler so that user exceptions aren't |
|
157 | # don't use the ipython crash handler so that user exceptions aren't | |
158 | # trapped |
|
158 | # trapped | |
159 | sys.excepthook = ultratb.FormattedTB(color_scheme=self.colors, |
|
159 | sys.excepthook = ultratb.FormattedTB(color_scheme=self.colors, | |
160 | mode=self.xmode, |
|
160 | mode=self.xmode, | |
161 | call_pdb=self.pdb) |
|
161 | call_pdb=self.pdb) | |
162 |
|
162 | |||
163 | def init_sys_modules(self): |
|
163 | def init_sys_modules(self): | |
164 | """ |
|
164 | """ | |
165 | Explicitly overwrite :mod:`IPython.core.interactiveshell` to do nothing. |
|
165 | Explicitly overwrite :mod:`IPython.core.interactiveshell` to do nothing. | |
166 | """ |
|
166 | """ | |
167 | pass |
|
167 | pass | |
168 |
|
168 | |||
169 | def init_magics(self): |
|
169 | def init_magics(self): | |
170 | super(InteractiveShellEmbed, self).init_magics() |
|
170 | super(InteractiveShellEmbed, self).init_magics() | |
171 | self.register_magics(EmbeddedMagics) |
|
171 | self.register_magics(EmbeddedMagics) | |
172 |
|
172 | |||
173 | def __call__(self, header='', local_ns=None, module=None, dummy=None, |
|
173 | def __call__(self, header='', local_ns=None, module=None, dummy=None, | |
174 | stack_depth=1, global_ns=None, compile_flags=None, **kw): |
|
174 | stack_depth=1, global_ns=None, compile_flags=None, **kw): | |
175 | """Activate the interactive interpreter. |
|
175 | """Activate the interactive interpreter. | |
176 |
|
176 | |||
177 | __call__(self,header='',local_ns=None,module=None,dummy=None) -> Start |
|
177 | __call__(self,header='',local_ns=None,module=None,dummy=None) -> Start | |
178 | the interpreter shell with the given local and global namespaces, and |
|
178 | the interpreter shell with the given local and global namespaces, and | |
179 | optionally print a header string at startup. |
|
179 | optionally print a header string at startup. | |
180 |
|
180 | |||
181 | The shell can be globally activated/deactivated using the |
|
181 | The shell can be globally activated/deactivated using the | |
182 | dummy_mode attribute. This allows you to turn off a shell used |
|
182 | dummy_mode attribute. This allows you to turn off a shell used | |
183 | for debugging globally. |
|
183 | for debugging globally. | |
184 |
|
184 | |||
185 | However, *each* time you call the shell you can override the current |
|
185 | However, *each* time you call the shell you can override the current | |
186 | state of dummy_mode with the optional keyword parameter 'dummy'. For |
|
186 | state of dummy_mode with the optional keyword parameter 'dummy'. For | |
187 | example, if you set dummy mode on with IPShell.dummy_mode = True, you |
|
187 | example, if you set dummy mode on with IPShell.dummy_mode = True, you | |
188 | can still have a specific call work by making it as IPShell(dummy=False). |
|
188 | can still have a specific call work by making it as IPShell(dummy=False). | |
189 | """ |
|
189 | """ | |
190 |
|
190 | |||
191 | # we are called, set the underlying interactiveshell not to exit. |
|
191 | # we are called, set the underlying interactiveshell not to exit. | |
192 | self.keep_running = True |
|
192 | self.keep_running = True | |
193 |
|
193 | |||
194 | # If the user has turned it off, go away |
|
194 | # If the user has turned it off, go away | |
195 | clid = kw.pop('_call_location_id', None) |
|
195 | clid = kw.pop('_call_location_id', None) | |
196 | if not clid: |
|
196 | if not clid: | |
197 | frame = sys._getframe(1) |
|
197 | frame = sys._getframe(1) | |
198 | clid = '%s:%s' % (frame.f_code.co_filename, frame.f_lineno) |
|
198 | clid = '%s:%s' % (frame.f_code.co_filename, frame.f_lineno) | |
199 | self._call_location_id = clid |
|
199 | self._call_location_id = clid | |
200 |
|
200 | |||
201 | if not self.embedded_active: |
|
201 | if not self.embedded_active: | |
202 | return |
|
202 | return | |
203 |
|
203 | |||
204 | # Normal exits from interactive mode set this flag, so the shell can't |
|
204 | # Normal exits from interactive mode set this flag, so the shell can't | |
205 | # re-enter (it checks this variable at the start of interactive mode). |
|
205 | # re-enter (it checks this variable at the start of interactive mode). | |
206 | self.exit_now = False |
|
206 | self.exit_now = False | |
207 |
|
207 | |||
208 | # Allow the dummy parameter to override the global __dummy_mode |
|
208 | # Allow the dummy parameter to override the global __dummy_mode | |
209 | if dummy or (dummy != 0 and self.dummy_mode): |
|
209 | if dummy or (dummy != 0 and self.dummy_mode): | |
210 | return |
|
210 | return | |
211 |
|
211 | |||
212 | # self.banner is auto computed |
|
212 | # self.banner is auto computed | |
213 | if header: |
|
213 | if header: | |
214 | self.old_banner2 = self.banner2 |
|
214 | self.old_banner2 = self.banner2 | |
215 | self.banner2 = self.banner2 + '\n' + header + '\n' |
|
215 | self.banner2 = self.banner2 + '\n' + header + '\n' | |
216 | else: |
|
216 | else: | |
217 | self.old_banner2 = '' |
|
217 | self.old_banner2 = '' | |
218 |
|
218 | |||
219 | if self.display_banner: |
|
219 | if self.display_banner: | |
220 | self.show_banner() |
|
220 | self.show_banner() | |
221 |
|
221 | |||
222 | # Call the embedding code with a stack depth of 1 so it can skip over |
|
222 | # Call the embedding code with a stack depth of 1 so it can skip over | |
223 | # our call and get the original caller's namespaces. |
|
223 | # our call and get the original caller's namespaces. | |
224 | self.mainloop(local_ns, module, stack_depth=stack_depth, |
|
224 | self.mainloop(local_ns, module, stack_depth=stack_depth, | |
225 | global_ns=global_ns, compile_flags=compile_flags) |
|
225 | global_ns=global_ns, compile_flags=compile_flags) | |
226 |
|
226 | |||
227 | self.banner2 = self.old_banner2 |
|
227 | self.banner2 = self.old_banner2 | |
228 |
|
228 | |||
229 | if self.exit_msg is not None: |
|
229 | if self.exit_msg is not None: | |
230 | print(self.exit_msg) |
|
230 | print(self.exit_msg) | |
231 |
|
231 | |||
232 | if self.should_raise: |
|
232 | if self.should_raise: | |
233 | raise KillEmbeded('Embedded IPython raising error, as user requested.') |
|
233 | raise KillEmbedded('Embedded IPython raising error, as user requested.') | |
234 |
|
234 | |||
235 |
|
235 | |||
236 | def mainloop(self, local_ns=None, module=None, stack_depth=0, |
|
236 | def mainloop(self, local_ns=None, module=None, stack_depth=0, | |
237 | display_banner=None, global_ns=None, compile_flags=None): |
|
237 | display_banner=None, global_ns=None, compile_flags=None): | |
238 | """Embeds IPython into a running python program. |
|
238 | """Embeds IPython into a running python program. | |
239 |
|
239 | |||
240 | Parameters |
|
240 | Parameters | |
241 | ---------- |
|
241 | ---------- | |
242 |
|
242 | |||
243 | local_ns, module |
|
243 | local_ns, module | |
244 | Working local namespace (a dict) and module (a module or similar |
|
244 | Working local namespace (a dict) and module (a module or similar | |
245 | object). If given as None, they are automatically taken from the scope |
|
245 | object). If given as None, they are automatically taken from the scope | |
246 | where the shell was called, so that program variables become visible. |
|
246 | where the shell was called, so that program variables become visible. | |
247 |
|
247 | |||
248 | stack_depth : int |
|
248 | stack_depth : int | |
249 | How many levels in the stack to go to looking for namespaces (when |
|
249 | How many levels in the stack to go to looking for namespaces (when | |
250 | local_ns or module is None). This allows an intermediate caller to |
|
250 | local_ns or module is None). This allows an intermediate caller to | |
251 | make sure that this function gets the namespace from the intended |
|
251 | make sure that this function gets the namespace from the intended | |
252 | level in the stack. By default (0) it will get its locals and globals |
|
252 | level in the stack. By default (0) it will get its locals and globals | |
253 | from the immediate caller. |
|
253 | from the immediate caller. | |
254 |
|
254 | |||
255 | compile_flags |
|
255 | compile_flags | |
256 | A bit field identifying the __future__ features |
|
256 | A bit field identifying the __future__ features | |
257 | that are enabled, as passed to the builtin :func:`compile` function. |
|
257 | that are enabled, as passed to the builtin :func:`compile` function. | |
258 | If given as None, they are automatically taken from the scope where |
|
258 | If given as None, they are automatically taken from the scope where | |
259 | the shell was called. |
|
259 | the shell was called. | |
260 |
|
260 | |||
261 | """ |
|
261 | """ | |
262 |
|
262 | |||
263 | if (global_ns is not None) and (module is None): |
|
263 | if (global_ns is not None) and (module is None): | |
264 | raise DeprecationWarning("'global_ns' keyword argument is deprecated, and has been removed in IPython 5.0 use `module` keyword argument instead.") |
|
264 | raise DeprecationWarning("'global_ns' keyword argument is deprecated, and has been removed in IPython 5.0 use `module` keyword argument instead.") | |
265 |
|
265 | |||
266 | if (display_banner is not None): |
|
266 | if (display_banner is not None): | |
267 | warnings.warn("The display_banner parameter is deprecated since IPython 4.0", DeprecationWarning) |
|
267 | warnings.warn("The display_banner parameter is deprecated since IPython 4.0", DeprecationWarning) | |
268 |
|
268 | |||
269 | # Get locals and globals from caller |
|
269 | # Get locals and globals from caller | |
270 | if ((local_ns is None or module is None or compile_flags is None) |
|
270 | if ((local_ns is None or module is None or compile_flags is None) | |
271 | and self.default_user_namespaces): |
|
271 | and self.default_user_namespaces): | |
272 | call_frame = sys._getframe(stack_depth).f_back |
|
272 | call_frame = sys._getframe(stack_depth).f_back | |
273 |
|
273 | |||
274 | if local_ns is None: |
|
274 | if local_ns is None: | |
275 | local_ns = call_frame.f_locals |
|
275 | local_ns = call_frame.f_locals | |
276 | if module is None: |
|
276 | if module is None: | |
277 | global_ns = call_frame.f_globals |
|
277 | global_ns = call_frame.f_globals | |
278 | try: |
|
278 | try: | |
279 | module = sys.modules[global_ns['__name__']] |
|
279 | module = sys.modules[global_ns['__name__']] | |
280 | except KeyError: |
|
280 | except KeyError: | |
281 | warnings.warn("Failed to get module %s" % \ |
|
281 | warnings.warn("Failed to get module %s" % \ | |
282 | global_ns.get('__name__', 'unknown module') |
|
282 | global_ns.get('__name__', 'unknown module') | |
283 | ) |
|
283 | ) | |
284 | module = DummyMod() |
|
284 | module = DummyMod() | |
285 | module.__dict__ = global_ns |
|
285 | module.__dict__ = global_ns | |
286 | if compile_flags is None: |
|
286 | if compile_flags is None: | |
287 | compile_flags = (call_frame.f_code.co_flags & |
|
287 | compile_flags = (call_frame.f_code.co_flags & | |
288 | compilerop.PyCF_MASK) |
|
288 | compilerop.PyCF_MASK) | |
289 |
|
289 | |||
290 | # Save original namespace and module so we can restore them after |
|
290 | # Save original namespace and module so we can restore them after | |
291 | # embedding; otherwise the shell doesn't shut down correctly. |
|
291 | # embedding; otherwise the shell doesn't shut down correctly. | |
292 | orig_user_module = self.user_module |
|
292 | orig_user_module = self.user_module | |
293 | orig_user_ns = self.user_ns |
|
293 | orig_user_ns = self.user_ns | |
294 | orig_compile_flags = self.compile.flags |
|
294 | orig_compile_flags = self.compile.flags | |
295 |
|
295 | |||
296 | # Update namespaces and fire up interpreter |
|
296 | # Update namespaces and fire up interpreter | |
297 |
|
297 | |||
298 | # The global one is easy, we can just throw it in |
|
298 | # The global one is easy, we can just throw it in | |
299 | if module is not None: |
|
299 | if module is not None: | |
300 | self.user_module = module |
|
300 | self.user_module = module | |
301 |
|
301 | |||
302 | # But the user/local one is tricky: ipython needs it to store internal |
|
302 | # But the user/local one is tricky: ipython needs it to store internal | |
303 | # data, but we also need the locals. We'll throw our hidden variables |
|
303 | # data, but we also need the locals. We'll throw our hidden variables | |
304 | # like _ih and get_ipython() into the local namespace, but delete them |
|
304 | # like _ih and get_ipython() into the local namespace, but delete them | |
305 | # later. |
|
305 | # later. | |
306 | if local_ns is not None: |
|
306 | if local_ns is not None: | |
307 | reentrant_local_ns = {k: v for (k, v) in local_ns.items() if k not in self.user_ns_hidden.keys()} |
|
307 | reentrant_local_ns = {k: v for (k, v) in local_ns.items() if k not in self.user_ns_hidden.keys()} | |
308 | self.user_ns = reentrant_local_ns |
|
308 | self.user_ns = reentrant_local_ns | |
309 | self.init_user_ns() |
|
309 | self.init_user_ns() | |
310 |
|
310 | |||
311 | # Compiler flags |
|
311 | # Compiler flags | |
312 | if compile_flags is not None: |
|
312 | if compile_flags is not None: | |
313 | self.compile.flags = compile_flags |
|
313 | self.compile.flags = compile_flags | |
314 |
|
314 | |||
315 | # make sure the tab-completer has the correct frame information, so it |
|
315 | # make sure the tab-completer has the correct frame information, so it | |
316 | # actually completes using the frame's locals/globals |
|
316 | # actually completes using the frame's locals/globals | |
317 | self.set_completer_frame() |
|
317 | self.set_completer_frame() | |
318 |
|
318 | |||
319 | with self.builtin_trap, self.display_trap: |
|
319 | with self.builtin_trap, self.display_trap: | |
320 | self.interact() |
|
320 | self.interact() | |
321 |
|
321 | |||
322 | # now, purge out the local namespace of IPython's hidden variables. |
|
322 | # now, purge out the local namespace of IPython's hidden variables. | |
323 | if local_ns is not None: |
|
323 | if local_ns is not None: | |
324 | local_ns.update({k: v for (k, v) in self.user_ns.items() if k not in self.user_ns_hidden.keys()}) |
|
324 | local_ns.update({k: v for (k, v) in self.user_ns.items() if k not in self.user_ns_hidden.keys()}) | |
325 |
|
325 | |||
326 |
|
326 | |||
327 | # Restore original namespace so shell can shut down when we exit. |
|
327 | # Restore original namespace so shell can shut down when we exit. | |
328 | self.user_module = orig_user_module |
|
328 | self.user_module = orig_user_module | |
329 | self.user_ns = orig_user_ns |
|
329 | self.user_ns = orig_user_ns | |
330 | self.compile.flags = orig_compile_flags |
|
330 | self.compile.flags = orig_compile_flags | |
331 |
|
331 | |||
332 |
|
332 | |||
333 | def embed(**kwargs): |
|
333 | def embed(**kwargs): | |
334 | """Call this to embed IPython at the current point in your program. |
|
334 | """Call this to embed IPython at the current point in your program. | |
335 |
|
335 | |||
336 | The first invocation of this will create an :class:`InteractiveShellEmbed` |
|
336 | The first invocation of this will create an :class:`InteractiveShellEmbed` | |
337 | instance and then call it. Consecutive calls just call the already |
|
337 | instance and then call it. Consecutive calls just call the already | |
338 | created instance. |
|
338 | created instance. | |
339 |
|
339 | |||
340 | If you don't want the kernel to initialize the namespace |
|
340 | If you don't want the kernel to initialize the namespace | |
341 | from the scope of the surrounding function, |
|
341 | from the scope of the surrounding function, | |
342 | and/or you want to load full IPython configuration, |
|
342 | and/or you want to load full IPython configuration, | |
343 | you probably want `IPython.start_ipython()` instead. |
|
343 | you probably want `IPython.start_ipython()` instead. | |
344 |
|
344 | |||
345 | Here is a simple example:: |
|
345 | Here is a simple example:: | |
346 |
|
346 | |||
347 | from IPython import embed |
|
347 | from IPython import embed | |
348 | a = 10 |
|
348 | a = 10 | |
349 | b = 20 |
|
349 | b = 20 | |
350 | embed(header='First time') |
|
350 | embed(header='First time') | |
351 | c = 30 |
|
351 | c = 30 | |
352 | d = 40 |
|
352 | d = 40 | |
353 | embed() |
|
353 | embed() | |
354 |
|
354 | |||
355 | Full customization can be done by passing a :class:`Config` in as the |
|
355 | Full customization can be done by passing a :class:`Config` in as the | |
356 | config argument. |
|
356 | config argument. | |
357 | """ |
|
357 | """ | |
358 | config = kwargs.get('config') |
|
358 | config = kwargs.get('config') | |
359 | header = kwargs.pop('header', u'') |
|
359 | header = kwargs.pop('header', u'') | |
360 | compile_flags = kwargs.pop('compile_flags', None) |
|
360 | compile_flags = kwargs.pop('compile_flags', None) | |
361 | if config is None: |
|
361 | if config is None: | |
362 | config = load_default_config() |
|
362 | config = load_default_config() | |
363 | config.InteractiveShellEmbed = config.TerminalInteractiveShell |
|
363 | config.InteractiveShellEmbed = config.TerminalInteractiveShell | |
364 | kwargs['config'] = config |
|
364 | kwargs['config'] = config | |
365 | #save ps1/ps2 if defined |
|
365 | #save ps1/ps2 if defined | |
366 | ps1 = None |
|
366 | ps1 = None | |
367 | ps2 = None |
|
367 | ps2 = None | |
368 | try: |
|
368 | try: | |
369 | ps1 = sys.ps1 |
|
369 | ps1 = sys.ps1 | |
370 | ps2 = sys.ps2 |
|
370 | ps2 = sys.ps2 | |
371 | except AttributeError: |
|
371 | except AttributeError: | |
372 | pass |
|
372 | pass | |
373 | #save previous instance |
|
373 | #save previous instance | |
374 | saved_shell_instance = InteractiveShell._instance |
|
374 | saved_shell_instance = InteractiveShell._instance | |
375 | if saved_shell_instance is not None: |
|
375 | if saved_shell_instance is not None: | |
376 | cls = type(saved_shell_instance) |
|
376 | cls = type(saved_shell_instance) | |
377 | cls.clear_instance() |
|
377 | cls.clear_instance() | |
378 | frame = sys._getframe(1) |
|
378 | frame = sys._getframe(1) | |
379 | shell = InteractiveShellEmbed.instance(_init_location_id='%s:%s' % ( |
|
379 | shell = InteractiveShellEmbed.instance(_init_location_id='%s:%s' % ( | |
380 | frame.f_code.co_filename, frame.f_lineno), **kwargs) |
|
380 | frame.f_code.co_filename, frame.f_lineno), **kwargs) | |
381 | shell(header=header, stack_depth=2, compile_flags=compile_flags, |
|
381 | shell(header=header, stack_depth=2, compile_flags=compile_flags, | |
382 | _call_location_id='%s:%s' % (frame.f_code.co_filename, frame.f_lineno)) |
|
382 | _call_location_id='%s:%s' % (frame.f_code.co_filename, frame.f_lineno)) | |
383 | InteractiveShellEmbed.clear_instance() |
|
383 | InteractiveShellEmbed.clear_instance() | |
384 | #restore previous instance |
|
384 | #restore previous instance | |
385 | if saved_shell_instance is not None: |
|
385 | if saved_shell_instance is not None: | |
386 | cls = type(saved_shell_instance) |
|
386 | cls = type(saved_shell_instance) | |
387 | cls.clear_instance() |
|
387 | cls.clear_instance() | |
388 | for subclass in cls._walk_mro(): |
|
388 | for subclass in cls._walk_mro(): | |
389 | subclass._instance = saved_shell_instance |
|
389 | subclass._instance = saved_shell_instance | |
390 | if ps1 is not None: |
|
390 | if ps1 is not None: | |
391 | sys.ps1 = ps1 |
|
391 | sys.ps1 = ps1 | |
392 | sys.ps2 = ps2 |
|
392 | sys.ps2 = ps2 |
@@ -1,976 +1,976 b'' | |||||
1 | { |
|
1 | { | |
2 | "cells": [ |
|
2 | "cells": [ | |
3 | { |
|
3 | { | |
4 | "cell_type": "markdown", |
|
4 | "cell_type": "markdown", | |
5 | "metadata": {}, |
|
5 | "metadata": {}, | |
6 | "source": [ |
|
6 | "source": [ | |
7 | "# Custom Display Logic" |
|
7 | "# Custom Display Logic" | |
8 | ] |
|
8 | ] | |
9 | }, |
|
9 | }, | |
10 | { |
|
10 | { | |
11 | "cell_type": "markdown", |
|
11 | "cell_type": "markdown", | |
12 | "metadata": {}, |
|
12 | "metadata": {}, | |
13 | "source": [ |
|
13 | "source": [ | |
14 | "## Overview" |
|
14 | "## Overview" | |
15 | ] |
|
15 | ] | |
16 | }, |
|
16 | }, | |
17 | { |
|
17 | { | |
18 | "cell_type": "markdown", |
|
18 | "cell_type": "markdown", | |
19 | "metadata": {}, |
|
19 | "metadata": {}, | |
20 | "source": [ |
|
20 | "source": [ | |
21 | "As described in the [Rich Output](Rich Output.ipynb) tutorial, the IPython display system can display rich representations of objects in the following formats:\n", |
|
21 | "As described in the [Rich Output](Rich Output.ipynb) tutorial, the IPython display system can display rich representations of objects in the following formats:\n", | |
22 | "\n", |
|
22 | "\n", | |
23 | "* JavaScript\n", |
|
23 | "* JavaScript\n", | |
24 | "* HTML\n", |
|
24 | "* HTML\n", | |
25 | "* PNG\n", |
|
25 | "* PNG\n", | |
26 | "* JPEG\n", |
|
26 | "* JPEG\n", | |
27 | "* SVG\n", |
|
27 | "* SVG\n", | |
28 | "* LaTeX\n", |
|
28 | "* LaTeX\n", | |
29 | "* PDF\n", |
|
29 | "* PDF\n", | |
30 | "\n", |
|
30 | "\n", | |
31 | "This Notebook shows how you can add custom display logic to your own classes, so that they can be displayed using these rich representations. There are two ways of accomplishing this:\n", |
|
31 | "This Notebook shows how you can add custom display logic to your own classes, so that they can be displayed using these rich representations. There are two ways of accomplishing this:\n", | |
32 | "\n", |
|
32 | "\n", | |
33 | "1. Implementing special display methods such as `_repr_html_` when you define your class.\n", |
|
33 | "1. Implementing special display methods such as `_repr_html_` when you define your class.\n", | |
34 | "2. Registering a display function for a particular existing class.\n", |
|
34 | "2. Registering a display function for a particular existing class.\n", | |
35 | "\n", |
|
35 | "\n", | |
36 | "This Notebook describes and illustrates both approaches." |
|
36 | "This Notebook describes and illustrates both approaches." | |
37 | ] |
|
37 | ] | |
38 | }, |
|
38 | }, | |
39 | { |
|
39 | { | |
40 | "cell_type": "markdown", |
|
40 | "cell_type": "markdown", | |
41 | "metadata": {}, |
|
41 | "metadata": {}, | |
42 | "source": [ |
|
42 | "source": [ | |
43 | "Import the IPython display functions." |
|
43 | "Import the IPython display functions." | |
44 | ] |
|
44 | ] | |
45 | }, |
|
45 | }, | |
46 | { |
|
46 | { | |
47 | "cell_type": "code", |
|
47 | "cell_type": "code", | |
48 | "execution_count": 1, |
|
48 | "execution_count": 1, | |
49 | "metadata": { |
|
49 | "metadata": { | |
50 | "collapsed": true |
|
50 | "collapsed": true | |
51 | }, |
|
51 | }, | |
52 | "outputs": [], |
|
52 | "outputs": [], | |
53 | "source": [ |
|
53 | "source": [ | |
54 | "from IPython.display import (\n", |
|
54 | "from IPython.display import (\n", | |
55 | " display, display_html, display_png, display_svg\n", |
|
55 | " display, display_html, display_png, display_svg\n", | |
56 | ")" |
|
56 | ")" | |
57 | ] |
|
57 | ] | |
58 | }, |
|
58 | }, | |
59 | { |
|
59 | { | |
60 | "cell_type": "markdown", |
|
60 | "cell_type": "markdown", | |
61 | "metadata": {}, |
|
61 | "metadata": {}, | |
62 | "source": [ |
|
62 | "source": [ | |
63 | "Parts of this notebook need the matplotlib inline backend:" |
|
63 | "Parts of this notebook need the matplotlib inline backend:" | |
64 | ] |
|
64 | ] | |
65 | }, |
|
65 | }, | |
66 | { |
|
66 | { | |
67 | "cell_type": "code", |
|
67 | "cell_type": "code", | |
68 | "execution_count": 2, |
|
68 | "execution_count": 2, | |
69 | "metadata": { |
|
69 | "metadata": { | |
70 | "collapsed": true |
|
70 | "collapsed": true | |
71 | }, |
|
71 | }, | |
72 | "outputs": [], |
|
72 | "outputs": [], | |
73 | "source": [ |
|
73 | "source": [ | |
74 | "import numpy as np\n", |
|
74 | "import numpy as np\n", | |
75 | "import matplotlib.pyplot as plt\n", |
|
75 | "import matplotlib.pyplot as plt\n", | |
76 | "plt.ion()" |
|
76 | "plt.ion()" | |
77 | ] |
|
77 | ] | |
78 | }, |
|
78 | }, | |
79 | { |
|
79 | { | |
80 | "cell_type": "markdown", |
|
80 | "cell_type": "markdown", | |
81 | "metadata": {}, |
|
81 | "metadata": {}, | |
82 | "source": [ |
|
82 | "source": [ | |
83 | "## Special display methods" |
|
83 | "## Special display methods" | |
84 | ] |
|
84 | ] | |
85 | }, |
|
85 | }, | |
86 | { |
|
86 | { | |
87 | "cell_type": "markdown", |
|
87 | "cell_type": "markdown", | |
88 | "metadata": {}, |
|
88 | "metadata": {}, | |
89 | "source": [ |
|
89 | "source": [ | |
90 | "The main idea of the first approach is that you have to implement special display methods when you define your class, one for each representation you want to use. Here is a list of the names of the special methods and the values they must return:\n", |
|
90 | "The main idea of the first approach is that you have to implement special display methods when you define your class, one for each representation you want to use. Here is a list of the names of the special methods and the values they must return:\n", | |
91 | "\n", |
|
91 | "\n", | |
92 | "* `_repr_html_`: return raw HTML as a string\n", |
|
92 | "* `_repr_html_`: return raw HTML as a string\n", | |
93 | "* `_repr_json_`: return a JSONable dict\n", |
|
93 | "* `_repr_json_`: return a JSONable dict\n", | |
94 | "* `_repr_jpeg_`: return raw JPEG data\n", |
|
94 | "* `_repr_jpeg_`: return raw JPEG data\n", | |
95 | "* `_repr_png_`: return raw PNG data\n", |
|
95 | "* `_repr_png_`: return raw PNG data\n", | |
96 | "* `_repr_svg_`: return raw SVG data as a string\n", |
|
96 | "* `_repr_svg_`: return raw SVG data as a string\n", | |
97 | "* `_repr_latex_`: return LaTeX commands in a string surrounded by \"$\".\n", |
|
97 | "* `_repr_latex_`: return LaTeX commands in a string surrounded by \"$\".\n", | |
98 | "* `_repr_mimebundle_`: return a full mimebundle containing the mapping from all mimetypes to data " |
|
98 | "* `_repr_mimebundle_`: return a full mimebundle containing the mapping from all mimetypes to data " | |
99 | ] |
|
99 | ] | |
100 | }, |
|
100 | }, | |
101 | { |
|
101 | { | |
102 | "cell_type": "markdown", |
|
102 | "cell_type": "markdown", | |
103 | "metadata": {}, |
|
103 | "metadata": {}, | |
104 | "source": [ |
|
104 | "source": [ | |
105 | "As an illustration, we build a class that holds data generated by sampling a Gaussian distribution with given mean and standard deviation. Here is the definition of the `Gaussian` class, which has a custom PNG and LaTeX representation." |
|
105 | "As an illustration, we build a class that holds data generated by sampling a Gaussian distribution with given mean and standard deviation. Here is the definition of the `Gaussian` class, which has a custom PNG and LaTeX representation." | |
106 | ] |
|
106 | ] | |
107 | }, |
|
107 | }, | |
108 | { |
|
108 | { | |
109 | "cell_type": "code", |
|
109 | "cell_type": "code", | |
110 | "execution_count": 3, |
|
110 | "execution_count": 3, | |
111 | "metadata": { |
|
111 | "metadata": { | |
112 | "collapsed": true |
|
112 | "collapsed": true | |
113 | }, |
|
113 | }, | |
114 | "outputs": [], |
|
114 | "outputs": [], | |
115 | "source": [ |
|
115 | "source": [ | |
116 | "from IPython.core.pylabtools import print_figure\n", |
|
116 | "from IPython.core.pylabtools import print_figure\n", | |
117 | "from IPython.display import Image, SVG, Math\n", |
|
117 | "from IPython.display import Image, SVG, Math\n", | |
118 | "\n", |
|
118 | "\n", | |
119 | "class Gaussian(object):\n", |
|
119 | "class Gaussian(object):\n", | |
120 | " \"\"\"A simple object holding data sampled from a Gaussian distribution.\n", |
|
120 | " \"\"\"A simple object holding data sampled from a Gaussian distribution.\n", | |
121 | " \"\"\"\n", |
|
121 | " \"\"\"\n", | |
122 | " def __init__(self, mean=0.0, std=1, size=1000):\n", |
|
122 | " def __init__(self, mean=0.0, std=1, size=1000):\n", | |
123 | " self.data = np.random.normal(mean, std, size)\n", |
|
123 | " self.data = np.random.normal(mean, std, size)\n", | |
124 | " self.mean = mean\n", |
|
124 | " self.mean = mean\n", | |
125 | " self.std = std\n", |
|
125 | " self.std = std\n", | |
126 | " self.size = size\n", |
|
126 | " self.size = size\n", | |
127 | " # For caching plots that may be expensive to compute\n", |
|
127 | " # For caching plots that may be expensive to compute\n", | |
128 | " self._png_data = None\n", |
|
128 | " self._png_data = None\n", | |
129 | " \n", |
|
129 | " \n", | |
130 | " def _figure_data(self, format):\n", |
|
130 | " def _figure_data(self, format):\n", | |
131 | " fig, ax = plt.subplots()\n", |
|
131 | " fig, ax = plt.subplots()\n", | |
132 | " ax.hist(self.data, bins=50)\n", |
|
132 | " ax.hist(self.data, bins=50)\n", | |
133 | " ax.set_title(self._repr_latex_())\n", |
|
133 | " ax.set_title(self._repr_latex_())\n", | |
134 | " ax.set_xlim(-10.0,10.0)\n", |
|
134 | " ax.set_xlim(-10.0,10.0)\n", | |
135 | " data = print_figure(fig, format)\n", |
|
135 | " data = print_figure(fig, format)\n", | |
136 | " # We MUST close the figure, otherwise IPython's display machinery\n", |
|
136 | " # We MUST close the figure, otherwise IPython's display machinery\n", | |
137 | " # will pick it up and send it as output, resulting in a double display\n", |
|
137 | " # will pick it up and send it as output, resulting in a double display\n", | |
138 | " plt.close(fig)\n", |
|
138 | " plt.close(fig)\n", | |
139 | " return data\n", |
|
139 | " return data\n", | |
140 | " \n", |
|
140 | " \n", | |
141 | " def _repr_png_(self):\n", |
|
141 | " def _repr_png_(self):\n", | |
142 | " if self._png_data is None:\n", |
|
142 | " if self._png_data is None:\n", | |
143 | " self._png_data = self._figure_data('png')\n", |
|
143 | " self._png_data = self._figure_data('png')\n", | |
144 | " return self._png_data\n", |
|
144 | " return self._png_data\n", | |
145 | " \n", |
|
145 | " \n", | |
146 | " def _repr_latex_(self):\n", |
|
146 | " def _repr_latex_(self):\n", | |
147 | " return r'$\\mathcal{N}(\\mu=%.2g, \\sigma=%.2g),\\ N=%d$' % (self.mean,\n", |
|
147 | " return r'$\\mathcal{N}(\\mu=%.2g, \\sigma=%.2g),\\ N=%d$' % (self.mean,\n", | |
148 | " self.std, self.size)" |
|
148 | " self.std, self.size)" | |
149 | ] |
|
149 | ] | |
150 | }, |
|
150 | }, | |
151 | { |
|
151 | { | |
152 | "cell_type": "markdown", |
|
152 | "cell_type": "markdown", | |
153 | "metadata": {}, |
|
153 | "metadata": {}, | |
154 | "source": [ |
|
154 | "source": [ | |
155 | "Create an instance of the Gaussian distribution and return it to display the default representation:" |
|
155 | "Create an instance of the Gaussian distribution and return it to display the default representation:" | |
156 | ] |
|
156 | ] | |
157 | }, |
|
157 | }, | |
158 | { |
|
158 | { | |
159 | "cell_type": "code", |
|
159 | "cell_type": "code", | |
160 | "execution_count": 4, |
|
160 | "execution_count": 4, | |
161 | "metadata": {}, |
|
161 | "metadata": {}, | |
162 | "outputs": [ |
|
162 | "outputs": [ | |
163 | { |
|
163 | { | |
164 | "data": { |
|
164 | "data": { | |
165 | "image/png": "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\n1ADDXpIa8P8BEb7Ae9JKdQAAAAAASUVORK5CYII=\n", |
|
165 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXsAAAEKCAYAAADzQPVvAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAFOZJREFUeJzt3X+0ZWV93/H3xxnAVIlAGJCIOpiFFgxhMLMIDUlKxBB+\nuAQbtRiXmRaSadrQ6lrtSsayklJjW0ybaNommolQJ1k0QBWEBRidotaVtRLMID+EAPIjoyKEGRUQ\niDEi3/6x99Xj5dx7z73nnPtjnvdrrbPu2fvZe5/vPGfP5+zz7H33TVUhSdq3PWelC5AkTZ9hL0kN\nMOwlqQGGvSQ1wLCXpAYY9pLUAMNekhpg2EtSAwx7keTMJI8kuTjJf0ny9pWuabVJ8pkkr1zpOqSl\nMuwbkuTHkuw3a95zgFOAXwK+CvwC8AdTruOAJJck+UKSJ5LckuSMab7mCDVdkGRXkm8m+eCQRf4b\n8M4lbvvgJJXkz2fN/4Mk71nKNge2MW/dSQ5JcnWSp/r+/vlR2kZp19pi2LflPODsWfNOBq6qqmv7\n6Ruq6htTrmM98CXgHwMvAH4duDLJxim/7nweAt4FXDpH+7XATyc5Ygnb3gT8DXDsrPU3AbcuYXuD\nFqr794C/Bw4H3gK8b+Abynxto7RrDTHs23ICsHXWvJOAm/rnZwD/b7AxyYVJ3jcwfXCSbyV57lKL\nqKqnquqiqtpdVc9U1XXAXwM/utC6SfZL8p+S7O7rqP5x21Lr6Wu6qqo+QvftZlj73wE3A6ctYfOb\ngF3ATuB1AEnWAccBtyyp4O/WNWfdSZ4H/Bzw61X1ZFX9Gd2H1lvna1to3XHq1cox7BuRZD2wFzg1\nycsHmtbXd++Gdxxwz6xVj+N7jz43Aff04Te4/euSPDbH47oFajsceDlw5wj/lHcBpwI/CRwE3Ahc\nDbx+UvXM4y7g+CWsdwJdH34EOKef9w+Bdf02p1X3y4FvV9XnB+bdBrxygbaF1tUatH6lC9Cy2QT8\nL2B/4G3AryQ5lu8Nm4OAJ2atdxwwOK68ie4//feoqtcupaj+HMJlwI6qunuBZQ8E/g3wI1X1pX7e\nh4F/WlUPTKKeBTwBLHUY5xrgE8D7+3/HJuCOqvrW4IITrvv5wOOz5j0OHLhA20Lrag3yyL4dp9Ad\nBf82cF6Sl9ANSewcWOZRBv4zJ9kf+CHgcwPLHM/448wz238O8Md048IXjLDKTwEPVNW9A/MOphsP\nXw4HAo8tZoUkBwDHALdW1aPAZ+iGy2aO9qfpSeD7Z837froPrfnaFlpXa5Bh347DqurRqvpTujH6\n3wWeX1VPDSxzO93X9xnHAl+uqr8FSBK6D41nHdkn+WiSJ+d4fHTI8gEuoTv593Ozj3DnsIHuA2lw\nG68HnjW8sdh6RnQMQ/7tC/hh4BvAzDePmaGcExgyXj/huj8PrE9y9MC84+mGy+ZrW2hdrUEO4+zD\nkvwE3TDM14FPDzT9C7rQ+visVW6gu0Lmsn76OOCwJD9Ed9XHhcBLgd2zX6uqFnvp5PvowvM1w67+\nmbmMsKr+2cDsO4BXJdlEd27hPwAFXDFuPf05jfV04+jr+hPQT1fV0337AXQnkLfMU98wJwC3DZwX\nuYbuEs5n+vqnVndVPZXkKuCdSX6RbujobODH52vr65i3XWtQVfnYRx90V1N8A3jvkLZfBV48a96h\nwIPA9/XTvwV8iO4o78vAvwbupxtfH6eul9KF9N/RDRfMPN4ysMyNwC8NWfdCug+eh4EPAodOqK8u\n6msafFw00P5GuktU561vyHb/J/A/Zs27lS7sD1yGug+h+zbxFPBF4OdHaRul3cfaeqR/U7WPSpJa\nxJuc5D8De6rqvf2wwQeq6sPTq3BoDfvTffP4kRpteGfqktwEnF9Vd6zG+qSFGPaaU5IHgdOq6q9W\nuhZJ4zHsNVSSg4FHgOd59CqtfYa9JDXASy8lqQHLeunloYceWhs3blzOl5SkNe/mm2/+SlVtGGcb\nyxr2GzduZNeuXcv5kpK05iX5wrjbcBhHkhpg2EtSAwx7SWqAYS9JDTDsJakBhr0kNcCwl6QGGPaS\n1ADDXpIaYNhLy2TjtuvZuO36sZeRlsKwl6QGGPaS1ADDXpIaYNhLUgMMe0lqgGEvSQ0w7CWpASP9\npaoku4EngG8DT1fV5iSHAFcAG4HdwJuq6tHplClJGsdijux/uqo2VdXmfnobcGNVHQ3c2E9Lklah\ncYZxzgZ29M93AOeMX44kaRpGDfsCPp7k5iRb+3mHV9XDAP3Pw4atmGRrkl1Jdu3du3f8iiVJizbS\nmD1wclU9lOQwYGeSu0d9garaDmwH2Lx5cy2hRknSmEY6sq+qh/qfe4CrgROBR5IcAdD/3DOtIiVJ\n41kw7JM8L8mBM8+B04A7gGuBLf1iW4BrplWkJGk8owzjHA5cnWRm+f9dVX+a5C+BK5OcD3wReOP0\nypT2HYO3MN598VkrWIlasmDYV9UDwPFD5n8VOHUaRUmSJsvfoJWkBhj2ktQAw15aQZP4M4T+KUON\nwrCXpAYY9pLUAMNekhpg2EtSAwx7SWqAYS9JDTDsJakBo97iWNISeQ28VgOP7CWpAYa9JDXAsJek\nBhj2ktQAw16SGmDYS1IDDHtJaoBhL0kNMOwlqQGGvSQ1wLCXpAYY9pLUAMNekhpg2EtSAwx7SWqA\n97OXVqGZe+Dvvvis75kenCcthkf2ktQAw16SGmDYS1IDRg77JOuS3JLkun76qCQ3Jbk3yRVJ9p9e\nmZKkcSzmyP5twF0D0+8G3lNVRwOPAudPsjBJ0uSMFPZJjgTOAj7QTwd4NfChfpEdwDnTKFCSNL5R\nj+zfC/wq8Ew//QPAY1X1dD/9IPCiCdcmSZqQBa+zT/JaYE9V3ZzklJnZQxatOdbfCmwFeMlLXrLE\nMqW1Y/Y18otZZ1rbl0Y5sj8ZeF2S3cDldMM37wUOSjLzYXEk8NCwlatqe1VtrqrNGzZsmEDJkqTF\nWjDsq+odVXVkVW0EzgU+UVVvAT4JvKFfbAtwzdSqlCSNZZzbJfwacHmSdwG3AJdMpiRJMxYzvCPN\nZ1FhX1WfAj7VP38AOHHyJUmSJs3foJWkBhj2ktQAb3EsTYnj7VpNPLKXpAYY9pLUAMNekhrgmL20\nRnlOQIvhkb0kNcCwl6QGGPaS1ADDXpIaYNhLUgMMe0lqgGEvSQ0w7KV9xMZt13vtveZk2EtSAwx7\nSWqAYS9JDTDspSVwfFxrjWEvSQ0w7CWpAYa9JDXAsJekBhj2ktQAw16SGmDYS1IDDHtJaoBhL0kN\nMOwlqQGGvSQ1YMGwT/LcJJ9JcluSO5P8x37+UUluSnJvkiuS7D/9ciVJSzHKkf03gVdX1fHAJuD0\nJCcB7wbeU1VHA48C50+vTEnSOBYM++o82U/u1z8KeDXwoX7+DuCcqVQoSRrbSGP2SdYluRXYA+wE\n7gceq6qn+0UeBF40nRIlSeMaKeyr6ttVtQk4EjgROGbYYsPWTbI1ya4ku/bu3bv0SiVJS7aoq3Gq\n6jHgU8BJwEFJ1vdNRwIPzbHO9qraXFWbN2zYME6tkqQlGuVqnA1JDuqffx/wGuAu4JPAG/rFtgDX\nTKtISdJ41i+8CEcAO5Kso/twuLKqrkvyV8DlSd4F3AJcMsU6pVXPP1Oo1WzBsK+q24EThsx/gG78\nXpK0yvkbtJLUAMNekhpg2EtSAwx7SWqAYS9JDTDsJakBhr0kNcCwl6QGGPaS1ADDXpIaYNhLUgMM\ne0lqgGEvSQ0w7CWpAYa9NIKN265fM/erX0u1avkY9pLUAMNekhpg2EtSA0b5G7SSeo6Fa63yyF6S\nGmDYS1IDDHtJaoBhLzXEa/DbZdhLUgMMe0lqgGEvSQ0w7CWpAYa9JDXAsJekBhj2ktSABe+Nk+TF\nwB8BLwSeAbZX1e8mOQS4AtgI7AbeVFWPTq9UafVZK9esr5U6NT2jHNk/DfzbqjoGOAn4lSTHAtuA\nG6vqaODGflqStAotGPZV9XBVfbZ//gRwF/Ai4GxgR7/YDuCcaRUpSRrPosbsk2wETgBuAg6vqoeh\n+0AADpt0cZKkyRg57JM8H/gw8Paq+voi1tuaZFeSXXv37l1KjZKkMY0U9kn2owv6y6rqqn72I0mO\n6NuPAPYMW7eqtlfV5qravGHDhknULElapAXDPkmAS4C7qup3BpquBbb0z7cA10y+PEnSJIzyZwlP\nBt4KfC7Jrf28fw9cDFyZ5Hzgi8Abp1OiJGlcC4Z9Vf0ZkDmaT51sOZKWw8x197svPmuFK9Fy8Tdo\nJakBhr0kNcCwl6QGGPaS1ADDXpIaYNhLUgMMe0lqgGEvSQ0w7CWpAYa9JDXAsJekBhj2ktQAw16S\nGmDYS1IDRrmfvaQ1aOY2xhJ4ZC9JTTDsJakBhr0kNcCwl6QGGPaS1ADDXpIaYNhLUgMMe0lqgGEv\nSQ0w7CWpAYa9JDXAe+NIvcF7yey++KxnzZPWMo/sJakBhr0kNcCwl6QGGPaS1IAFwz7JpUn2JLlj\nYN4hSXYmubf/efB0y5QkjWOUI/sPAqfPmrcNuLGqjgZu7KclSavUgmFfVZ8GvjZr9tnAjv75DuCc\nCdclSZqgpY7ZH15VDwP0Pw+ba8EkW5PsSrJr7969S3w5SdOwcdv1c/4uwXxtWnumfoK2qrZX1eaq\n2rxhw4Zpv5wkaYilhv0jSY4A6H/umVxJkqRJW2rYXwts6Z9vAa6ZTDmSpGkY5dLLPwH+HHhFkgeT\nnA9cDPxMknuBn+mnJUmr1II3QquqN8/RdOqEa5EkTYm/QStJDTDsJakB3s9eGqK168tn/r0z9/HX\nvscje0lqgGEvSQ0w7CXNy9sm7BsMe0lqgGEvSQ0w7CWpAV56qWZ5ueGzLWZs3v5bWzyyl6QGGPaS\n1ADDXpIa4Ji99kmDY88zY8peK66WeWQvSQ0w7CWpAYa9JDXAsJekBhj2ktQAw16SGmDYS1IDvM5e\nzfP6e7XAI3tJaoBhL0kNMOwlqQGO2Wuf55j8ZM3Xn97jfvXyyF6SGmDYS1IDDHtJaoBj9lqTZo8N\nOy4/fUvpY8fwV4+xjuyTnJ7kniT3Jdk2qaIkSZO15LBPsg74PeAM4FjgzUmOnVRhkqTJGefI/kTg\nvqp6oKr+HrgcOHsyZUmSJilVtbQVkzcAp1fVL/bTbwV+rKoumLXcVmBrP/nDwB1LL3fZHAp8ZaWL\nGMFaqHMt1AjWOWnWOVmvqKoDx9nAOCdoM2Tesz45qmo7sB0gya6q2jzGay4L65yctVAjWOekWedk\nJdk17jbGGcZ5EHjxwPSRwEPjlSNJmoZxwv4vgaOTHJVkf+Bc4NrJlCVJmqQlD+NU1dNJLgA+BqwD\nLq2qOxdYbftSX2+ZWefkrIUawTonzTona+w6l3yCVpK0dni7BElqgGEvSQ2YeNgneWOSO5M8k2Tz\nrLZ39LdWuCfJz86x/lFJbkpyb5Ir+pO/U9W/zq39Y3eSW+dYbneSz/XLjX0p1BLqvCjJlwdqPXOO\n5VbsNhZJ/muSu5PcnuTqJAfNsdyK9OVCfZPkgH5/uK/fDzcuV20DNbw4ySeT3NX/X3rbkGVOSfL4\nwL7wG8tdZ1/HvO9jOv+978/bk7xqBWp8xUA/3Zrk60nePmuZFenPJJcm2ZPkjoF5hyTZ2WfgziQH\nz7Huln6Ze5NsWfDFqmqiD+AY4BXAp4DNA/OPBW4DDgCOAu4H1g1Z/0rg3P75+4F/OekaF6j/t4Hf\nmKNtN3DoctYz6/UvAv7dAsus6/v2ZcD+fZ8fu4w1ngas75+/G3j3aunLUfoG+FfA+/vn5wJXrMD7\nfATwqv75gcDnh9R5CnDdcte22PcROBP4KN3v5ZwE3LTC9a4D/gZ46WroT+CngFcBdwzM+y1gW/98\n27D/Q8AhwAP9z4P75wfP91oTP7Kvqruq6p4hTWcDl1fVN6vqr4H76G658B1JArwa+FA/awdwzqRr\nnEv/+m8C/mS5XnMKVvQ2FlX18ap6up/8C7rfv1gtRumbs+n2O+j2w1P7/WLZVNXDVfXZ/vkTwF3A\ni5azhgk6G/ij6vwFcFCSI1awnlOB+6vqCytYw3dU1aeBr82aPbgPzpWBPwvsrKqvVdWjwE7g9Ple\naznH7F8EfGlg+kGevQP/APDYQFgMW2aafhJ4pKrunaO9gI8nubm/DcRKuKD/OnzpHF/vRunn5XIe\n3VHdMCvRl6P0zXeW6ffDx+n2yxXRDyOdANw0pPkfJbktyUeTvHJZC/uuhd7H1bQ/Qvdtba6DudXQ\nnwCHV9XD0H3wA4cNWWbR/bqk6+yT/F/ghUOaLqyqa+Zabci82dd9jnQLhqUYseY3M/9R/clV9VCS\nw4CdSe7uP5knZr46gfcBv0nXJ79JN+R03uxNDFl3otfXjtKXSS4EngYum2MzU+/LIVZ0H1ysJM8H\nPgy8vaq+Pqv5s3RDEU/2524+Ahy93DWy8Pu4mvpzf+B1wDuGNK+W/hzVovt1SWFfVa9Zwmqj3F7h\nK3Rf89b3R1UTuwXDQjUnWQ/8E+BH59nGQ/3PPUmuphsWmGhAjdq3Sf4QuG5I09RvYzFCX24BXguc\nWv0A45BtTL0vhxilb2aWebDfJ17As79mT12S/eiC/rKqump2+2D4V9UNSX4/yaFVtaw39RrhfVxN\nt1U5A/hsVT0yu2G19GfvkSRHVNXD/ZDXniHLPEh3nmHGkXTnSee0nMM41wLn9lc7HEX3qfmZwQX6\nYPgk8IZ+1hZgrm8Kk/Ya4O6qenBYY5LnJTlw5jndichlvYPnrLHO18/x+it6G4skpwO/Bryuqv52\njmVWqi9H6Ztr6fY76PbDT8z1gTUt/TmCS4C7qup35ljmhTPnEpKcSPd/+avLV+XI7+O1wC/0V+Wc\nBDw+M0SxAub85r4a+nPA4D44VwZ+DDgtycH9cO5p/by5TeHs8uvpPnW+CTwCfGyg7UK6qyHuAc4Y\nmH8D8IP985fRfQjcB/wf4IBJ1zhH3R8EfnnWvB8Ebhio67b+cSfdkMVyn7n/Y+BzwO39DnHE7Dr7\n6TPpruC4f7nr7N+3LwG39o/3z65xJftyWN8A76T7cAJ4br/f3dfvhy9bgff5J+i+kt8+0I9nAr88\ns48CF/R9dxvdifAfX4E6h76Ps+oM3R85ur/fdzcvd519Hf+ALrxfMDBvxfuT7sPnYeBbfW6eT3eO\n6Ebg3v7nIf2ym4EPDKx7Xr+f3gf884Vey9slSFID/A1aSWqAYS9JDTDsJakBhr0kNcCwl6QGGPaS\n1ADDXpIa8P8BEb7Ae9JKdQAAAAAASUVORK5CYII=\n", | |
166 | "text/latex": [ |
|
166 | "text/latex": [ | |
167 | "$\\mathcal{N}(\\mu=2, \\sigma=1),\\ N=1000$" |
|
167 | "$\\mathcal{N}(\\mu=2, \\sigma=1),\\ N=1000$" | |
168 | ], |
|
168 | ], | |
169 | "text/plain": [ |
|
169 | "text/plain": [ | |
170 | "<__main__.Gaussian at 0x116fe76d8>" |
|
170 | "<__main__.Gaussian at 0x116fe76d8>" | |
171 | ] |
|
171 | ] | |
172 | }, |
|
172 | }, | |
173 | "execution_count": 4, |
|
173 | "execution_count": 4, | |
174 | "metadata": {}, |
|
174 | "metadata": {}, | |
175 | "output_type": "execute_result" |
|
175 | "output_type": "execute_result" | |
176 | } |
|
176 | } | |
177 | ], |
|
177 | ], | |
178 | "source": [ |
|
178 | "source": [ | |
179 | "x = Gaussian(2.0, 1.0)\n", |
|
179 | "x = Gaussian(2.0, 1.0)\n", | |
180 | "x" |
|
180 | "x" | |
181 | ] |
|
181 | ] | |
182 | }, |
|
182 | }, | |
183 | { |
|
183 | { | |
184 | "cell_type": "markdown", |
|
184 | "cell_type": "markdown", | |
185 | "metadata": {}, |
|
185 | "metadata": {}, | |
186 | "source": [ |
|
186 | "source": [ | |
187 | "You can also pass the object to the `display` function to display the default representation:" |
|
187 | "You can also pass the object to the `display` function to display the default representation:" | |
188 | ] |
|
188 | ] | |
189 | }, |
|
189 | }, | |
190 | { |
|
190 | { | |
191 | "cell_type": "code", |
|
191 | "cell_type": "code", | |
192 | "execution_count": 5, |
|
192 | "execution_count": 5, | |
193 | "metadata": {}, |
|
193 | "metadata": {}, | |
194 | "outputs": [ |
|
194 | "outputs": [ | |
195 | { |
|
195 | { | |
196 | "data": { |
|
196 | "data": { | |
197 | "image/png": "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\n1ADDXpIa8P8BEb7Ae9JKdQAAAAAASUVORK5CYII=\n", |
|
197 | "image/png": "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\n1ADDXpIa8P8BEb7Ae9JKdQAAAAAASUVORK5CYII=\n", | |
198 | "text/latex": [ |
|
198 | "text/latex": [ | |
199 | "$\\mathcal{N}(\\mu=2, \\sigma=1),\\ N=1000$" |
|
199 | "$\\mathcal{N}(\\mu=2, \\sigma=1),\\ N=1000$" | |
200 | ], |
|
200 | ], | |
201 | "text/plain": [ |
|
201 | "text/plain": [ | |
202 | "<__main__.Gaussian at 0x116fe76d8>" |
|
202 | "<__main__.Gaussian at 0x116fe76d8>" | |
203 | ] |
|
203 | ] | |
204 | }, |
|
204 | }, | |
205 | "metadata": {}, |
|
205 | "metadata": {}, | |
206 | "output_type": "display_data" |
|
206 | "output_type": "display_data" | |
207 | } |
|
207 | } | |
208 | ], |
|
208 | ], | |
209 | "source": [ |
|
209 | "source": [ | |
210 | "display(x)" |
|
210 | "display(x)" | |
211 | ] |
|
211 | ] | |
212 | }, |
|
212 | }, | |
213 | { |
|
213 | { | |
214 | "cell_type": "markdown", |
|
214 | "cell_type": "markdown", | |
215 | "metadata": {}, |
|
215 | "metadata": {}, | |
216 | "source": [ |
|
216 | "source": [ | |
217 | "Use `display_png` to view the PNG representation:" |
|
217 | "Use `display_png` to view the PNG representation:" | |
218 | ] |
|
218 | ] | |
219 | }, |
|
219 | }, | |
220 | { |
|
220 | { | |
221 | "cell_type": "code", |
|
221 | "cell_type": "code", | |
222 | "execution_count": 6, |
|
222 | "execution_count": 6, | |
223 | "metadata": {}, |
|
223 | "metadata": {}, | |
224 | "outputs": [ |
|
224 | "outputs": [ | |
225 | { |
|
225 | { | |
226 | "data": { |
|
226 | "data": { | |
227 | "image/png": "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\n1ADDXpIa8P8BEb7Ae9JKdQAAAAAASUVORK5CYII=\n" |
|
227 | "image/png": "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\n1ADDXpIa8P8BEb7Ae9JKdQAAAAAASUVORK5CYII=\n" | |
228 | }, |
|
228 | }, | |
229 | "metadata": {}, |
|
229 | "metadata": {}, | |
230 | "output_type": "display_data" |
|
230 | "output_type": "display_data" | |
231 | } |
|
231 | } | |
232 | ], |
|
232 | ], | |
233 | "source": [ |
|
233 | "source": [ | |
234 | "display_png(x)" |
|
234 | "display_png(x)" | |
235 | ] |
|
235 | ] | |
236 | }, |
|
236 | }, | |
237 | { |
|
237 | { | |
238 | "cell_type": "markdown", |
|
238 | "cell_type": "markdown", | |
239 | "metadata": {}, |
|
239 | "metadata": {}, | |
240 | "source": [ |
|
240 | "source": [ | |
241 | "<div class=\"alert alert-success\">\n", |
|
241 | "<div class=\"alert alert-success\">\n", | |
242 | "It is important to note a subtle different between <code>display</code> and <code>display_png</code>. The former computes <em>all</em> representations of the object, and lets the notebook UI decide which to display. The later only computes the PNG representation.\n", |
|
242 | "It is important to note a subtle different between <code>display</code> and <code>display_png</code>. The former computes <em>all</em> representations of the object, and lets the notebook UI decide which to display. The later only computes the PNG representation.\n", | |
243 | "</div>" |
|
243 | "</div>" | |
244 | ] |
|
244 | ] | |
245 | }, |
|
245 | }, | |
246 | { |
|
246 | { | |
247 | "cell_type": "markdown", |
|
247 | "cell_type": "markdown", | |
248 | "metadata": {}, |
|
248 | "metadata": {}, | |
249 | "source": [ |
|
249 | "source": [ | |
250 | "Create a new Gaussian with different parameters:" |
|
250 | "Create a new Gaussian with different parameters:" | |
251 | ] |
|
251 | ] | |
252 | }, |
|
252 | }, | |
253 | { |
|
253 | { | |
254 | "cell_type": "code", |
|
254 | "cell_type": "code", | |
255 | "execution_count": 7, |
|
255 | "execution_count": 7, | |
256 | "metadata": {}, |
|
256 | "metadata": {}, | |
257 | "outputs": [ |
|
257 | "outputs": [ | |
258 | { |
|
258 | { | |
259 | "data": { |
|
259 | "data": { | |
260 | "image/png": "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\nLnYAAAAASUVORK5CYII=\n", |
|
260 | "image/png": "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\nLnYAAAAASUVORK5CYII=\n", | |
261 | "text/latex": [ |
|
261 | "text/latex": [ | |
262 | "$\\mathcal{N}(\\mu=0, \\sigma=2),\\ N=2000$" |
|
262 | "$\\mathcal{N}(\\mu=0, \\sigma=2),\\ N=2000$" | |
263 | ], |
|
263 | ], | |
264 | "text/plain": [ |
|
264 | "text/plain": [ | |
265 | "<__main__.Gaussian at 0x116fe7668>" |
|
265 | "<__main__.Gaussian at 0x116fe7668>" | |
266 | ] |
|
266 | ] | |
267 | }, |
|
267 | }, | |
268 | "execution_count": 7, |
|
268 | "execution_count": 7, | |
269 | "metadata": {}, |
|
269 | "metadata": {}, | |
270 | "output_type": "execute_result" |
|
270 | "output_type": "execute_result" | |
271 | } |
|
271 | } | |
272 | ], |
|
272 | ], | |
273 | "source": [ |
|
273 | "source": [ | |
274 | "x2 = Gaussian(0, 2, 2000)\n", |
|
274 | "x2 = Gaussian(0, 2, 2000)\n", | |
275 | "x2" |
|
275 | "x2" | |
276 | ] |
|
276 | ] | |
277 | }, |
|
277 | }, | |
278 | { |
|
278 | { | |
279 | "cell_type": "markdown", |
|
279 | "cell_type": "markdown", | |
280 | "metadata": {}, |
|
280 | "metadata": {}, | |
281 | "source": [ |
|
281 | "source": [ | |
282 | "You can then compare the two Gaussians by displaying their histograms:" |
|
282 | "You can then compare the two Gaussians by displaying their histograms:" | |
283 | ] |
|
283 | ] | |
284 | }, |
|
284 | }, | |
285 | { |
|
285 | { | |
286 | "cell_type": "code", |
|
286 | "cell_type": "code", | |
287 | "execution_count": 8, |
|
287 | "execution_count": 8, | |
288 | "metadata": {}, |
|
288 | "metadata": {}, | |
289 | "outputs": [ |
|
289 | "outputs": [ | |
290 | { |
|
290 | { | |
291 | "data": { |
|
291 | "data": { | |
292 | "image/png": "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\n1ADDXpIa8P8BEb7Ae9JKdQAAAAAASUVORK5CYII=\n" |
|
292 | "image/png": "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\n1ADDXpIa8P8BEb7Ae9JKdQAAAAAASUVORK5CYII=\n" | |
293 | }, |
|
293 | }, | |
294 | "metadata": {}, |
|
294 | "metadata": {}, | |
295 | "output_type": "display_data" |
|
295 | "output_type": "display_data" | |
296 | }, |
|
296 | }, | |
297 | { |
|
297 | { | |
298 | "data": { |
|
298 | "data": { | |
299 | "image/png": "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\nLnYAAAAASUVORK5CYII=\n" |
|
299 | "image/png": "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\nLnYAAAAASUVORK5CYII=\n" | |
300 | }, |
|
300 | }, | |
301 | "metadata": {}, |
|
301 | "metadata": {}, | |
302 | "output_type": "display_data" |
|
302 | "output_type": "display_data" | |
303 | } |
|
303 | } | |
304 | ], |
|
304 | ], | |
305 | "source": [ |
|
305 | "source": [ | |
306 | "display_png(x)\n", |
|
306 | "display_png(x)\n", | |
307 | "display_png(x2)" |
|
307 | "display_png(x2)" | |
308 | ] |
|
308 | ] | |
309 | }, |
|
309 | }, | |
310 | { |
|
310 | { | |
311 | "cell_type": "markdown", |
|
311 | "cell_type": "markdown", | |
312 | "metadata": {}, |
|
312 | "metadata": {}, | |
313 | "source": [ |
|
313 | "source": [ | |
314 | "Note that like `print`, you can call any of the `display` functions multiple times in a cell." |
|
314 | "Note that like `print`, you can call any of the `display` functions multiple times in a cell." | |
315 | ] |
|
315 | ] | |
316 | }, |
|
316 | }, | |
317 | { |
|
317 | { | |
318 | "cell_type": "markdown", |
|
318 | "cell_type": "markdown", | |
319 | "metadata": {}, |
|
319 | "metadata": {}, | |
320 | "source": [ |
|
320 | "source": [ | |
321 | "## Adding IPython display support to existing objects" |
|
321 | "## Adding IPython display support to existing objects" | |
322 | ] |
|
322 | ] | |
323 | }, |
|
323 | }, | |
324 | { |
|
324 | { | |
325 | "cell_type": "markdown", |
|
325 | "cell_type": "markdown", | |
326 | "metadata": {}, |
|
326 | "metadata": {}, | |
327 | "source": [ |
|
327 | "source": [ | |
328 | "When you are directly writing your own classes, you can adapt them for display in IPython by following the above approach. But in practice, you often need to work with existing classes that you can't easily modify. We now illustrate how to add rich output capabilities to existing objects. We will use the NumPy polynomials and change their default representation to be a formatted LaTeX expression." |
|
328 | "When you are directly writing your own classes, you can adapt them for display in IPython by following the above approach. But in practice, you often need to work with existing classes that you can't easily modify. We now illustrate how to add rich output capabilities to existing objects. We will use the NumPy polynomials and change their default representation to be a formatted LaTeX expression." | |
329 | ] |
|
329 | ] | |
330 | }, |
|
330 | }, | |
331 | { |
|
331 | { | |
332 | "cell_type": "markdown", |
|
332 | "cell_type": "markdown", | |
333 | "metadata": {}, |
|
333 | "metadata": {}, | |
334 | "source": [ |
|
334 | "source": [ | |
335 | "First, consider how a NumPy polynomial object renders by default:" |
|
335 | "First, consider how a NumPy polynomial object renders by default:" | |
336 | ] |
|
336 | ] | |
337 | }, |
|
337 | }, | |
338 | { |
|
338 | { | |
339 | "cell_type": "code", |
|
339 | "cell_type": "code", | |
340 | "execution_count": 9, |
|
340 | "execution_count": 9, | |
341 | "metadata": {}, |
|
341 | "metadata": {}, | |
342 | "outputs": [ |
|
342 | "outputs": [ | |
343 | { |
|
343 | { | |
344 | "data": { |
|
344 | "data": { | |
345 | "text/plain": [ |
|
345 | "text/plain": [ | |
346 | "Polynomial([ 1., 2., 3.], [-10., 10.], [-1, 1])" |
|
346 | "Polynomial([ 1., 2., 3.], [-10., 10.], [-1, 1])" | |
347 | ] |
|
347 | ] | |
348 | }, |
|
348 | }, | |
349 | "execution_count": 9, |
|
349 | "execution_count": 9, | |
350 | "metadata": {}, |
|
350 | "metadata": {}, | |
351 | "output_type": "execute_result" |
|
351 | "output_type": "execute_result" | |
352 | } |
|
352 | } | |
353 | ], |
|
353 | ], | |
354 | "source": [ |
|
354 | "source": [ | |
355 | "p = np.polynomial.Polynomial([1,2,3], [-10, 10])\n", |
|
355 | "p = np.polynomial.Polynomial([1,2,3], [-10, 10])\n", | |
356 | "p" |
|
356 | "p" | |
357 | ] |
|
357 | ] | |
358 | }, |
|
358 | }, | |
359 | { |
|
359 | { | |
360 | "cell_type": "markdown", |
|
360 | "cell_type": "markdown", | |
361 | "metadata": {}, |
|
361 | "metadata": {}, | |
362 | "source": [ |
|
362 | "source": [ | |
363 | "Next, define a function that pretty-prints a polynomial as a LaTeX string:" |
|
363 | "Next, define a function that pretty-prints a polynomial as a LaTeX string:" | |
364 | ] |
|
364 | ] | |
365 | }, |
|
365 | }, | |
366 | { |
|
366 | { | |
367 | "cell_type": "code", |
|
367 | "cell_type": "code", | |
368 | "execution_count": 10, |
|
368 | "execution_count": 10, | |
369 | "metadata": { |
|
369 | "metadata": { | |
370 | "collapsed": true |
|
370 | "collapsed": true | |
371 | }, |
|
371 | }, | |
372 | "outputs": [], |
|
372 | "outputs": [], | |
373 | "source": [ |
|
373 | "source": [ | |
374 | "def poly_to_latex(p):\n", |
|
374 | "def poly_to_latex(p):\n", | |
375 | " terms = ['%.2g' % p.coef[0]]\n", |
|
375 | " terms = ['%.2g' % p.coef[0]]\n", | |
376 | " if len(p) > 1:\n", |
|
376 | " if len(p) > 1:\n", | |
377 | " term = 'x'\n", |
|
377 | " term = 'x'\n", | |
378 | " c = p.coef[1]\n", |
|
378 | " c = p.coef[1]\n", | |
379 | " if c!=1:\n", |
|
379 | " if c!=1:\n", | |
380 | " term = ('%.2g ' % c) + term\n", |
|
380 | " term = ('%.2g ' % c) + term\n", | |
381 | " terms.append(term)\n", |
|
381 | " terms.append(term)\n", | |
382 | " if len(p) > 2:\n", |
|
382 | " if len(p) > 2:\n", | |
383 | " for i in range(2, len(p)):\n", |
|
383 | " for i in range(2, len(p)):\n", | |
384 | " term = 'x^%d' % i\n", |
|
384 | " term = 'x^%d' % i\n", | |
385 | " c = p.coef[i]\n", |
|
385 | " c = p.coef[i]\n", | |
386 | " if c!=1:\n", |
|
386 | " if c!=1:\n", | |
387 | " term = ('%.2g ' % c) + term\n", |
|
387 | " term = ('%.2g ' % c) + term\n", | |
388 | " terms.append(term)\n", |
|
388 | " terms.append(term)\n", | |
389 | " px = '$P(x)=%s$' % '+'.join(terms)\n", |
|
389 | " px = '$P(x)=%s$' % '+'.join(terms)\n", | |
390 | " dom = r', $x \\in [%.2g,\\ %.2g]$' % tuple(p.domain)\n", |
|
390 | " dom = r', $x \\in [%.2g,\\ %.2g]$' % tuple(p.domain)\n", | |
391 | " return px+dom" |
|
391 | " return px+dom" | |
392 | ] |
|
392 | ] | |
393 | }, |
|
393 | }, | |
394 | { |
|
394 | { | |
395 | "cell_type": "markdown", |
|
395 | "cell_type": "markdown", | |
396 | "metadata": {}, |
|
396 | "metadata": {}, | |
397 | "source": [ |
|
397 | "source": [ | |
398 | "This produces, on our polynomial ``p``, the following:" |
|
398 | "This produces, on our polynomial ``p``, the following:" | |
399 | ] |
|
399 | ] | |
400 | }, |
|
400 | }, | |
401 | { |
|
401 | { | |
402 | "cell_type": "code", |
|
402 | "cell_type": "code", | |
403 | "execution_count": 11, |
|
403 | "execution_count": 11, | |
404 | "metadata": {}, |
|
404 | "metadata": {}, | |
405 | "outputs": [ |
|
405 | "outputs": [ | |
406 | { |
|
406 | { | |
407 | "data": { |
|
407 | "data": { | |
408 | "text/plain": [ |
|
408 | "text/plain": [ | |
409 | "'$P(x)=1+2 x+3 x^2$, $x \\\\in [-10,\\\\ 10]$'" |
|
409 | "'$P(x)=1+2 x+3 x^2$, $x \\\\in [-10,\\\\ 10]$'" | |
410 | ] |
|
410 | ] | |
411 | }, |
|
411 | }, | |
412 | "execution_count": 11, |
|
412 | "execution_count": 11, | |
413 | "metadata": {}, |
|
413 | "metadata": {}, | |
414 | "output_type": "execute_result" |
|
414 | "output_type": "execute_result" | |
415 | } |
|
415 | } | |
416 | ], |
|
416 | ], | |
417 | "source": [ |
|
417 | "source": [ | |
418 | "poly_to_latex(p)" |
|
418 | "poly_to_latex(p)" | |
419 | ] |
|
419 | ] | |
420 | }, |
|
420 | }, | |
421 | { |
|
421 | { | |
422 | "cell_type": "markdown", |
|
422 | "cell_type": "markdown", | |
423 | "metadata": {}, |
|
423 | "metadata": {}, | |
424 | "source": [ |
|
424 | "source": [ | |
425 | "You can render this string using the `Latex` class:" |
|
425 | "You can render this string using the `Latex` class:" | |
426 | ] |
|
426 | ] | |
427 | }, |
|
427 | }, | |
428 | { |
|
428 | { | |
429 | "cell_type": "code", |
|
429 | "cell_type": "code", | |
430 | "execution_count": 12, |
|
430 | "execution_count": 12, | |
431 | "metadata": {}, |
|
431 | "metadata": {}, | |
432 | "outputs": [ |
|
432 | "outputs": [ | |
433 | { |
|
433 | { | |
434 | "data": { |
|
434 | "data": { | |
435 | "text/latex": [ |
|
435 | "text/latex": [ | |
436 | "$P(x)=1+2 x+3 x^2$, $x \\in [-10,\\ 10]$" |
|
436 | "$P(x)=1+2 x+3 x^2$, $x \\in [-10,\\ 10]$" | |
437 | ], |
|
437 | ], | |
438 | "text/plain": [ |
|
438 | "text/plain": [ | |
439 | "<IPython.core.display.Latex object>" |
|
439 | "<IPython.core.display.Latex object>" | |
440 | ] |
|
440 | ] | |
441 | }, |
|
441 | }, | |
442 | "execution_count": 12, |
|
442 | "execution_count": 12, | |
443 | "metadata": {}, |
|
443 | "metadata": {}, | |
444 | "output_type": "execute_result" |
|
444 | "output_type": "execute_result" | |
445 | } |
|
445 | } | |
446 | ], |
|
446 | ], | |
447 | "source": [ |
|
447 | "source": [ | |
448 | "from IPython.display import Latex\n", |
|
448 | "from IPython.display import Latex\n", | |
449 | "Latex(poly_to_latex(p))" |
|
449 | "Latex(poly_to_latex(p))" | |
450 | ] |
|
450 | ] | |
451 | }, |
|
451 | }, | |
452 | { |
|
452 | { | |
453 | "cell_type": "markdown", |
|
453 | "cell_type": "markdown", | |
454 | "metadata": {}, |
|
454 | "metadata": {}, | |
455 | "source": [ |
|
455 | "source": [ | |
456 | "However, you can configure IPython to do this automatically by registering the `Polynomial` class and the `poly_to_latex` function with an IPython display formatter. Let's look at the default formatters provided by IPython:" |
|
456 | "However, you can configure IPython to do this automatically by registering the `Polynomial` class and the `poly_to_latex` function with an IPython display formatter. Let's look at the default formatters provided by IPython:" | |
457 | ] |
|
457 | ] | |
458 | }, |
|
458 | }, | |
459 | { |
|
459 | { | |
460 | "cell_type": "code", |
|
460 | "cell_type": "code", | |
461 | "execution_count": 13, |
|
461 | "execution_count": 13, | |
462 | "metadata": {}, |
|
462 | "metadata": {}, | |
463 | "outputs": [ |
|
463 | "outputs": [ | |
464 | { |
|
464 | { | |
465 | "name": "stdout", |
|
465 | "name": "stdout", | |
466 | "output_type": "stream", |
|
466 | "output_type": "stream", | |
467 | "text": [ |
|
467 | "text": [ | |
468 | " text/plain : PlainTextFormatter\n", |
|
468 | " text/plain : PlainTextFormatter\n", | |
469 | " text/html : HTMLFormatter\n", |
|
469 | " text/html : HTMLFormatter\n", | |
470 | " text/markdown : MarkdownFormatter\n", |
|
470 | " text/markdown : MarkdownFormatter\n", | |
471 | " image/svg+xml : SVGFormatter\n", |
|
471 | " image/svg+xml : SVGFormatter\n", | |
472 | " image/png : PNGFormatter\n", |
|
472 | " image/png : PNGFormatter\n", | |
473 | " application/pdf : PDFFormatter\n", |
|
473 | " application/pdf : PDFFormatter\n", | |
474 | " image/jpeg : JPEGFormatter\n", |
|
474 | " image/jpeg : JPEGFormatter\n", | |
475 | " text/latex : LatexFormatter\n", |
|
475 | " text/latex : LatexFormatter\n", | |
476 | " application/json : JSONFormatter\n", |
|
476 | " application/json : JSONFormatter\n", | |
477 | " application/javascript : JavascriptFormatter\n" |
|
477 | " application/javascript : JavascriptFormatter\n" | |
478 | ] |
|
478 | ] | |
479 | } |
|
479 | } | |
480 | ], |
|
480 | ], | |
481 | "source": [ |
|
481 | "source": [ | |
482 | "ip = get_ipython()\n", |
|
482 | "ip = get_ipython()\n", | |
483 | "for mime, formatter in ip.display_formatter.formatters.items():\n", |
|
483 | "for mime, formatter in ip.display_formatter.formatters.items():\n", | |
484 | " print('%24s : %s' % (mime, formatter.__class__.__name__))" |
|
484 | " print('%24s : %s' % (mime, formatter.__class__.__name__))" | |
485 | ] |
|
485 | ] | |
486 | }, |
|
486 | }, | |
487 | { |
|
487 | { | |
488 | "cell_type": "markdown", |
|
488 | "cell_type": "markdown", | |
489 | "metadata": {}, |
|
489 | "metadata": {}, | |
490 | "source": [ |
|
490 | "source": [ | |
491 | "The `formatters` attribute is a dictionary keyed by MIME types. To define a custom LaTeX display function, you want a handle on the `text/latex` formatter:" |
|
491 | "The `formatters` attribute is a dictionary keyed by MIME types. To define a custom LaTeX display function, you want a handle on the `text/latex` formatter:" | |
492 | ] |
|
492 | ] | |
493 | }, |
|
493 | }, | |
494 | { |
|
494 | { | |
495 | "cell_type": "code", |
|
495 | "cell_type": "code", | |
496 | "execution_count": 14, |
|
496 | "execution_count": 14, | |
497 | "metadata": { |
|
497 | "metadata": { | |
498 | "collapsed": true |
|
498 | "collapsed": true | |
499 | }, |
|
499 | }, | |
500 | "outputs": [], |
|
500 | "outputs": [], | |
501 | "source": [ |
|
501 | "source": [ | |
502 | "ip = get_ipython()\n", |
|
502 | "ip = get_ipython()\n", | |
503 | "latex_f = ip.display_formatter.formatters['text/latex']" |
|
503 | "latex_f = ip.display_formatter.formatters['text/latex']" | |
504 | ] |
|
504 | ] | |
505 | }, |
|
505 | }, | |
506 | { |
|
506 | { | |
507 | "cell_type": "markdown", |
|
507 | "cell_type": "markdown", | |
508 | "metadata": {}, |
|
508 | "metadata": {}, | |
509 | "source": [ |
|
509 | "source": [ | |
510 | "The formatter object has a couple of methods for registering custom display functions for existing types." |
|
510 | "The formatter object has a couple of methods for registering custom display functions for existing types." | |
511 | ] |
|
511 | ] | |
512 | }, |
|
512 | }, | |
513 | { |
|
513 | { | |
514 | "cell_type": "code", |
|
514 | "cell_type": "code", | |
515 | "execution_count": 15, |
|
515 | "execution_count": 15, | |
516 | "metadata": {}, |
|
516 | "metadata": {}, | |
517 | "outputs": [ |
|
517 | "outputs": [ | |
518 | { |
|
518 | { | |
519 | "name": "stdout", |
|
519 | "name": "stdout", | |
520 | "output_type": "stream", |
|
520 | "output_type": "stream", | |
521 | "text": [ |
|
521 | "text": [ | |
522 | "Help on method for_type in module IPython.core.formatters:\n", |
|
522 | "Help on method for_type in module IPython.core.formatters:\n", | |
523 | "\n", |
|
523 | "\n", | |
524 | "for_type(typ, func=None) method of IPython.core.formatters.LatexFormatter instance\n", |
|
524 | "for_type(typ, func=None) method of IPython.core.formatters.LatexFormatter instance\n", | |
525 | " Add a format function for a given type.\n", |
|
525 | " Add a format function for a given type.\n", | |
526 | " \n", |
|
526 | " \n", | |
527 | " Parameters\n", |
|
527 | " Parameters\n", | |
528 | " -----------\n", |
|
528 | " -----------\n", | |
529 | " typ : type or '__module__.__name__' string for a type\n", |
|
529 | " typ : type or '__module__.__name__' string for a type\n", | |
530 | " The class of the object that will be formatted using `func`.\n", |
|
530 | " The class of the object that will be formatted using `func`.\n", | |
531 | " func : callable\n", |
|
531 | " func : callable\n", | |
532 | " A callable for computing the format data.\n", |
|
532 | " A callable for computing the format data.\n", | |
533 | " `func` will be called with the object to be formatted,\n", |
|
533 | " `func` will be called with the object to be formatted,\n", | |
534 | " and will return the raw data in this formatter's format.\n", |
|
534 | " and will return the raw data in this formatter's format.\n", | |
535 | " Subclasses may use a different call signature for the\n", |
|
535 | " Subclasses may use a different call signature for the\n", | |
536 | " `func` argument.\n", |
|
536 | " `func` argument.\n", | |
537 | " \n", |
|
537 | " \n", | |
538 | " If `func` is None or not specified, there will be no change,\n", |
|
538 | " If `func` is None or not specified, there will be no change,\n", | |
539 | " only returning the current value.\n", |
|
539 | " only returning the current value.\n", | |
540 | " \n", |
|
540 | " \n", | |
541 | " Returns\n", |
|
541 | " Returns\n", | |
542 | " -------\n", |
|
542 | " -------\n", | |
543 | " oldfunc : callable\n", |
|
543 | " oldfunc : callable\n", | |
544 | " The currently registered callable.\n", |
|
544 | " The currently registered callable.\n", | |
545 | " If you are registering a new formatter,\n", |
|
545 | " If you are registering a new formatter,\n", | |
546 | " this will be the previous value (to enable restoring later).\n", |
|
546 | " this will be the previous value (to enable restoring later).\n", | |
547 | "\n" |
|
547 | "\n" | |
548 | ] |
|
548 | ] | |
549 | } |
|
549 | } | |
550 | ], |
|
550 | ], | |
551 | "source": [ |
|
551 | "source": [ | |
552 | "help(latex_f.for_type)" |
|
552 | "help(latex_f.for_type)" | |
553 | ] |
|
553 | ] | |
554 | }, |
|
554 | }, | |
555 | { |
|
555 | { | |
556 | "cell_type": "code", |
|
556 | "cell_type": "code", | |
557 | "execution_count": 16, |
|
557 | "execution_count": 16, | |
558 | "metadata": {}, |
|
558 | "metadata": {}, | |
559 | "outputs": [ |
|
559 | "outputs": [ | |
560 | { |
|
560 | { | |
561 | "name": "stdout", |
|
561 | "name": "stdout", | |
562 | "output_type": "stream", |
|
562 | "output_type": "stream", | |
563 | "text": [ |
|
563 | "text": [ | |
564 | "Help on method for_type_by_name in module IPython.core.formatters:\n", |
|
564 | "Help on method for_type_by_name in module IPython.core.formatters:\n", | |
565 | "\n", |
|
565 | "\n", | |
566 | "for_type_by_name(type_module, type_name, func=None) method of IPython.core.formatters.LatexFormatter instance\n", |
|
566 | "for_type_by_name(type_module, type_name, func=None) method of IPython.core.formatters.LatexFormatter instance\n", | |
567 | " Add a format function for a type specified by the full dotted\n", |
|
567 | " Add a format function for a type specified by the full dotted\n", | |
568 | " module and name of the type, rather than the type of the object.\n", |
|
568 | " module and name of the type, rather than the type of the object.\n", | |
569 | " \n", |
|
569 | " \n", | |
570 | " Parameters\n", |
|
570 | " Parameters\n", | |
571 | " ----------\n", |
|
571 | " ----------\n", | |
572 | " type_module : str\n", |
|
572 | " type_module : str\n", | |
573 | " The full dotted name of the module the type is defined in, like\n", |
|
573 | " The full dotted name of the module the type is defined in, like\n", | |
574 | " ``numpy``.\n", |
|
574 | " ``numpy``.\n", | |
575 | " type_name : str\n", |
|
575 | " type_name : str\n", | |
576 | " The name of the type (the class name), like ``dtype``\n", |
|
576 | " The name of the type (the class name), like ``dtype``\n", | |
577 | " func : callable\n", |
|
577 | " func : callable\n", | |
578 | " A callable for computing the format data.\n", |
|
578 | " A callable for computing the format data.\n", | |
579 | " `func` will be called with the object to be formatted,\n", |
|
579 | " `func` will be called with the object to be formatted,\n", | |
580 | " and will return the raw data in this formatter's format.\n", |
|
580 | " and will return the raw data in this formatter's format.\n", | |
581 | " Subclasses may use a different call signature for the\n", |
|
581 | " Subclasses may use a different call signature for the\n", | |
582 | " `func` argument.\n", |
|
582 | " `func` argument.\n", | |
583 | " \n", |
|
583 | " \n", | |
584 | " If `func` is None or unspecified, there will be no change,\n", |
|
584 | " If `func` is None or unspecified, there will be no change,\n", | |
585 | " only returning the current value.\n", |
|
585 | " only returning the current value.\n", | |
586 | " \n", |
|
586 | " \n", | |
587 | " Returns\n", |
|
587 | " Returns\n", | |
588 | " -------\n", |
|
588 | " -------\n", | |
589 | " oldfunc : callable\n", |
|
589 | " oldfunc : callable\n", | |
590 | " The currently registered callable.\n", |
|
590 | " The currently registered callable.\n", | |
591 | " If you are registering a new formatter,\n", |
|
591 | " If you are registering a new formatter,\n", | |
592 | " this will be the previous value (to enable restoring later).\n", |
|
592 | " this will be the previous value (to enable restoring later).\n", | |
593 | "\n" |
|
593 | "\n" | |
594 | ] |
|
594 | ] | |
595 | } |
|
595 | } | |
596 | ], |
|
596 | ], | |
597 | "source": [ |
|
597 | "source": [ | |
598 | "help(latex_f.for_type_by_name)" |
|
598 | "help(latex_f.for_type_by_name)" | |
599 | ] |
|
599 | ] | |
600 | }, |
|
600 | }, | |
601 | { |
|
601 | { | |
602 | "cell_type": "markdown", |
|
602 | "cell_type": "markdown", | |
603 | "metadata": {}, |
|
603 | "metadata": {}, | |
604 | "source": [ |
|
604 | "source": [ | |
605 | "In this case, we will use `for_type_by_name` to register `poly_to_latex` as the display function for the `Polynomial` type:" |
|
605 | "In this case, we will use `for_type_by_name` to register `poly_to_latex` as the display function for the `Polynomial` type:" | |
606 | ] |
|
606 | ] | |
607 | }, |
|
607 | }, | |
608 | { |
|
608 | { | |
609 | "cell_type": "code", |
|
609 | "cell_type": "code", | |
610 | "execution_count": 17, |
|
610 | "execution_count": 17, | |
611 | "metadata": { |
|
611 | "metadata": { | |
612 | "collapsed": true |
|
612 | "collapsed": true | |
613 | }, |
|
613 | }, | |
614 | "outputs": [], |
|
614 | "outputs": [], | |
615 | "source": [ |
|
615 | "source": [ | |
616 | "latex_f.for_type_by_name('numpy.polynomial.polynomial',\n", |
|
616 | "latex_f.for_type_by_name('numpy.polynomial.polynomial',\n", | |
617 | " 'Polynomial', poly_to_latex)" |
|
617 | " 'Polynomial', poly_to_latex)" | |
618 | ] |
|
618 | ] | |
619 | }, |
|
619 | }, | |
620 | { |
|
620 | { | |
621 | "cell_type": "markdown", |
|
621 | "cell_type": "markdown", | |
622 | "metadata": {}, |
|
622 | "metadata": {}, | |
623 | "source": [ |
|
623 | "source": [ | |
624 | "Once the custom display function has been registered, all NumPy `Polynomial` instances will be represented by their LaTeX form instead:" |
|
624 | "Once the custom display function has been registered, all NumPy `Polynomial` instances will be represented by their LaTeX form instead:" | |
625 | ] |
|
625 | ] | |
626 | }, |
|
626 | }, | |
627 | { |
|
627 | { | |
628 | "cell_type": "code", |
|
628 | "cell_type": "code", | |
629 | "execution_count": 18, |
|
629 | "execution_count": 18, | |
630 | "metadata": {}, |
|
630 | "metadata": {}, | |
631 | "outputs": [ |
|
631 | "outputs": [ | |
632 | { |
|
632 | { | |
633 | "data": { |
|
633 | "data": { | |
634 | "text/latex": [ |
|
634 | "text/latex": [ | |
635 | "$P(x)=1+2 x+3 x^2$, $x \\in [-10,\\ 10]$" |
|
635 | "$P(x)=1+2 x+3 x^2$, $x \\in [-10,\\ 10]$" | |
636 | ], |
|
636 | ], | |
637 | "text/plain": [ |
|
637 | "text/plain": [ | |
638 | "Polynomial([ 1., 2., 3.], [-10., 10.], [-1, 1])" |
|
638 | "Polynomial([ 1., 2., 3.], [-10., 10.], [-1, 1])" | |
639 | ] |
|
639 | ] | |
640 | }, |
|
640 | }, | |
641 | "execution_count": 18, |
|
641 | "execution_count": 18, | |
642 | "metadata": {}, |
|
642 | "metadata": {}, | |
643 | "output_type": "execute_result" |
|
643 | "output_type": "execute_result" | |
644 | } |
|
644 | } | |
645 | ], |
|
645 | ], | |
646 | "source": [ |
|
646 | "source": [ | |
647 | "p" |
|
647 | "p" | |
648 | ] |
|
648 | ] | |
649 | }, |
|
649 | }, | |
650 | { |
|
650 | { | |
651 | "cell_type": "code", |
|
651 | "cell_type": "code", | |
652 | "execution_count": 19, |
|
652 | "execution_count": 19, | |
653 | "metadata": {}, |
|
653 | "metadata": {}, | |
654 | "outputs": [ |
|
654 | "outputs": [ | |
655 | { |
|
655 | { | |
656 | "data": { |
|
656 | "data": { | |
657 | "text/latex": [ |
|
657 | "text/latex": [ | |
658 | "$P(x)=-20+71 x+-15 x^2+x^3$, $x \\in [-1,\\ 1]$" |
|
658 | "$P(x)=-20+71 x+-15 x^2+x^3$, $x \\in [-1,\\ 1]$" | |
659 | ], |
|
659 | ], | |
660 | "text/plain": [ |
|
660 | "text/plain": [ | |
661 | "Polynomial([-20., 71., -15., 1.], [-1, 1], [-1, 1])" |
|
661 | "Polynomial([-20., 71., -15., 1.], [-1, 1], [-1, 1])" | |
662 | ] |
|
662 | ] | |
663 | }, |
|
663 | }, | |
664 | "execution_count": 19, |
|
664 | "execution_count": 19, | |
665 | "metadata": {}, |
|
665 | "metadata": {}, | |
666 | "output_type": "execute_result" |
|
666 | "output_type": "execute_result" | |
667 | } |
|
667 | } | |
668 | ], |
|
668 | ], | |
669 | "source": [ |
|
669 | "source": [ | |
670 | "p2 = np.polynomial.Polynomial([-20, 71, -15, 1])\n", |
|
670 | "p2 = np.polynomial.Polynomial([-20, 71, -15, 1])\n", | |
671 | "p2" |
|
671 | "p2" | |
672 | ] |
|
672 | ] | |
673 | }, |
|
673 | }, | |
674 | { |
|
674 | { | |
675 | "cell_type": "markdown", |
|
675 | "cell_type": "markdown", | |
676 | "metadata": {}, |
|
676 | "metadata": {}, | |
677 | "source": [ |
|
677 | "source": [ | |
678 | "## Custom Mimetypes with `_repr_mimebundle_`\n", |
|
678 | "## Custom Mimetypes with `_repr_mimebundle_`\n", | |
679 | "\n", |
|
679 | "\n", | |
680 | "Available on IPython 5.4+ and 6.1+.\n", |
|
680 | "Available on IPython 5.4+ and 6.1+.\n", | |
681 | "\n", |
|
681 | "\n", | |
682 | "For objects needing full control over the `repr` protocol may decide to implement the `_repr_mimebundle_(include, exclude)` method.\n", |
|
682 | "For objects needing full control over the `repr` protocol may decide to implement the `_repr_mimebundle_(include, exclude)` method.\n", | |
683 | "Unlike the other `_repr_*_` methods must return many representation of the object in a mapping object which keys are _mimetypes_ and value are associated data. The `_repr_mimebundle_()` method, may also return a second mapping from _mimetypes_ to metadata. \n", |
|
683 | "Unlike the other `_repr_*_` methods must return many representation of the object in a mapping object which keys are _mimetypes_ and value are associated data. The `_repr_mimebundle_()` method, may also return a second mapping from _mimetypes_ to metadata. \n", | |
684 | "\n", |
|
684 | "\n", | |
685 | "Example:" |
|
685 | "Example:" | |
686 | ] |
|
686 | ] | |
687 | }, |
|
687 | }, | |
688 | { |
|
688 | { | |
689 | "cell_type": "code", |
|
689 | "cell_type": "code", | |
690 | "execution_count": 20, |
|
690 | "execution_count": 20, | |
691 | "metadata": { |
|
691 | "metadata": { | |
692 | "collapsed": true |
|
692 | "collapsed": true | |
693 | }, |
|
693 | }, | |
694 | "outputs": [], |
|
694 | "outputs": [], | |
695 | "source": [ |
|
695 | "source": [ | |
696 | "class Gaussian(object):\n", |
|
696 | "class Gaussian(object):\n", | |
697 | " \"\"\"A simple object holding data sampled from a Gaussian distribution.\n", |
|
697 | " \"\"\"A simple object holding data sampled from a Gaussian distribution.\n", | |
698 | " \"\"\"\n", |
|
698 | " \"\"\"\n", | |
699 | " def __init__(self, mean=0.0, std=1, size=1000):\n", |
|
699 | " def __init__(self, mean=0.0, std=1, size=1000):\n", | |
700 | " self.data = np.random.normal(mean, std, size)\n", |
|
700 | " self.data = np.random.normal(mean, std, size)\n", | |
701 | " self.mean = mean\n", |
|
701 | " self.mean = mean\n", | |
702 | " self.std = std\n", |
|
702 | " self.std = std\n", | |
703 | " self.size = size\n", |
|
703 | " self.size = size\n", | |
704 | " # For caching plots that may be expensive to compute\n", |
|
704 | " # For caching plots that may be expensive to compute\n", | |
705 | " self._png_data = None\n", |
|
705 | " self._png_data = None\n", | |
706 | " \n", |
|
706 | " \n", | |
707 | " def _figure_data(self, format):\n", |
|
707 | " def _figure_data(self, format):\n", | |
708 | " fig, ax = plt.subplots()\n", |
|
708 | " fig, ax = plt.subplots()\n", | |
709 | " ax.hist(self.data, bins=50)\n", |
|
709 | " ax.hist(self.data, bins=50)\n", | |
710 | " ax.set_xlim(-10.0,10.0)\n", |
|
710 | " ax.set_xlim(-10.0,10.0)\n", | |
711 | " data = print_figure(fig, format)\n", |
|
711 | " data = print_figure(fig, format)\n", | |
712 | " # We MUST close the figure, otherwise IPython's display machinery\n", |
|
712 | " # We MUST close the figure, otherwise IPython's display machinery\n", | |
713 | " # will pick it up and send it as output, resulting in a double display\n", |
|
713 | " # will pick it up and send it as output, resulting in a double display\n", | |
714 | " plt.close(fig)\n", |
|
714 | " plt.close(fig)\n", | |
715 | " return data\n", |
|
715 | " return data\n", | |
716 | " \n", |
|
716 | " \n", | |
717 | " def _compute_mathml(self):\n", |
|
717 | " def _compute_mathml(self):\n", | |
718 | " return \"\"\"\n", |
|
718 | " return \"\"\"\n", | |
719 | " <math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n", |
|
719 | " <math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n", | |
720 | " <mrow class=\"MJX-TeXAtom-ORD\">\n", |
|
720 | " <mrow class=\"MJX-TeXAtom-ORD\">\n", | |
721 | " <mi class=\"MJX-tex-caligraphic\" mathvariant=\"script\">N</mi>\n", |
|
721 | " <mi class=\"MJX-tex-caligraphic\" mathvariant=\"script\">N</mi>\n", | |
722 | " </mrow>\n", |
|
722 | " </mrow>\n", | |
723 | " <mo stretchy=\"false\">(</mo>\n", |
|
723 | " <mo stretchy=\"false\">(</mo>\n", | |
724 | " <mi>μ<!-- ΞΌ --></mi>\n", |
|
724 | " <mi>μ<!-- ΞΌ --></mi>\n", | |
725 | " <mo>=</mo>\n", |
|
725 | " <mo>=</mo>\n", | |
726 | " <mn>{mu}</mn>\n", |
|
726 | " <mn>{mu}</mn>\n", | |
727 | " <mo>,</mo>\n", |
|
727 | " <mo>,</mo>\n", | |
728 | " <mi>σ<!-- Ο --></mi>\n", |
|
728 | " <mi>σ<!-- Ο --></mi>\n", | |
729 | " <mo>=</mo>\n", |
|
729 | " <mo>=</mo>\n", | |
730 | " <mn>{sigma}</mn>\n", |
|
730 | " <mn>{sigma}</mn>\n", | |
731 | " <mo stretchy=\"false\">)</mo>\n", |
|
731 | " <mo stretchy=\"false\">)</mo>\n", | |
732 | " <mo>,</mo>\n", |
|
732 | " <mo>,</mo>\n", | |
733 | " <mtext> </mtext>\n", |
|
733 | " <mtext> </mtext>\n", | |
734 | " <mi>N</mi>\n", |
|
734 | " <mi>N</mi>\n", | |
735 | " <mo>=</mo>\n", |
|
735 | " <mo>=</mo>\n", | |
736 | " <mn>{N}</mn>\n", |
|
736 | " <mn>{N}</mn>\n", | |
737 | " </math>\n", |
|
737 | " </math>\n", | |
738 | " \"\"\".format(N=self.size, mu=self.mean, sigma=self.std)\n", |
|
738 | " \"\"\".format(N=self.size, mu=self.mean, sigma=self.std)\n", | |
739 | " \n", |
|
739 | " \n", | |
740 | " def _repr_mimebundle_(self, include, exclude, **kwargs):\n", |
|
740 | " def _repr_mimebundle_(self, include, exclude, **kwargs):\n", | |
741 | " \"\"\"\n", |
|
741 | " \"\"\"\n", | |
742 | " repr_mimebundle shoudl accept include, exclude and **kwargs\n", |
|
742 | " repr_mimebundle shoudl accept include, exclude and **kwargs\n", | |
743 | " \"\"\"\n", |
|
743 | " \"\"\"\n", | |
744 | " if self._png_data is None:\n", |
|
744 | " if self._png_data is None:\n", | |
745 | " self._png_data = self._figure_data('png')\n", |
|
745 | " self._png_data = self._figure_data('png')\n", | |
746 | " math = r'$\\mathcal{N}(\\mu=%.2g, \\sigma=%.2g),\\ N=%d$' % (self.mean,\n", |
|
746 | " math = r'$\\mathcal{N}(\\mu=%.2g, \\sigma=%.2g),\\ N=%d$' % (self.mean,\n", | |
747 | " self.std, self.size)\n", |
|
747 | " self.std, self.size)\n", | |
748 | " data = {'image/png':self._png_data,\n", |
|
748 | " data = {'image/png':self._png_data,\n", | |
749 | " 'text/latex':math,\n", |
|
749 | " 'text/latex':math,\n", | |
750 | " 'application/mathml+xml': self._compute_mathml()\n", |
|
750 | " 'application/mathml+xml': self._compute_mathml()\n", | |
751 | " }\n", |
|
751 | " }\n", | |
752 | " if include:\n", |
|
752 | " if include:\n", | |
753 | " data = {k:v for (k,v) in data.items() if k in include}\n", |
|
753 | " data = {k:v for (k,v) in data.items() if k in include}\n", | |
754 | " if exclude:\n", |
|
754 | " if exclude:\n", | |
755 | " data = {k:v for (k,v) in data.items() if k not in exclude}\n", |
|
755 | " data = {k:v for (k,v) in data.items() if k not in exclude}\n", | |
756 | " return data" |
|
756 | " return data" | |
757 | ] |
|
757 | ] | |
758 | }, |
|
758 | }, | |
759 | { |
|
759 | { | |
760 | "cell_type": "code", |
|
760 | "cell_type": "code", | |
761 | "execution_count": 21, |
|
761 | "execution_count": 21, | |
762 | "metadata": {}, |
|
762 | "metadata": {}, | |
763 | "outputs": [ |
|
763 | "outputs": [ | |
764 | { |
|
764 | { | |
765 | "data": { |
|
765 | "data": { | |
766 | "application/mathml+xml": "\n <math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n <mrow class=\"MJX-TeXAtom-ORD\">\n <mi class=\"MJX-tex-caligraphic\" mathvariant=\"script\">N</mi>\n </mrow>\n <mo stretchy=\"false\">(</mo>\n <mi>μ<!-- ΞΌ --></mi>\n <mo>=</mo>\n <mn>0.0</mn>\n <mo>,</mo>\n <mi>σ<!-- Ο --></mi>\n <mo>=</mo>\n <mn>1</mn>\n <mo stretchy=\"false\">)</mo>\n <mo>,</mo>\n <mtext> </mtext>\n <mi>N</mi>\n <mo>=</mo>\n <mn>1000</mn>\n </math>\n ", |
|
766 | "application/mathml+xml": "\n <math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n <mrow class=\"MJX-TeXAtom-ORD\">\n <mi class=\"MJX-tex-caligraphic\" mathvariant=\"script\">N</mi>\n </mrow>\n <mo stretchy=\"false\">(</mo>\n <mi>μ<!-- ΞΌ --></mi>\n <mo>=</mo>\n <mn>0.0</mn>\n <mo>,</mo>\n <mi>σ<!-- Ο --></mi>\n <mo>=</mo>\n <mn>1</mn>\n <mo stretchy=\"false\">)</mo>\n <mo>,</mo>\n <mtext> </mtext>\n <mi>N</mi>\n <mo>=</mo>\n <mn>1000</mn>\n </math>\n ", | |
767 | "image/png": "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\nDfgfS9fLKUqMYTsAAAAASUVORK5CYII=\n", |
|
767 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXsAAAD8CAYAAACW/ATfAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAEftJREFUeJzt3X+MZWddx/H3x5aCQKVbOi0LZd2SNBU0oS2TBkUNsvwo\nlLDFUFJidIWaFQ0EYowskhgV/1g0/kxUstLKahBaCrUbWn6sSwkx0cK2tKVlW7etS1m77C4/SlES\ntPL1j3sWx/FO587cc++d2ef9Sib3nHPPueeb55753Geee86ZVBWSpJPbD8y6AEnS5Bn2ktQAw16S\nGmDYS1IDDHtJaoBhL0kNMOwlqQGGvSQ1wLCXpAacOs2dnXXWWbV58+Zp7lKS1r3bbrvta1U1N85r\nTDXsN2/ezP79+6e5S0la95J8edzXcBhHkhpg2EtSA5YN+yQXJLljwc+jSd6e5Mwke5Mc7B43TKNg\nSdLKLRv2VXVfVV1YVRcCLwC+A9wA7AD2VdX5wL5uXpK0Bq10GGcL8EBVfRnYCuzulu8GLu+zMElS\nf1Ya9lcCH+ymz6mqIwDd49l9FiZJ6s/IYZ/kNOA1wIdXsoMk25PsT7L/+PHjK61PktSDlfTsXwnc\nXlVHu/mjSTYCdI/Hhm1UVbuqar6q5ufmxromQJK0SisJ+zfwv0M4AHuAbd30NuDGvoqSJPVrpCto\nkzwZeBnwywsW7wSuS3IV8BBwRf/lSbO3ecdN358+tPOyGVYird5IYV9V3wGevmjZ1xmcnSNJWuO8\nglaSGmDYS1IDDHtJaoBhL0kNmOr97KW1xjNt1Ap79pLUAMNekhpg2EtSAwx7SWqAYS9JDTDsJakB\nhr0kNcCwl6QGGPaS1ADDXpIaYNhLUgMMe0lqgGEvSQ0w7CWpAYa9JDXAsJekBowU9knOSHJ9knuT\nHEjy40nOTLI3ycHuccOki5Ukrc6oPfs/BT5RVT8CPB84AOwA9lXV+cC+bl6StAYtG/ZJfgj4aeBq\ngKr6z6p6BNgK7O5W2w1cPqkiJUnjGaVn/xzgOPDXSb6Q5H1JngKcU1VHALrHsydYpyRpDKOE/anA\nxcBfVtVFwH+wgiGbJNuT7E+y//jx46ssU5I0jlHC/jBwuKpu7eavZxD+R5NsBOgejw3buKp2VdV8\nVc3Pzc31UbMkaYWWDfuq+irwlSQXdIu2AF8C9gDbumXbgBsnUqEkaWynjrjeW4EPJDkNeBB4I4MP\niuuSXAU8BFwxmRIlSeMaKeyr6g5gfshTW/otR5I0CV5BK0kNMOwlqQGGvSQ1wLCXpAYY9pLUAMNe\nkhpg2EtSAwx7SWqAYS9JDTDsJakBo94bRzopbN5x06xLkGbCnr0kNcCwl6QGGPaS1ADDXpIaYNhL\nUgMMe2mRzTtu8qwdnXQMe0lqgGEvSQ0w7CWpAYa9JDVgpNslJDkEfBv4b+CxqppPciZwLbAZOAS8\nvqq+OZkyJUnjWEnP/meq6sKqmu/mdwD7qup8YF83L0lag8YZxtkK7O6mdwOXj1+OJGkSRg37Aj6V\n5LYk27tl51TVEYDu8exJFChJGt+otzh+UVU9nORsYG+Se0fdQffhsB1g06ZNqyhRkjSukXr2VfVw\n93gMuAG4BDiaZCNA93hsiW13VdV8Vc3Pzc31U7UkaUWWDfskT0ly+olp4OXA3cAeYFu32jbgxkkV\nKUkazyjDOOcANyQ5sf7fVdUnknweuC7JVcBDwBWTK1OaPu+Po5PJsmFfVQ8Czx+y/OvAlkkUJUnq\nl1fQSlIDDHtJaoBhL0kNMOwlqQGjXlQlrTsLz6Y5tPOyGVYizZ49e0lqgGEvSQ0w7CWpAYa9JDXA\nsJekBhj2ktQAw16SGmDYS1IDDHtJaoBhL0kNMOwlqQGGvbQCm3fc5H+w0rpk2EtSAwx7SWqAYS9J\nDTDsJakBI4d9klOSfCHJx7r585LcmuRgkmuTnDa5MiVJ41hJz/5twIEF8+8B/riqzge+CVzVZ2GS\npP6MFPZJzgUuA97XzQd4CXB9t8pu4PJJFChJGt+oPfs/AX4D+F43/3Tgkap6rJs/DDyr59okST1Z\n9h+OJ3k1cKyqbkvy4hOLh6xaS2y/HdgOsGnTplWWKY3HC6HUulF69i8CXpPkEPAhBsM3fwKckeTE\nh8W5wMPDNq6qXVU1X1Xzc3NzPZQsSVqpZcO+qt5ZVedW1WbgSuDTVfVzwC3A67rVtgE3TqxKSdJY\nxjnP/h3AryW5n8EY/tX9lCRJ6tuyY/YLVdVngM900w8Cl/RfkiSpb15BK0kNMOwlqQGGvSQ1wLCX\npAas6Ata6WTmhVc6mdmzl6QGGPaS1ACHcaQeLRwKOrTzshlWIv1f9uwlqQGGvSQ1wLCXxrB5x02e\nxaN1wbCXpAYY9pLUAM/G0UnHYRXp/7NnL0kNMOwlqQEO42hdGnbxksM30tLs2UtSAwx7SWqAwzjS\nKjhkpPXGnr0kNWDZsE/ypCSfS3JnknuS/E63/LwktyY5mOTaJKdNvlxJ0mqM0rP/LvCSqno+cCFw\naZIXAu8B/riqzge+CVw1uTIlSeNYNuxr4N+72Sd0PwW8BLi+W74buHwiFUqSxjbSmH2SU5LcARwD\n9gIPAI9U1WPdKoeBZ02mREnSuEYK+6r676q6EDgXuAR47rDVhm2bZHuS/Un2Hz9+fPWVSpJWbUVn\n41TVI8BngBcCZyQ5cermucDDS2yzq6rmq2p+bm5unFolSas0ytk4c0nO6KZ/EHgpcAC4BXhdt9o2\n4MZJFSlJGs8oF1VtBHYnOYXBh8N1VfWxJF8CPpTk94AvAFdPsE5p3Tlx4ZX/eFxrwbJhX1V3ARcN\nWf4gg/F7SdIa5xW0ktQAw16SGmDYS1IDDHtJaoBhL0kNMOwlqQGGvSQ1wLCXpAYY9pLUAMNekhrg\nPxzXuuc//5aWZ89ekhpg2EtSAxzG0brikI20OvbsJakBhr0kNcCwl6QGGPaS1ADDXpIaYNhLUgMM\ne0lqwLJhn+TZSW5JciDJPUne1i0/M8neJAe7xw2TL1eStBqpqsdfIdkIbKyq25OcDtwGXA78IvCN\nqtqZZAewoare8XivNT8/X/v37++ncjXlZLiY6tDOy2ZdgtapJLdV1fw4r7Fsz76qjlTV7d30t4ED\nwLOArcDubrXdDD4AJElr0IrG7JNsBi4CbgXOqaojMPhAAM7uuzhJUj9GvjdOkqcCHwHeXlWPJhl1\nu+3AdoBNmzatpkY1ZuGQjUMfUj9G6tkneQKDoP9AVX20W3y0G88/Ma5/bNi2VbWrquaran5ubq6P\nmiVJKzTK2TgBrgYOVNUfLXhqD7Ctm94G3Nh/eZKkPowyjPMi4OeBLya5o1v2m8BO4LokVwEPAVdM\npkRJ0riWDfuq+kdgqQH6Lf2WI0maBK+glaQGGPaS1ADDXpIaYNhLUgMMe0lqgGEvSQ0w7CWpAYa9\nJDXAsJekBhj2ktQAw16aks07bjop/uOW1ifDXpIaYNhLUgMMe2mGHNrRtBj2ktQAw16SGjDyPxyX\n1A+HbTQL9uwlqQGGvSQ1wGEcrWkOeUj9sGcvSQ1YNuyTXJPkWJK7Fyw7M8neJAe7xw2TLVOSNI5R\nevbvBy5dtGwHsK+qzgf2dfOSVsmLqzRpy4Z9VX0W+MaixVuB3d30buDynuuSJPVotWP251TVEYDu\n8ez+SpIk9W3iX9Am2Z5kf5L9x48fn/TuJElDrDbsjybZCNA9HltqxaraVVXzVTU/Nze3yt1Jksax\n2rDfA2zrprcBN/ZTjiRpEkY59fKDwD8BFyQ5nOQqYCfwsiQHgZd185KkNWrZK2ir6g1LPLWl51ok\nSRPiFbSS1ADvjaM1w4uKpMmxZy9JDTDsJakBDuNoZhy2kabHnr0kNcCwl6QGGPaS1ADDXpIaYNhL\nUgMMe2kN8T9WaVIMe0lqgGEvSQ3woipN1IkhiUM7L/s/85Kmy569JDXAsJekBjiMo94sHKI5MWyj\n1VlpWy4eLpMWs2cvSQ0w7CWpAQ7jaMUcMpiuxWcweWaTVsOevSQ1YKywT3JpkvuS3J9kR19FSZL6\ntephnCSnAH8OvAw4DHw+yZ6q+lJfxWn9cohhckZp22FDbQ6/tW2cnv0lwP1V9WBV/SfwIWBrP2VJ\nkvo0Ttg/C/jKgvnD3TJJ0hqTqlrdhskVwCuq6pe6+Z8HLqmqty5abzuwvZv9MeDu1Zc7NWcBX5t1\nESNYD3WuhxrBOvtmnf26oKpOH+cFxjn18jDw7AXz5wIPL16pqnYBuwCS7K+q+TH2ORXW2Z/1UCNY\nZ9+ss19J9o/7GuMM43weOD/JeUlOA64E9oxbkCSpf6vu2VfVY0neAnwSOAW4pqru6a0ySVJvxrqC\ntqpuBm5ewSa7xtnfFFlnf9ZDjWCdfbPOfo1d56q/oJUkrR/eLkGSGtB72Ce5Isk9Sb6XZH7Rc+/s\nbq1wX5JXLLH9eUluTXIwybXdl78T1e3nju7nUJI7lljvUJIvduuN/e34Kur87ST/tqDWVy2x3sxu\nY5HkD5Lcm+SuJDckOWOJ9WbSlsu1TZIndsfD/d1xuHlatS2o4dlJbklyoPtdetuQdV6c5FsLjoXf\nmnadXR2P+z5m4M+69rwrycUzqPGCBe10R5JHk7x90Tozac8k1yQ5luTuBcvOTLK3y8C9STYsse22\nbp2DSbYtu7Oq6vUHeC5wAfAZYH7B8ucBdwJPBM4DHgBOGbL9dcCV3fR7gV/pu8Zl6v9D4LeWeO4Q\ncNY061m0/98Gfn2ZdU7p2vY5wGldmz9vijW+HDi1m34P8J610pajtA3wq8B7u+krgWtn8D5vBC7u\npk8H/mVInS8GPjbt2lb6PgKvAj4OBHghcOuM6z0F+Crww2uhPYGfBi4G7l6w7PeBHd30jmG/Q8CZ\nwIPd44ZuesPj7av3nn1VHaiq+4Y8tRX4UFV9t6r+FbifwS0Xvi9JgJcA13eLdgOX913jUrr9vx74\n4LT2OQEzvY1FVX2qqh7rZv+ZwfUXa8UobbOVwXEHg+NwS3dcTE1VHamq27vpbwMHWL9Xp28F/qYG\n/hk4I8nGGdazBXigqr48wxq+r6o+C3xj0eKFx+BSGfgKYG9VfaOqvgnsBS59vH1Nc8x+lNsrPB14\nZEFYTPsWDD8FHK2qg0s8X8CnktzWXRk8C2/p/hy+Zok/79bSbSzexKBXN8ws2nKUtvn+Ot1x+C0G\nx+VMdMNIFwG3Dnn6x5PcmeTjSX50qoX9r+Xex7V0PMLgr7WlOnNroT0BzqmqIzD44AfOHrLOitt1\nVadeJvkH4BlDnnpXVd241GZDli0+FWiUdVZlxJrfwOP36l9UVQ8nORvYm+Te7pO5N49XJ/CXwLsZ\ntMm7GQw5vWnxSwzZttdTrkZpyyTvAh4DPrDEy0y8LYeY6TG4UkmeCnwEeHtVPbro6dsZDEX8e/fd\nzd8D50+7RpZ/H9dSe54GvAZ455Cn10p7jmrF7bqqsK+ql65is1Fur/A1Bn/mndr1qobegmE1lqs5\nyanAzwIveJzXeLh7PJbkBgbDAr0G1Khtm+SvgI8NeWqk21iMY4S23Aa8GthS3QDjkNeYeFsOMUrb\nnFjncHdMPI3//2f2xCV5AoOg/0BVfXTx8wvDv6puTvIXSc6qqqne52WE93Hix+MKvBK4vaqOLn5i\nrbRn52iSjVV1pBvyOjZkncMMvmc44VwG35MuaZrDOHuAK7uzHc5j8Kn5uYUrdMFwC/C6btE2YKm/\nFPr2UuDeqjo87MkkT0ly+olpBl9ETvWmbovGOl+7xP5nehuLJJcC7wBeU1XfWWKdWbXlKG2zh8Fx\nB4Pj8NNLfWBNSvcdwdXAgar6oyXWecaJ7xKSXMLgd/nr06ty5PdxD/AL3Vk5LwS+dWKIYgaW/Mt9\nLbTnAguPwaUy8JPAy5Ns6IZzX94tW9oEvl1+LYNPne8CR4FPLnjuXQzOhrgPeOWC5TcDz+ymn8Pg\nQ+B+4MPAE/uucYm63w+8edGyZwI3L6jrzu7nHgZDFtP+5v5vgS8Cd3UHxMbFdXbzr2JwBscD066z\ne9++AtzR/bx3cY2zbMthbQP8LoMPJ4Andcfd/d1x+JwZvM8/yeBP8rsWtOOrgDefOEaBt3RtdyeD\nL8J/YgZ1Dn0fF9UZBv/k6IHu2J2fdp1dHU9mEN5PW7Bs5u3J4MPnCPBfXW5exeA7on3Awe7xzG7d\neeB9C7Z9U3ec3g+8cbl9eQWtJDXAK2glqQGGvSQ1wLCXpAYY9pLUAMNekhpg2EtSAwx7SWqAYS9J\nDfgfS9fLKUqMYTsAAAAASUVORK5CYII=\n", | |
768 | "text/latex": [ |
|
768 | "text/latex": [ | |
769 | "$\\mathcal{N}(\\mu=0, \\sigma=1),\\ N=1000$" |
|
769 | "$\\mathcal{N}(\\mu=0, \\sigma=1),\\ N=1000$" | |
770 | ], |
|
770 | ], | |
771 | "text/plain": [ |
|
771 | "text/plain": [ | |
772 | "<__main__.Gaussian at 0x11a614e80>" |
|
772 | "<__main__.Gaussian at 0x11a614e80>" | |
773 | ] |
|
773 | ] | |
774 | }, |
|
774 | }, | |
775 | "metadata": {}, |
|
775 | "metadata": {}, | |
776 | "output_type": "display_data" |
|
776 | "output_type": "display_data" | |
777 | } |
|
777 | } | |
778 | ], |
|
778 | ], | |
779 | "source": [ |
|
779 | "source": [ | |
780 | "# that is deffinitively wrong as it shoudl show the PNG. \n", |
|
780 | "# that is deffinitively wrong as it shoudl show the PNG. \n", | |
781 | "display(Gaussian())" |
|
781 | "display(Gaussian())" | |
782 | ] |
|
782 | ] | |
783 | }, |
|
783 | }, | |
784 | { |
|
784 | { | |
785 | "cell_type": "markdown", |
|
785 | "cell_type": "markdown", | |
786 | "metadata": {}, |
|
786 | "metadata": {}, | |
787 | "source": [ |
|
787 | "source": [ | |
788 | "In the above example, the 3 mimetypes are embeded in the notebook document this allowing custom extensions and converters to display the representation(s) of their choice.\n", |
|
788 | "In the above example, the 3 mimetypes are embedded in the notebook document this allowing custom extensions and converters to display the representation(s) of their choice.\n", | |
789 | "\n", |
|
789 | "\n", | |
790 | "For example, converting this noetebook to _epub_ may decide to use the MathML representation as most ebook reader cannot run mathjax (unlike browsers). \n", |
|
790 | "For example, converting this noetebook to _epub_ may decide to use the MathML representation as most ebook reader cannot run mathjax (unlike browsers). \n", | |
791 | "\n", |
|
791 | "\n", | |
792 | "\n", |
|
792 | "\n", | |
793 | "### Implementation guidelines\n", |
|
793 | "### Implementation guidelines\n", | |
794 | "\n", |
|
794 | "\n", | |
795 | "The `_repr_mimebundle_` methods is also given two keywords parameters : `include` and `exclude`. Each can be a containers (e.g.:`list`, `set` ...) of mimetypes to return or `None`, This allows implementation to avoid computing potentially unnecessary and expensive mimetypes representations. \n", |
|
795 | "The `_repr_mimebundle_` methods is also given two keywords parameters : `include` and `exclude`. Each can be a containers (e.g.:`list`, `set` ...) of mimetypes to return or `None`, This allows implementation to avoid computing potentially unnecessary and expensive mimetypes representations. \n", | |
796 | "\n", |
|
796 | "\n", | |
797 | "When `include` is non-empty (empty `list` or None), `_repr_mimebundle_` may decide to returns only the mimetypes in include.\n", |
|
797 | "When `include` is non-empty (empty `list` or None), `_repr_mimebundle_` may decide to returns only the mimetypes in include.\n", | |
798 | "When `exclude` is non-empty, `_repr_mimebundle_` may decide to not return any mimetype in exclude. \n", |
|
798 | "When `exclude` is non-empty, `_repr_mimebundle_` may decide to not return any mimetype in exclude. \n", | |
799 | "If both `include` and `exclude` and overlap, mimetypes present in exclude may not be returned. \n", |
|
799 | "If both `include` and `exclude` and overlap, mimetypes present in exclude may not be returned. \n", | |
800 | "\n", |
|
800 | "\n", | |
801 | "If implementations decide to ignore the `include` and `exclude` logic and always returns a full mimebundles, the IPython kernel will take care of removing non-desired representations.\n", |
|
801 | "If implementations decide to ignore the `include` and `exclude` logic and always returns a full mimebundles, the IPython kernel will take care of removing non-desired representations.\n", | |
802 | "\n", |
|
802 | "\n", | |
803 | "The `_repr_mimebundle_` method should accept arbitrary keyword arguments for future compatiility.\n" |
|
803 | "The `_repr_mimebundle_` method should accept arbitrary keyword arguments for future compatiility.\n" | |
804 | ] |
|
804 | ] | |
805 | }, |
|
805 | }, | |
806 | { |
|
806 | { | |
807 | "cell_type": "code", |
|
807 | "cell_type": "code", | |
808 | "execution_count": 22, |
|
808 | "execution_count": 22, | |
809 | "metadata": {}, |
|
809 | "metadata": {}, | |
810 | "outputs": [ |
|
810 | "outputs": [ | |
811 | { |
|
811 | { | |
812 | "data": { |
|
812 | "data": { | |
813 | "text/latex": [ |
|
813 | "text/latex": [ | |
814 | "$\\mathcal{N}(\\mu=0, \\sigma=1),\\ N=1000$" |
|
814 | "$\\mathcal{N}(\\mu=0, \\sigma=1),\\ N=1000$" | |
815 | ] |
|
815 | ] | |
816 | }, |
|
816 | }, | |
817 | "metadata": {}, |
|
817 | "metadata": {}, | |
818 | "output_type": "display_data" |
|
818 | "output_type": "display_data" | |
819 | } |
|
819 | } | |
820 | ], |
|
820 | ], | |
821 | "source": [ |
|
821 | "source": [ | |
822 | "display(Gaussian(), include={'text/latex'}) # only show latex" |
|
822 | "display(Gaussian(), include={'text/latex'}) # only show latex" | |
823 | ] |
|
823 | ] | |
824 | }, |
|
824 | }, | |
825 | { |
|
825 | { | |
826 | "cell_type": "code", |
|
826 | "cell_type": "code", | |
827 | "execution_count": 23, |
|
827 | "execution_count": 23, | |
828 | "metadata": {}, |
|
828 | "metadata": {}, | |
829 | "outputs": [ |
|
829 | "outputs": [ | |
830 | { |
|
830 | { | |
831 | "data": { |
|
831 | "data": { | |
832 | "application/mathml+xml": "\n <math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n <mrow class=\"MJX-TeXAtom-ORD\">\n <mi class=\"MJX-tex-caligraphic\" mathvariant=\"script\">N</mi>\n </mrow>\n <mo stretchy=\"false\">(</mo>\n <mi>μ<!-- ΞΌ --></mi>\n <mo>=</mo>\n <mn>0.0</mn>\n <mo>,</mo>\n <mi>σ<!-- Ο --></mi>\n <mo>=</mo>\n <mn>1</mn>\n <mo stretchy=\"false\">)</mo>\n <mo>,</mo>\n <mtext> </mtext>\n <mi>N</mi>\n <mo>=</mo>\n <mn>1000</mn>\n </math>\n ", |
|
832 | "application/mathml+xml": "\n <math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n <mrow class=\"MJX-TeXAtom-ORD\">\n <mi class=\"MJX-tex-caligraphic\" mathvariant=\"script\">N</mi>\n </mrow>\n <mo stretchy=\"false\">(</mo>\n <mi>μ<!-- ΞΌ --></mi>\n <mo>=</mo>\n <mn>0.0</mn>\n <mo>,</mo>\n <mi>σ<!-- Ο --></mi>\n <mo>=</mo>\n <mn>1</mn>\n <mo stretchy=\"false\">)</mo>\n <mo>,</mo>\n <mtext> </mtext>\n <mi>N</mi>\n <mo>=</mo>\n <mn>1000</mn>\n </math>\n ", | |
833 | "text/latex": [ |
|
833 | "text/latex": [ | |
834 | "$\\mathcal{N}(\\mu=0, \\sigma=1),\\ N=1000$" |
|
834 | "$\\mathcal{N}(\\mu=0, \\sigma=1),\\ N=1000$" | |
835 | ], |
|
835 | ], | |
836 | "text/plain": [ |
|
836 | "text/plain": [ | |
837 | "<__main__.Gaussian at 0x116fe7550>" |
|
837 | "<__main__.Gaussian at 0x116fe7550>" | |
838 | ] |
|
838 | ] | |
839 | }, |
|
839 | }, | |
840 | "metadata": {}, |
|
840 | "metadata": {}, | |
841 | "output_type": "display_data" |
|
841 | "output_type": "display_data" | |
842 | } |
|
842 | } | |
843 | ], |
|
843 | ], | |
844 | "source": [ |
|
844 | "source": [ | |
845 | "display(Gaussian(), exclude={'image/png'}) # exclude png" |
|
845 | "display(Gaussian(), exclude={'image/png'}) # exclude png" | |
846 | ] |
|
846 | ] | |
847 | }, |
|
847 | }, | |
848 | { |
|
848 | { | |
849 | "cell_type": "code", |
|
849 | "cell_type": "code", | |
850 | "execution_count": 24, |
|
850 | "execution_count": 24, | |
851 | "metadata": {}, |
|
851 | "metadata": {}, | |
852 | "outputs": [ |
|
852 | "outputs": [ | |
853 | { |
|
853 | { | |
854 | "data": { |
|
854 | "data": { | |
855 | "text/plain": [ |
|
855 | "text/plain": [ | |
856 | "<__main__.Gaussian at 0x11a8a0b38>" |
|
856 | "<__main__.Gaussian at 0x11a8a0b38>" | |
857 | ] |
|
857 | ] | |
858 | }, |
|
858 | }, | |
859 | "metadata": {}, |
|
859 | "metadata": {}, | |
860 | "output_type": "display_data" |
|
860 | "output_type": "display_data" | |
861 | } |
|
861 | } | |
862 | ], |
|
862 | ], | |
863 | "source": [ |
|
863 | "source": [ | |
864 | "display(Gaussian(), include={'text/plain', 'image/png'}, exclude={'image/png'}) # keep only plain/text" |
|
864 | "display(Gaussian(), include={'text/plain', 'image/png'}, exclude={'image/png'}) # keep only plain/text" | |
865 | ] |
|
865 | ] | |
866 | }, |
|
866 | }, | |
867 | { |
|
867 | { | |
868 | "cell_type": "markdown", |
|
868 | "cell_type": "markdown", | |
869 | "metadata": {}, |
|
869 | "metadata": {}, | |
870 | "source": [ |
|
870 | "source": [ | |
871 | "## More complex display with `_ipython_display_`" |
|
871 | "## More complex display with `_ipython_display_`" | |
872 | ] |
|
872 | ] | |
873 | }, |
|
873 | }, | |
874 | { |
|
874 | { | |
875 | "cell_type": "markdown", |
|
875 | "cell_type": "markdown", | |
876 | "metadata": {}, |
|
876 | "metadata": {}, | |
877 | "source": [ |
|
877 | "source": [ | |
878 | "Rich output special methods and functions can only display one object or MIME type at a time. Sometimes this is not enough if you want to display multiple objects or MIME types at once. An example of this would be to use an HTML representation to put some HTML elements in the DOM and then use a JavaScript representation to add events to those elements.\n", |
|
878 | "Rich output special methods and functions can only display one object or MIME type at a time. Sometimes this is not enough if you want to display multiple objects or MIME types at once. An example of this would be to use an HTML representation to put some HTML elements in the DOM and then use a JavaScript representation to add events to those elements.\n", | |
879 | "\n", |
|
879 | "\n", | |
880 | "**IPython 2.0** recognizes another display method, `_ipython_display_`, which allows your objects to take complete control of displaying themselves. If this method is defined, IPython will call it, and make no effort to display the object using the above described `_repr_*_` methods for custom display functions. It's a way for you to say \"Back off, IPython, I can display this myself.\" Most importantly, your `_ipython_display_` method can make multiple calls to the top-level `display` functions to accomplish its goals.\n", |
|
880 | "**IPython 2.0** recognizes another display method, `_ipython_display_`, which allows your objects to take complete control of displaying themselves. If this method is defined, IPython will call it, and make no effort to display the object using the above described `_repr_*_` methods for custom display functions. It's a way for you to say \"Back off, IPython, I can display this myself.\" Most importantly, your `_ipython_display_` method can make multiple calls to the top-level `display` functions to accomplish its goals.\n", | |
881 | "\n", |
|
881 | "\n", | |
882 | "Here is an object that uses `display_html` and `display_javascript` to make a plot using the [Flot](http://www.flotcharts.org/) JavaScript plotting library:" |
|
882 | "Here is an object that uses `display_html` and `display_javascript` to make a plot using the [Flot](http://www.flotcharts.org/) JavaScript plotting library:" | |
883 | ] |
|
883 | ] | |
884 | }, |
|
884 | }, | |
885 | { |
|
885 | { | |
886 | "cell_type": "code", |
|
886 | "cell_type": "code", | |
887 | "execution_count": 25, |
|
887 | "execution_count": 25, | |
888 | "metadata": { |
|
888 | "metadata": { | |
889 | "collapsed": true |
|
889 | "collapsed": true | |
890 | }, |
|
890 | }, | |
891 | "outputs": [], |
|
891 | "outputs": [], | |
892 | "source": [ |
|
892 | "source": [ | |
893 | "import json\n", |
|
893 | "import json\n", | |
894 | "import uuid\n", |
|
894 | "import uuid\n", | |
895 | "from IPython.display import display_javascript, display_html, display\n", |
|
895 | "from IPython.display import display_javascript, display_html, display\n", | |
896 | "\n", |
|
896 | "\n", | |
897 | "class FlotPlot(object):\n", |
|
897 | "class FlotPlot(object):\n", | |
898 | " def __init__(self, x, y):\n", |
|
898 | " def __init__(self, x, y):\n", | |
899 | " self.x = x\n", |
|
899 | " self.x = x\n", | |
900 | " self.y = y\n", |
|
900 | " self.y = y\n", | |
901 | " self.uuid = str(uuid.uuid4())\n", |
|
901 | " self.uuid = str(uuid.uuid4())\n", | |
902 | " \n", |
|
902 | " \n", | |
903 | " def _ipython_display_(self):\n", |
|
903 | " def _ipython_display_(self):\n", | |
904 | " json_data = json.dumps(list(zip(self.x, self.y)))\n", |
|
904 | " json_data = json.dumps(list(zip(self.x, self.y)))\n", | |
905 | " display_html('<div id=\"{}\" style=\"height: 300px; width:80%;\"></div>'.format(self.uuid),\n", |
|
905 | " display_html('<div id=\"{}\" style=\"height: 300px; width:80%;\"></div>'.format(self.uuid),\n", | |
906 | " raw=True\n", |
|
906 | " raw=True\n", | |
907 | " )\n", |
|
907 | " )\n", | |
908 | " display_javascript(\"\"\"\n", |
|
908 | " display_javascript(\"\"\"\n", | |
909 | " require([\"//cdnjs.cloudflare.com/ajax/libs/flot/0.8.2/jquery.flot.min.js\"], function() {\n", |
|
909 | " require([\"//cdnjs.cloudflare.com/ajax/libs/flot/0.8.2/jquery.flot.min.js\"], function() {\n", | |
910 | " var line = JSON.parse(\"%s\");\n", |
|
910 | " var line = JSON.parse(\"%s\");\n", | |
911 | " console.log(line);\n", |
|
911 | " console.log(line);\n", | |
912 | " $.plot(\"#%s\", [line]);\n", |
|
912 | " $.plot(\"#%s\", [line]);\n", | |
913 | " });\n", |
|
913 | " });\n", | |
914 | " \"\"\" % (json_data, self.uuid), raw=True)\n" |
|
914 | " \"\"\" % (json_data, self.uuid), raw=True)\n" | |
915 | ] |
|
915 | ] | |
916 | }, |
|
916 | }, | |
917 | { |
|
917 | { | |
918 | "cell_type": "code", |
|
918 | "cell_type": "code", | |
919 | "execution_count": 26, |
|
919 | "execution_count": 26, | |
920 | "metadata": {}, |
|
920 | "metadata": {}, | |
921 | "outputs": [ |
|
921 | "outputs": [ | |
922 | { |
|
922 | { | |
923 | "data": { |
|
923 | "data": { | |
924 | "text/html": [ |
|
924 | "text/html": [ | |
925 | "<div id=\"c6929609-3cb6-4443-9574-d9f71791a987\" style=\"height: 300px; width:80%;\"></div>" |
|
925 | "<div id=\"c6929609-3cb6-4443-9574-d9f71791a987\" style=\"height: 300px; width:80%;\"></div>" | |
926 | ] |
|
926 | ] | |
927 | }, |
|
927 | }, | |
928 | "metadata": {}, |
|
928 | "metadata": {}, | |
929 | "output_type": "display_data" |
|
929 | "output_type": "display_data" | |
930 | }, |
|
930 | }, | |
931 | { |
|
931 | { | |
932 | "data": { |
|
932 | "data": { | |
933 | "application/javascript": [ |
|
933 | "application/javascript": [ | |
934 | "\n", |
|
934 | "\n", | |
935 | " require([\"//cdnjs.cloudflare.com/ajax/libs/flot/0.8.2/jquery.flot.min.js\"], function() {\n", |
|
935 | " require([\"//cdnjs.cloudflare.com/ajax/libs/flot/0.8.2/jquery.flot.min.js\"], function() {\n", | |
936 | " var line = JSON.parse(\"[[0.0, 0.0], [0.20408163265306123, 0.20266793654820095], [0.40816326530612246, 0.39692414892492234], [0.6122448979591837, 0.5747060412161791], [0.8163265306122449, 0.7286347834693503], [1.0204081632653061, 0.8523215697196184], [1.2244897959183674, 0.9406327851124867], [1.4285714285714286, 0.9899030763721239], [1.6326530612244898, 0.9980874821347183], [1.836734693877551, 0.9648463089837632], [2.0408163265306123, 0.8915592304110037], [2.2448979591836737, 0.7812680235262639], [2.4489795918367347, 0.6385503202266021], [2.6530612244897958, 0.469329612777201], [2.857142857142857, 0.28062939951435684], [3.0612244897959187, 0.0802816748428135], [3.2653061224489797, -0.12339813736217871], [3.4693877551020407, -0.3219563150726187], [3.673469387755102, -0.5071517094845144], [3.8775510204081636, -0.6712977935519321], [4.081632653061225, -0.8075816909683364], [4.285714285714286, -0.9103469443107828], [4.4897959183673475, -0.9753282860670456], [4.6938775510204085, -0.9998286683840896], [4.8979591836734695, -0.9828312039256306], [5.1020408163265305, -0.9250413717382029], [5.3061224489795915, -0.8288577363730427], [5.510204081632653, -0.6982723955653996], [5.714285714285714, -0.5387052883861563], [5.918367346938775, -0.35677924089893803], [6.122448979591837, -0.16004508604325057], [6.326530612244898, 0.04333173336868346], [6.530612244897959, 0.2449100710119793], [6.73469387755102, 0.4363234264718193], [6.938775510204081, 0.6096271964908323], [7.142857142857143, 0.7576284153927202], [7.346938775510204, 0.8741842988197335], [7.551020408163265, 0.9544571997387519], [7.755102040816327, 0.9951153947776636], [7.959183673469388, 0.9944713672636168], [8.16326530612245, 0.9525518475314604], [8.36734693877551, 0.8710967034823207], [8.571428571428571, 0.7534867274396376], [8.775510204081632, 0.6046033165061543], [8.979591836734695, 0.43062587038273736], [9.183673469387756, 0.23877531564403087], [9.387755102040817, 0.03701440148506237], [9.591836734693878, -0.1662827938487564], [9.795918367346939, -0.3626784288265488], [10.0, -0.5440211108893699]]\");\n", |
|
936 | " var line = JSON.parse(\"[[0.0, 0.0], [0.20408163265306123, 0.20266793654820095], [0.40816326530612246, 0.39692414892492234], [0.6122448979591837, 0.5747060412161791], [0.8163265306122449, 0.7286347834693503], [1.0204081632653061, 0.8523215697196184], [1.2244897959183674, 0.9406327851124867], [1.4285714285714286, 0.9899030763721239], [1.6326530612244898, 0.9980874821347183], [1.836734693877551, 0.9648463089837632], [2.0408163265306123, 0.8915592304110037], [2.2448979591836737, 0.7812680235262639], [2.4489795918367347, 0.6385503202266021], [2.6530612244897958, 0.469329612777201], [2.857142857142857, 0.28062939951435684], [3.0612244897959187, 0.0802816748428135], [3.2653061224489797, -0.12339813736217871], [3.4693877551020407, -0.3219563150726187], [3.673469387755102, -0.5071517094845144], [3.8775510204081636, -0.6712977935519321], [4.081632653061225, -0.8075816909683364], [4.285714285714286, -0.9103469443107828], [4.4897959183673475, -0.9753282860670456], [4.6938775510204085, -0.9998286683840896], [4.8979591836734695, -0.9828312039256306], [5.1020408163265305, -0.9250413717382029], [5.3061224489795915, -0.8288577363730427], [5.510204081632653, -0.6982723955653996], [5.714285714285714, -0.5387052883861563], [5.918367346938775, -0.35677924089893803], [6.122448979591837, -0.16004508604325057], [6.326530612244898, 0.04333173336868346], [6.530612244897959, 0.2449100710119793], [6.73469387755102, 0.4363234264718193], [6.938775510204081, 0.6096271964908323], [7.142857142857143, 0.7576284153927202], [7.346938775510204, 0.8741842988197335], [7.551020408163265, 0.9544571997387519], [7.755102040816327, 0.9951153947776636], [7.959183673469388, 0.9944713672636168], [8.16326530612245, 0.9525518475314604], [8.36734693877551, 0.8710967034823207], [8.571428571428571, 0.7534867274396376], [8.775510204081632, 0.6046033165061543], [8.979591836734695, 0.43062587038273736], [9.183673469387756, 0.23877531564403087], [9.387755102040817, 0.03701440148506237], [9.591836734693878, -0.1662827938487564], [9.795918367346939, -0.3626784288265488], [10.0, -0.5440211108893699]]\");\n", | |
937 | " console.log(line);\n", |
|
937 | " console.log(line);\n", | |
938 | " $.plot(\"#c6929609-3cb6-4443-9574-d9f71791a987\", [line]);\n", |
|
938 | " $.plot(\"#c6929609-3cb6-4443-9574-d9f71791a987\", [line]);\n", | |
939 | " });\n", |
|
939 | " });\n", | |
940 | " " |
|
940 | " " | |
941 | ] |
|
941 | ] | |
942 | }, |
|
942 | }, | |
943 | "metadata": {}, |
|
943 | "metadata": {}, | |
944 | "output_type": "display_data" |
|
944 | "output_type": "display_data" | |
945 | } |
|
945 | } | |
946 | ], |
|
946 | ], | |
947 | "source": [ |
|
947 | "source": [ | |
948 | "import numpy as np\n", |
|
948 | "import numpy as np\n", | |
949 | "x = np.linspace(0,10)\n", |
|
949 | "x = np.linspace(0,10)\n", | |
950 | "y = np.sin(x)\n", |
|
950 | "y = np.sin(x)\n", | |
951 | "FlotPlot(x, np.sin(x))" |
|
951 | "FlotPlot(x, np.sin(x))" | |
952 | ] |
|
952 | ] | |
953 | } |
|
953 | } | |
954 | ], |
|
954 | ], | |
955 | "metadata": { |
|
955 | "metadata": { | |
956 | "kernelspec": { |
|
956 | "kernelspec": { | |
957 | "display_name": "Python 3", |
|
957 | "display_name": "Python 3", | |
958 | "language": "python", |
|
958 | "language": "python", | |
959 | "name": "python3" |
|
959 | "name": "python3" | |
960 | }, |
|
960 | }, | |
961 | "language_info": { |
|
961 | "language_info": { | |
962 | "codemirror_mode": { |
|
962 | "codemirror_mode": { | |
963 | "name": "ipython", |
|
963 | "name": "ipython", | |
964 | "version": 3 |
|
964 | "version": 3 | |
965 | }, |
|
965 | }, | |
966 | "file_extension": ".py", |
|
966 | "file_extension": ".py", | |
967 | "mimetype": "text/x-python", |
|
967 | "mimetype": "text/x-python", | |
968 | "name": "python", |
|
968 | "name": "python", | |
969 | "nbconvert_exporter": "python", |
|
969 | "nbconvert_exporter": "python", | |
970 | "pygments_lexer": "ipython3", |
|
970 | "pygments_lexer": "ipython3", | |
971 | "version": "3.6.0" |
|
971 | "version": "3.6.0" | |
972 | } |
|
972 | } | |
973 | }, |
|
973 | }, | |
974 | "nbformat": 4, |
|
974 | "nbformat": 4, | |
975 | "nbformat_minor": 1 |
|
975 | "nbformat_minor": 1 | |
976 | } |
|
976 | } |
General Comments 0
You need to be logged in to leave comments.
Login now