##// END OF EJS Templates
Merge branch 'master' into pr/11354
Tony Fast -
r24639:0e3f99cc merge
parent child Browse files
Show More
@@ -0,0 +1,1 b''
1 ``IPython.display.Video`` now supports ``width`` and ``height`` arguments, allowing a custom width and height to be set instead of using the video's width and height No newline at end of file
@@ -238,16 +238,22 b' def display(*objs, include=None, exclude=None, metadata=None, transient=None, di'
238 want to use. Here is a list of the names of the special methods and the
238 want to use. Here is a list of the names of the special methods and the
239 values they must return:
239 values they must return:
240
240
241 - `_repr_html_`: return raw HTML as a string
241 - `_repr_html_`: return raw HTML as a string, or a tuple (see below).
242 - `_repr_json_`: return a JSONable dict
242 - `_repr_json_`: return a JSONable dict, or a tuple (see below).
243 - `_repr_jpeg_`: return raw JPEG data
243 - `_repr_jpeg_`: return raw JPEG data, or a tuple (see below).
244 - `_repr_png_`: return raw PNG data
244 - `_repr_png_`: return raw PNG data, or a tuple (see below).
245 - `_repr_svg_`: return raw SVG data as a string
245 - `_repr_svg_`: return raw SVG data as a string, or a tuple (see below).
246 - `_repr_latex_`: return LaTeX commands in a string surrounded by "$".
246 - `_repr_latex_`: return LaTeX commands in a string surrounded by "$",
247 or a tuple (see below).
247 - `_repr_mimebundle_`: return a full mimebundle containing the mapping
248 - `_repr_mimebundle_`: return a full mimebundle containing the mapping
248 from all mimetypes to data.
249 from all mimetypes to data.
249 Use this for any mime-type not listed above.
250 Use this for any mime-type not listed above.
250
251
252 The above functions may also return the object's metadata alonside the
253 data. If the metadata is available, the functions will return a tuple
254 containing the data and metadata, in that order. If there is no metadata
255 available, then the functions will return the data only.
256
251 When you are directly writing your own classes, you can adapt them for
257 When you are directly writing your own classes, you can adapt them for
252 display in IPython by following the above approach. But in practice, you
258 display in IPython by following the above approach. But in practice, you
253 often need to work with existing classes that you can't easily modify.
259 often need to work with existing classes that you can't easily modify.
@@ -666,6 +672,11 b' class Pretty(TextDisplayObject):'
666
672
667 class HTML(TextDisplayObject):
673 class HTML(TextDisplayObject):
668
674
675 def __init__(self, data=None, url=None, filename=None, metadata=None):
676 if data and "<iframe " in data and "</iframe>" in data:
677 warnings.warn("Consider using IPython.display.IFrame instead")
678 super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata)
679
669 def _repr_html_(self):
680 def _repr_html_(self):
670 return self._data_and_metadata()
681 return self._data_and_metadata()
671
682
@@ -1256,7 +1267,8 b' class Image(DisplayObject):'
1256
1267
1257 class Video(DisplayObject):
1268 class Video(DisplayObject):
1258
1269
1259 def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=None):
1270 def __init__(self, data=None, url=None, filename=None, embed=False,
1271 mimetype=None, width=None, height=None):
1260 """Create a video object given raw data or an URL.
1272 """Create a video object given raw data or an URL.
1261
1273
1262 When this object is returned by an input cell or passed to the
1274 When this object is returned by an input cell or passed to the
@@ -1288,6 +1300,12 b' class Video(DisplayObject):'
1288 mimetype: unicode
1300 mimetype: unicode
1289 Specify the mimetype for embedded videos.
1301 Specify the mimetype for embedded videos.
1290 Default will be guessed from file extension, if available.
1302 Default will be guessed from file extension, if available.
1303 width : int
1304 Width in pixels to which to constrain the video in HTML.
1305 If not supplied, defaults to the width of the video.
1306 height : int
1307 Height in pixels to which to constrain the video in html.
1308 If not supplied, defaults to the height of the video.
1291
1309
1292 Examples
1310 Examples
1293 --------
1311 --------
@@ -1314,16 +1332,24 b' class Video(DisplayObject):'
1314
1332
1315 self.mimetype = mimetype
1333 self.mimetype = mimetype
1316 self.embed = embed
1334 self.embed = embed
1335 self.width = width
1336 self.height = height
1317 super(Video, self).__init__(data=data, url=url, filename=filename)
1337 super(Video, self).__init__(data=data, url=url, filename=filename)
1318
1338
1319 def _repr_html_(self):
1339 def _repr_html_(self):
1340 width = height = ''
1341 if self.width:
1342 width = ' width="%d"' % self.width
1343 if self.height:
1344 height = ' height="%d"' % self.height
1345
1320 # External URLs and potentially local files are not embedded into the
1346 # External URLs and potentially local files are not embedded into the
1321 # notebook output.
1347 # notebook output.
1322 if not self.embed:
1348 if not self.embed:
1323 url = self.url if self.url is not None else self.filename
1349 url = self.url if self.url is not None else self.filename
1324 output = """<video src="{0}" controls>
1350 output = """<video src="{0}" controls {1} {2}>
1325 Your browser does not support the <code>video</code> element.
1351 Your browser does not support the <code>video</code> element.
1326 </video>""".format(url)
1352 </video>""".format(url, width, height)
1327 return output
1353 return output
1328
1354
1329 # Embedded videos are base64-encoded.
1355 # Embedded videos are base64-encoded.
@@ -1342,10 +1368,10 b' class Video(DisplayObject):'
1342 else:
1368 else:
1343 b64_video = b2a_base64(video).decode('ascii').rstrip()
1369 b64_video = b2a_base64(video).decode('ascii').rstrip()
1344
1370
1345 output = """<video controls>
1371 output = """<video controls {0} {1}>
1346 <source src="data:{0};base64,{1}" type="{0}">
1372 <source src="data:{2};base64,{3}" type="{2}">
1347 Your browser does not support the video tag.
1373 Your browser does not support the video tag.
1348 </video>""".format(mimetype, b64_video)
1374 </video>""".format(width, height, mimetype, b64_video)
1349 return output
1375 return output
1350
1376
1351 def reload(self):
1377 def reload(self):
@@ -20,10 +20,12 b" _indent_re = re.compile(r'^[ \\t]+')"
20
20
21 def leading_indent(lines):
21 def leading_indent(lines):
22 """Remove leading indentation.
22 """Remove leading indentation.
23
23
24 If the first line starts with a spaces or tabs, the same whitespace will be
24 If the first line starts with a spaces or tabs, the same whitespace will be
25 removed from each following line in the cell.
25 removed from each following line in the cell.
26 """
26 """
27 if not lines:
28 return lines
27 m = _indent_re.match(lines[0])
29 m = _indent_re.match(lines[0])
28 if not m:
30 if not m:
29 return lines
31 return lines
@@ -34,7 +36,7 b' def leading_indent(lines):'
34
36
35 class PromptStripper:
37 class PromptStripper:
36 """Remove matching input prompts from a block of input.
38 """Remove matching input prompts from a block of input.
37
39
38 Parameters
40 Parameters
39 ----------
41 ----------
40 prompt_re : regular expression
42 prompt_re : regular expression
@@ -45,7 +47,7 b' class PromptStripper:'
45 If no initial expression is given, prompt_re will be used everywhere.
47 If no initial expression is given, prompt_re will be used everywhere.
46 Used mainly for plain Python prompts (``>>>``), where the continuation prompt
48 Used mainly for plain Python prompts (``>>>``), where the continuation prompt
47 ``...`` is a valid Python expression in Python 3, so shouldn't be stripped.
49 ``...`` is a valid Python expression in Python 3, so shouldn't be stripped.
48
50
49 If initial_re and prompt_re differ,
51 If initial_re and prompt_re differ,
50 only initial_re will be tested against the first line.
52 only initial_re will be tested against the first line.
51 If any prompt is found on the first two lines,
53 If any prompt is found on the first two lines,
@@ -59,6 +61,8 b' class PromptStripper:'
59 return [self.prompt_re.sub('', l, count=1) for l in lines]
61 return [self.prompt_re.sub('', l, count=1) for l in lines]
60
62
61 def __call__(self, lines):
63 def __call__(self, lines):
64 if not lines:
65 return lines
62 if self.initial_re.match(lines[0]) or \
66 if self.initial_re.match(lines[0]) or \
63 (len(lines) > 1 and self.prompt_re.match(lines[1])):
67 (len(lines) > 1 and self.prompt_re.match(lines[1])):
64 return self._strip(lines)
68 return self._strip(lines)
@@ -72,7 +76,7 b' classic_prompt = PromptStripper('
72 ipython_prompt = PromptStripper(re.compile(r'^(In \[\d+\]: |\s*\.{3,}: ?)'))
76 ipython_prompt = PromptStripper(re.compile(r'^(In \[\d+\]: |\s*\.{3,}: ?)'))
73
77
74 def cell_magic(lines):
78 def cell_magic(lines):
75 if not lines[0].startswith('%%'):
79 if not lines or not lines[0].startswith('%%'):
76 return lines
80 return lines
77 if re.match('%%\w+\?', lines[0]):
81 if re.match('%%\w+\?', lines[0]):
78 # This case will be handled by help_end
82 # This case will be handled by help_end
@@ -92,7 +96,7 b' def _find_assign_op(token_line):'
92 for i, ti in enumerate(token_line):
96 for i, ti in enumerate(token_line):
93 s = ti.string
97 s = ti.string
94 if s == '=' and paren_level == 0:
98 if s == '=' and paren_level == 0:
95 return i
99 return i
96 if s in '([{':
100 if s in '([{':
97 paren_level += 1
101 paren_level += 1
98 elif s in ')]}':
102 elif s in ')]}':
@@ -112,7 +116,7 b' def find_end_of_continued_line(lines, start_line: int):'
112 return end_line
116 return end_line
113
117
114 def assemble_continued_line(lines, start: Tuple[int, int], end_line: int):
118 def assemble_continued_line(lines, start: Tuple[int, int], end_line: int):
115 """Assemble a single line from multiple continued line pieces
119 """Assemble a single line from multiple continued line pieces
116
120
117 Continued lines are lines ending in ``\``, and the line following the last
121 Continued lines are lines ending in ``\``, and the line following the last
118 ``\`` in the block.
122 ``\`` in the block.
@@ -202,7 +206,7 b' class MagicAssign(TokenTransformBase):'
202 and (line[assign_ix+1].string == '%') \
206 and (line[assign_ix+1].string == '%') \
203 and (line[assign_ix+2].type == tokenize.NAME):
207 and (line[assign_ix+2].type == tokenize.NAME):
204 return cls(line[assign_ix+1].start)
208 return cls(line[assign_ix+1].start)
205
209
206 def transform(self, lines: List[str]):
210 def transform(self, lines: List[str]):
207 """Transform a magic assignment found by the ``find()`` classmethod.
211 """Transform a magic assignment found by the ``find()`` classmethod.
208 """
212 """
@@ -212,12 +216,12 b' class MagicAssign(TokenTransformBase):'
212 rhs = assemble_continued_line(lines, (start_line, start_col), end_line)
216 rhs = assemble_continued_line(lines, (start_line, start_col), end_line)
213 assert rhs.startswith('%'), rhs
217 assert rhs.startswith('%'), rhs
214 magic_name, _, args = rhs[1:].partition(' ')
218 magic_name, _, args = rhs[1:].partition(' ')
215
219
216 lines_before = lines[:start_line]
220 lines_before = lines[:start_line]
217 call = "get_ipython().run_line_magic({!r}, {!r})".format(magic_name, args)
221 call = "get_ipython().run_line_magic({!r}, {!r})".format(magic_name, args)
218 new_line = lhs + call + '\n'
222 new_line = lhs + call + '\n'
219 lines_after = lines[end_line+1:]
223 lines_after = lines[end_line+1:]
220
224
221 return lines_before + [new_line] + lines_after
225 return lines_before + [new_line] + lines_after
222
226
223
227
@@ -464,7 +468,7 b' def make_tokens_by_line(lines):'
464 pass
468 pass
465 if not tokens_by_line[-1]:
469 if not tokens_by_line[-1]:
466 tokens_by_line.pop()
470 tokens_by_line.pop()
467
471
468 return tokens_by_line
472 return tokens_by_line
469
473
470 def show_linewise_tokens(s: str):
474 def show_linewise_tokens(s: str):
@@ -501,12 +505,12 b' class TransformerManager:'
501 EscapedCommand,
505 EscapedCommand,
502 HelpEnd,
506 HelpEnd,
503 ]
507 ]
504
508
505 def do_one_token_transform(self, lines):
509 def do_one_token_transform(self, lines):
506 """Find and run the transform earliest in the code.
510 """Find and run the transform earliest in the code.
507
511
508 Returns (changed, lines).
512 Returns (changed, lines).
509
513
510 This method is called repeatedly until changed is False, indicating
514 This method is called repeatedly until changed is False, indicating
511 that all available transformations are complete.
515 that all available transformations are complete.
512
516
@@ -195,6 +195,14 b' def test_displayobject_repr():'
195 j._show_mem_addr = False
195 j._show_mem_addr = False
196 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
196 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
197
197
198 @mock.patch('warnings.warn')
199 def test_encourage_iframe_over_html(m_warn):
200 display.HTML('<br />')
201 m_warn.assert_not_called()
202
203 display.HTML('<iframe src="http://a.com"></iframe>')
204 m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
205
198 def test_progress():
206 def test_progress():
199 p = display.ProgressBar(10)
207 p = display.ProgressBar(10)
200 nt.assert_in('0/10',repr(p))
208 nt.assert_in('0/10',repr(p))
@@ -103,6 +103,12 b' b) = zip?'
103 [r"get_ipython().set_next_input('(a,\nb) = zip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
103 [r"get_ipython().set_next_input('(a,\nb) = zip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
104 )
104 )
105
105
106 def null_cleanup_transformer(lines):
107 """
108 A cleanup transform that returns an empty list.
109 """
110 return []
111
106 def check_make_token_by_line_never_ends_empty():
112 def check_make_token_by_line_never_ends_empty():
107 """
113 """
108 Check that not sequence of single or double characters ends up leading to en empty list of tokens
114 Check that not sequence of single or double characters ends up leading to en empty list of tokens
@@ -226,3 +232,7 b' def test_check_complete():'
226 for k in short:
232 for k in short:
227 cc(c+k)
233 cc(c+k)
228
234
235 def test_null_cleanup_transformer():
236 manager = ipt2.TransformerManager()
237 manager.cleanup_transforms.insert(0, null_cleanup_transformer)
238 nt.assert_is(manager.transform_cell(""), "")
@@ -65,6 +65,21 b' There are also two more powerful display methods:'
65 Displays the object as a side effect; the return value is ignored. If this
65 Displays the object as a side effect; the return value is ignored. If this
66 is defined, all other display methods are ignored.
66 is defined, all other display methods are ignored.
67
67
68 To customize how the REPL pretty-prints your object, add a `_repr_pretty_`
69 method to the class. The method should accept a pretty printer, and a boolean
70 that indicates whether the printer detected a cycle. The method should act on
71 the printer to produce your customized pretty output. Here is an example::
72
73 class MyObject(object):
74
75 def _repr_pretty_(self, p, cycle):
76 if cycle:
77 p.text('MyObject(...)')
78 else:
79 p.text('MyObject[...]')
80
81 For details, see :py:mod:`IPython.lib.pretty`.
82
68 Formatters for third-party types
83 Formatters for third-party types
69 --------------------------------
84 --------------------------------
70
85
General Comments 0
You need to be logged in to leave comments. Login now