test_display.py
270 lines
| 9.3 KiB
| text/x-python
|
PythonLexer
Greg Caporaso
|
r8366 | """Tests for IPython.lib.display. | ||
""" | ||||
#----------------------------------------------------------------------------- | ||||
# Copyright (c) 2012, the IPython Development Team. | ||||
# | ||||
# Distributed under the terms of the Modified BSD License. | ||||
# | ||||
# The full license is in the file COPYING.txt, distributed with this software. | ||||
#----------------------------------------------------------------------------- | ||||
#----------------------------------------------------------------------------- | ||||
# Imports | ||||
#----------------------------------------------------------------------------- | ||||
Greg Caporaso
|
r8369 | from tempfile import NamedTemporaryFile, mkdtemp | ||
Thomas Kluyver
|
r13548 | from os.path import split, join as pjoin, dirname | ||
Cristian Ciupitu
|
r24228 | import sys | ||
try: | ||||
import pathlib | ||||
except ImportError: | ||||
pass | ||||
Matan Gover
|
r24973 | from unittest import TestCase, mock | ||
import struct | ||||
import wave | ||||
from io import BytesIO | ||||
Greg Caporaso
|
r8366 | |||
# Third-party imports | ||||
import nose.tools as nt | ||||
Matthias Bussonnier
|
r25029 | |||
try: | ||||
import numpy | ||||
except ImportError: | ||||
pass | ||||
Greg Caporaso
|
r8366 | |||
# Our own imports | ||||
from IPython.lib import display | ||||
Matthias Bussonnier
|
r25029 | from IPython.testing.decorators import skipif_not_numpy | ||
Greg Caporaso
|
r8366 | #----------------------------------------------------------------------------- | ||
# Classes and functions | ||||
#----------------------------------------------------------------------------- | ||||
#-------------------------- | ||||
# FileLink tests | ||||
#-------------------------- | ||||
def test_instantiation_FileLink(): | ||||
Greg Caporaso
|
r8835 | """FileLink: Test class can be instantiated""" | ||
Greg Caporaso
|
r8366 | fl = display.FileLink('example.txt') | ||
Cristian Ciupitu
|
r24228 | # TODO: remove if when only Python >= 3.6 is supported | ||
kousik
|
r25246 | fl = display.FileLink(pathlib.PurePath('example.txt')) | ||
Greg Caporaso
|
r8366 | |||
Min ho Kim
|
r25167 | def test_warning_on_non_existent_path_FileLink(): | ||
"""FileLink: Calling _repr_html_ on non-existent files returns a warning | ||||
Greg Caporaso
|
r8835 | """ | ||
Greg Caporaso
|
r8366 | fl = display.FileLink('example.txt') | ||
nt.assert_true(fl._repr_html_().startswith('Path (<tt>example.txt</tt>)')) | ||||
Greg Caporaso
|
r8369 | def test_existing_path_FileLink(): | ||
Greg Caporaso
|
r8835 | """FileLink: Calling _repr_html_ functions as expected on existing filepath | ||
""" | ||||
Greg Caporaso
|
r8369 | tf = NamedTemporaryFile() | ||
fl = display.FileLink(tf.name) | ||||
actual = fl._repr_html_() | ||||
MinRK
|
r14894 | expected = "<a href='%s' target='_blank'>%s</a><br>" % (tf.name,tf.name) | ||
Greg Caporaso
|
r8369 | nt.assert_equal(actual,expected) | ||
Greg Caporaso
|
r8444 | def test_existing_path_FileLink_repr(): | ||
Greg Caporaso
|
r8835 | """FileLink: Calling repr() functions as expected on existing filepath | ||
""" | ||||
Greg Caporaso
|
r8444 | tf = NamedTemporaryFile() | ||
fl = display.FileLink(tf.name) | ||||
actual = repr(fl) | ||||
expected = tf.name | ||||
nt.assert_equal(actual,expected) | ||||
Greg Caporaso
|
r8836 | def test_error_on_directory_to_FileLink(): | ||
"""FileLink: Raises error when passed directory | ||||
""" | ||||
td = mkdtemp() | ||||
nt.assert_raises(ValueError,display.FileLink,td) | ||||
Greg Caporaso
|
r8366 | #-------------------------- | ||
# FileLinks tests | ||||
#-------------------------- | ||||
def test_instantiation_FileLinks(): | ||||
Greg Caporaso
|
r8835 | """FileLinks: Test class can be instantiated | ||
""" | ||||
Greg Caporaso
|
r8369 | fls = display.FileLinks('example') | ||
Greg Caporaso
|
r8366 | |||
Min ho Kim
|
r25167 | def test_warning_on_non_existent_path_FileLinks(): | ||
"""FileLinks: Calling _repr_html_ on non-existent files returns a warning | ||||
Greg Caporaso
|
r8835 | """ | ||
Greg Caporaso
|
r8366 | fls = display.FileLinks('example') | ||
nt.assert_true(fls._repr_html_().startswith('Path (<tt>example</tt>)')) | ||||
Greg Caporaso
|
r8369 | def test_existing_path_FileLinks(): | ||
Greg Caporaso
|
r8835 | """FileLinks: Calling _repr_html_ functions as expected on existing dir | ||
""" | ||||
Greg Caporaso
|
r8369 | td = mkdtemp() | ||
tf1 = NamedTemporaryFile(dir=td) | ||||
tf2 = NamedTemporaryFile(dir=td) | ||||
fl = display.FileLinks(td) | ||||
actual = fl._repr_html_() | ||||
actual = actual.split('\n') | ||||
actual.sort() | ||||
Greg Caporaso
|
r9093 | # the links should always have forward slashes, even on windows, so replace | ||
# backslashes with forward slashes here | ||||
Greg Caporaso
|
r8631 | expected = ["%s/<br>" % td, | ||
MinRK
|
r14894 | " <a href='%s' target='_blank'>%s</a><br>" %\ | ||
Greg Caporaso
|
r9093 | (tf2.name.replace("\\","/"),split(tf2.name)[1]), | ||
MinRK
|
r14894 | " <a href='%s' target='_blank'>%s</a><br>" %\ | ||
Greg Caporaso
|
r9093 | (tf1.name.replace("\\","/"),split(tf1.name)[1])] | ||
Greg Caporaso
|
r8369 | expected.sort() | ||
# We compare the sorted list of links here as that's more reliable | ||||
nt.assert_equal(actual,expected) | ||||
Greg Caporaso
|
r8632 | def test_existing_path_FileLinks_alt_formatter(): | ||
Greg Caporaso
|
r8835 | """FileLinks: Calling _repr_html_ functions as expected w/ an alt formatter | ||
Greg Caporaso
|
r8632 | """ | ||
td = mkdtemp() | ||||
tf1 = NamedTemporaryFile(dir=td) | ||||
tf2 = NamedTemporaryFile(dir=td) | ||||
Greg Caporaso
|
r8802 | def fake_formatter(dirname,fnames,included_suffixes): | ||
Greg Caporaso
|
r8801 | return ["hello","world"] | ||
Greg Caporaso
|
r8632 | fl = display.FileLinks(td,notebook_display_formatter=fake_formatter) | ||
actual = fl._repr_html_() | ||||
actual = actual.split('\n') | ||||
actual.sort() | ||||
expected = ["hello","world"] | ||||
expected.sort() | ||||
# We compare the sorted list of links here as that's more reliable | ||||
nt.assert_equal(actual,expected) | ||||
Greg Caporaso
|
r8444 | def test_existing_path_FileLinks_repr(): | ||
Greg Caporaso
|
r8835 | """FileLinks: Calling repr() functions as expected on existing directory """ | ||
Greg Caporaso
|
r8444 | td = mkdtemp() | ||
tf1 = NamedTemporaryFile(dir=td) | ||||
tf2 = NamedTemporaryFile(dir=td) | ||||
fl = display.FileLinks(td) | ||||
actual = repr(fl) | ||||
actual = actual.split('\n') | ||||
actual.sort() | ||||
Greg Caporaso
|
r8631 | expected = ['%s/' % td, ' %s' % split(tf1.name)[1],' %s' % split(tf2.name)[1]] | ||
Greg Caporaso
|
r8444 | expected.sort() | ||
# We compare the sorted list of links here as that's more reliable | ||||
nt.assert_equal(actual,expected) | ||||
Greg Caporaso
|
r8632 | |||
def test_existing_path_FileLinks_repr_alt_formatter(): | ||||
Greg Caporaso
|
r8835 | """FileLinks: Calling repr() functions as expected w/ alt formatter | ||
Greg Caporaso
|
r8632 | """ | ||
td = mkdtemp() | ||||
tf1 = NamedTemporaryFile(dir=td) | ||||
tf2 = NamedTemporaryFile(dir=td) | ||||
Greg Caporaso
|
r8802 | def fake_formatter(dirname,fnames,included_suffixes): | ||
Greg Caporaso
|
r8801 | return ["hello","world"] | ||
Greg Caporaso
|
r8632 | fl = display.FileLinks(td,terminal_display_formatter=fake_formatter) | ||
actual = repr(fl) | ||||
actual = actual.split('\n') | ||||
actual.sort() | ||||
expected = ["hello","world"] | ||||
expected.sort() | ||||
# We compare the sorted list of links here as that's more reliable | ||||
nt.assert_equal(actual,expected) | ||||
Greg Caporaso
|
r8836 | |||
def test_error_on_file_to_FileLinks(): | ||||
"""FileLinks: Raises error when passed file | ||||
""" | ||||
td = mkdtemp() | ||||
tf1 = NamedTemporaryFile(dir=td) | ||||
nt.assert_raises(ValueError,display.FileLinks,tf1.name) | ||||
Greg Caporaso
|
r8444 | |||
Doug Blank
|
r19367 | def test_recursive_FileLinks(): | ||
"""FileLinks: Does not recurse when recursive=False | ||||
""" | ||||
td = mkdtemp() | ||||
tf = NamedTemporaryFile(dir=td) | ||||
subtd = mkdtemp(dir=td) | ||||
subtf = NamedTemporaryFile(dir=subtd) | ||||
fl = display.FileLinks(td) | ||||
actual = str(fl) | ||||
actual = actual.split('\n') | ||||
nt.assert_equal(len(actual), 4, actual) | ||||
fl = display.FileLinks(td, recursive=False) | ||||
actual = str(fl) | ||||
actual = actual.split('\n') | ||||
nt.assert_equal(len(actual), 2, actual) | ||||
Thomas Kluyver
|
r13548 | def test_audio_from_file(): | ||
path = pjoin(dirname(__file__), 'test.wav') | ||||
Doug Blank
|
r19367 | display.Audio(filename=path) | ||
Thomas Kluyver
|
r24130 | |||
Matan Gover
|
r24973 | class TestAudioDataWithNumpy(TestCase): | ||
Matthias Bussonnier
|
r25029 | |||
@skipif_not_numpy | ||||
Matan Gover
|
r24973 | def test_audio_from_numpy_array(self): | ||
test_tone = get_test_tone() | ||||
audio = display.Audio(test_tone, rate=44100) | ||||
nt.assert_equal(len(read_wav(audio.data)), len(test_tone)) | ||||
Matthias Bussonnier
|
r25029 | @skipif_not_numpy | ||
Matan Gover
|
r24973 | def test_audio_from_list(self): | ||
test_tone = get_test_tone() | ||||
audio = display.Audio(list(test_tone), rate=44100) | ||||
nt.assert_equal(len(read_wav(audio.data)), len(test_tone)) | ||||
Matthias Bussonnier
|
r25029 | @skipif_not_numpy | ||
Matan Gover
|
r24973 | def test_audio_from_numpy_array_without_rate_raises(self): | ||
nt.assert_raises(ValueError, display.Audio, get_test_tone()) | ||||
Matthias Bussonnier
|
r25029 | @skipif_not_numpy | ||
Matan Gover
|
r24973 | def test_audio_data_normalization(self): | ||
expected_max_value = numpy.iinfo(numpy.int16).max | ||||
for scale in [1, 0.5, 2]: | ||||
audio = display.Audio(get_test_tone(scale), rate=44100) | ||||
actual_max_value = numpy.max(numpy.abs(read_wav(audio.data))) | ||||
nt.assert_equal(actual_max_value, expected_max_value) | ||||
Matthias Bussonnier
|
r25029 | @skipif_not_numpy | ||
Matan Gover
|
r24973 | def test_audio_data_without_normalization(self): | ||
max_int16 = numpy.iinfo(numpy.int16).max | ||||
for scale in [1, 0.5, 0.2]: | ||||
test_tone = get_test_tone(scale) | ||||
test_tone_max_abs = numpy.max(numpy.abs(test_tone)) | ||||
expected_max_value = int(max_int16 * test_tone_max_abs) | ||||
audio = display.Audio(test_tone, rate=44100, normalize=False) | ||||
actual_max_value = numpy.max(numpy.abs(read_wav(audio.data))) | ||||
nt.assert_equal(actual_max_value, expected_max_value) | ||||
def test_audio_data_without_normalization_raises_for_invalid_data(self): | ||||
nt.assert_raises( | ||||
ValueError, | ||||
lambda: display.Audio([1.001], rate=44100, normalize=False)) | ||||
nt.assert_raises( | ||||
ValueError, | ||||
lambda: display.Audio([-1.001], rate=44100, normalize=False)) | ||||
def simulate_numpy_not_installed(): | ||||
Matthias Bussonnier
|
r25032 | try: | ||
import numpy | ||||
return mock.patch('numpy.array', mock.MagicMock(side_effect=ImportError)) | ||||
except ModuleNotFoundError: | ||||
return lambda x:x | ||||
Matan Gover
|
r24973 | |||
@simulate_numpy_not_installed() | ||||
class TestAudioDataWithoutNumpy(TestAudioDataWithNumpy): | ||||
# All tests from `TestAudioDataWithNumpy` are inherited. | ||||
Matthias Bussonnier
|
r25029 | @skipif_not_numpy | ||
Matan Gover
|
r24973 | def test_audio_raises_for_nested_list(self): | ||
Matan Gover
|
r24972 | stereo_signal = [list(get_test_tone())] * 2 | ||
Matan Gover
|
r24973 | nt.assert_raises( | ||
TypeError, | ||||
lambda: display.Audio(stereo_signal, rate=44100)) | ||||
Matthias Bussonnier
|
r25032 | @skipif_not_numpy | ||
Matan Gover
|
r24973 | def get_test_tone(scale=1): | ||
return numpy.sin(2 * numpy.pi * 440 * numpy.linspace(0, 1, 44100)) * scale | ||||
def read_wav(data): | ||||
with wave.open(BytesIO(data)) as wave_file: | ||||
wave_data = wave_file.readframes(wave_file.getnframes()) | ||||
num_samples = wave_file.getnframes() * wave_file.getnchannels() | ||||
return struct.unpack('<%sh' % num_samples, wave_data) | ||||
Matan Gover
|
r24971 | |||
Thomas Kluyver
|
r24130 | def test_code_from_file(): | ||
c = display.Code(filename=__file__) | ||||
assert c._repr_html_().startswith('<style>') | ||||