# This Python file uses the following encoding: utf-8 # Licensed under a 3-clause BSD style license - see LICENSE.rst import pytest import numpy as np from io import StringIO from astropy import table from astropy.io import ascii from astropy.table import Table, QTable from astropy.table.table_helpers import simple_table from astropy import units as u from astropy.utils import console BIG_WIDE_ARR = np.arange(2000, dtype=np.float64).reshape(100, 20) SMALL_ARR = np.arange(18, dtype=np.int64).reshape(6, 3) @pytest.mark.usefixtures('table_type') class TestMultiD(): def test_multidim(self, table_type): """Test printing with multidimensional column""" arr = [np.array([[1, 2], [10, 20]], dtype=np.int64), np.array([[3, 4], [30, 40]], dtype=np.int64), np.array([[5, 6], [50, 60]], dtype=np.int64)] t = table_type(arr) lines = t.pformat() assert lines == ['col0 [2] col1 [2] col2 [2]', '-------- -------- --------', ' 1 .. 2 3 .. 4 5 .. 6', '10 .. 20 30 .. 40 50 .. 60'] lines = t.pformat(html=True) assert lines == [ f'', '', '', '', '
col0 [2]col1 [2]col2 [2]
1 .. 23 .. 45 .. 6
10 .. 2030 .. 4050 .. 60
'] nbclass = table.conf.default_notebook_table_class masked = 'masked=True ' if t.masked else '' assert t._repr_html_().splitlines() == [ f'
{table_type.__name__} {masked}length=2', f'', '', '', '', '', '
col0 [2]col1 [2]col2 [2]
int64int64int64
1 .. 23 .. 45 .. 6
10 .. 2030 .. 4050 .. 60
'] t = table_type([arr]) lines = t.pformat() assert lines == ['col0 [2,2]', '----------', ' 1 .. 20', ' 3 .. 40', ' 5 .. 60'] def test_fake_multidim(self, table_type): """Test printing with 'fake' multidimensional column""" arr = [np.array([[(1,)], [(10,)]], dtype=np.int64), np.array([[(3,)], [(30,)]], dtype=np.int64), np.array([[(5,)], [(50,)]], dtype=np.int64)] t = table_type(arr) lines = t.pformat() assert lines == ['col0 [1,1] col1 [1,1] col2 [1,1]', '---------- ---------- ----------', ' 1 3 5', ' 10 30 50'] lines = t.pformat(html=True) assert lines == [ f'', '', '', '', '
col0 [1,1]col1 [1,1]col2 [1,1]
135
103050
'] nbclass = table.conf.default_notebook_table_class masked = 'masked=True ' if t.masked else '' assert t._repr_html_().splitlines() == [ f'
{table_type.__name__} {masked}length=2', f'', '', '', '', '', '
col0 [1,1]col1 [1,1]col2 [1,1]
int64int64int64
135
103050
'] t = table_type([arr]) lines = t.pformat() assert lines == ['col0 [2,1,1]', '------------', ' 1 .. 10', ' 3 .. 30', ' 5 .. 50'] def test_html_escaping(): t = table.Table([('', 2, 3)]) nbclass = table.conf.default_notebook_table_class assert t._repr_html_().splitlines() == [ '
Table length=3', f'', '', '', '', '', '', '
col0
str33
<script>alert("gotcha");</script>
2
3
'] @pytest.mark.usefixtures('table_type') class TestPprint(): def _setup(self, table_type): self.tb = table_type(BIG_WIDE_ARR) self.tb['col0'].format = 'e' self.tb['col1'].format = '.6f' self.tb['col0'].unit = 'km**2' self.tb['col19'].unit = 'kg s m**-2' self.ts = table_type(SMALL_ARR) def test_empty_table(self, table_type): t = table_type() lines = t.pformat() assert lines == [''] c = repr(t) masked = 'masked=True ' if t.masked else '' assert c.splitlines() == [f'<{table_type.__name__} {masked}length=0>', ''] def test_format0(self, table_type): """Try getting screen size but fail to defaults because testing doesn't have access to screen (fcntl.ioctl fails). """ self._setup(table_type) arr = np.arange(4000, dtype=np.float64).reshape(100, 40) lines = table_type(arr).pformat() nlines, width = console.terminal_size() assert len(lines) == nlines for line in lines[:-1]: # skip last "Length = .. rows" line assert width - 10 < len(line) <= width def test_format1(self, table_type): """Basic test of formatting, unit header row included""" self._setup(table_type) lines = self.tb.pformat(max_lines=8, max_width=40) assert lines == [' col0 col1 ... col19 ', ' km2 ... kg s / m2', '------------ ----------- ... ---------', '0.000000e+00 1.000000 ... 19.0', ' ... ... ... ...', '1.960000e+03 1961.000000 ... 1979.0', '1.980000e+03 1981.000000 ... 1999.0', 'Length = 100 rows'] def test_format2(self, table_type): """Basic test of formatting, unit header row excluded""" self._setup(table_type) lines = self.tb.pformat(max_lines=8, max_width=40, show_unit=False) assert lines == [' col0 col1 ... col19 ', '------------ ----------- ... ------', '0.000000e+00 1.000000 ... 19.0', '2.000000e+01 21.000000 ... 39.0', ' ... ... ... ...', '1.960000e+03 1961.000000 ... 1979.0', '1.980000e+03 1981.000000 ... 1999.0', 'Length = 100 rows'] def test_format3(self, table_type): """Include the unit header row""" self._setup(table_type) lines = self.tb.pformat(max_lines=8, max_width=40, show_unit=True) assert lines == [' col0 col1 ... col19 ', ' km2 ... kg s / m2', '------------ ----------- ... ---------', '0.000000e+00 1.000000 ... 19.0', ' ... ... ... ...', '1.960000e+03 1961.000000 ... 1979.0', '1.980000e+03 1981.000000 ... 1999.0', 'Length = 100 rows'] def test_format4(self, table_type): """Do not include the name header row""" self._setup(table_type) lines = self.tb.pformat(max_lines=8, max_width=40, show_name=False) assert lines == [' km2 ... kg s / m2', '------------ ----------- ... ---------', '0.000000e+00 1.000000 ... 19.0', '2.000000e+01 21.000000 ... 39.0', ' ... ... ... ...', '1.960000e+03 1961.000000 ... 1979.0', '1.980000e+03 1981.000000 ... 1999.0', 'Length = 100 rows'] def test_noclip(self, table_type): """Basic table print""" self._setup(table_type) lines = self.ts.pformat(max_lines=-1, max_width=-1) assert lines == ['col0 col1 col2', '---- ---- ----', ' 0 1 2', ' 3 4 5', ' 6 7 8', ' 9 10 11', ' 12 13 14', ' 15 16 17'] def test_clip1(self, table_type): """max lines below hard limit of 8 """ self._setup(table_type) lines = self.ts.pformat(max_lines=3, max_width=-1) assert lines == ['col0 col1 col2', '---- ---- ----', ' 0 1 2', ' 3 4 5', ' 6 7 8', ' 9 10 11', ' 12 13 14', ' 15 16 17'] def test_clip2(self, table_type): """max lines below hard limit of 8 and output longer than 8 """ self._setup(table_type) lines = self.ts.pformat(max_lines=3, max_width=-1, show_unit=True, show_dtype=True) assert lines == [' col0 col1 col2', ' ', 'int64 int64 int64', '----- ----- -----', ' 0 1 2', ' ... ... ...', ' 15 16 17', 'Length = 6 rows'] def test_clip3(self, table_type): """Max lines below hard limit of 8 and max width below hard limit of 10 """ self._setup(table_type) lines = self.ts.pformat(max_lines=3, max_width=1, show_unit=True) assert lines == ['col0 ...', ' ...', '---- ...', ' 0 ...', ' ... ...', ' 12 ...', ' 15 ...', 'Length = 6 rows'] def test_clip4(self, table_type): """Test a range of max_lines""" self._setup(table_type) for max_lines in (0, 1, 4, 5, 6, 7, 8, 100, 101, 102, 103, 104, 130): lines = self.tb.pformat(max_lines=max_lines, show_unit=False) assert len(lines) == max(8, min(102, max_lines)) def test_pformat_all(self, table_type): """Test that all rows are printed by default""" self._setup(table_type) lines = self.tb.pformat_all() # +3 accounts for the three header lines in this table assert len(lines) == BIG_WIDE_ARR.shape[0] + 3 @pytest.fixture def test_pprint_all(self, table_type, capsys): """Test that all rows are printed by default""" self._setup(table_type) self.tb.pprint_all() (out, err) = capsys.readouterr() # +3 accounts for the three header lines in this table assert len(out) == BIG_WIDE_ARR.shape[0] + 3 @pytest.mark.usefixtures('table_type') class TestFormat(): def test_column_format(self, table_type): t = table_type([[1, 2], [3, 4]], names=('a', 'b')) # default (format=None) assert str(t['a']) == ' a \n---\n 1\n 2' # just a plain format string t['a'].format = '5.2f' assert str(t['a']) == ' a \n-----\n 1.00\n 2.00' # Old-style that is almost new-style t['a'].format = '{ %4.2f }' assert str(t['a']) == ' a \n--------\n{ 1.00 }\n{ 2.00 }' # New-style that is almost old-style t['a'].format = '%{0:}' assert str(t['a']) == ' a \n---\n %1\n %2' # New-style with extra spaces t['a'].format = ' {0:05d} ' assert str(t['a']) == ' a \n-------\n 00001 \n 00002 ' # New-style has precedence t['a'].format = '%4.2f {0:}' assert str(t['a']) == ' a \n-------\n%4.2f 1\n%4.2f 2' # Invalid format spec with pytest.raises(ValueError): t['a'].format = 'fail' assert t['a'].format == '%4.2f {0:}' # format did not change def test_column_format_with_threshold(self, table_type): from astropy import conf with conf.set_temp('max_lines', 8): t = table_type([np.arange(20)], names=['a']) t['a'].format = '%{0:}' assert str(t['a']).splitlines() == [' a ', '---', ' %0', ' %1', '...', '%18', '%19', 'Length = 20 rows'] t['a'].format = '{ %4.2f }' assert str(t['a']).splitlines() == [' a ', '---------', ' { 0.00 }', ' { 1.00 }', ' ...', '{ 18.00 }', '{ 19.00 }', 'Length = 20 rows'] def test_column_format_func(self, table_type): # run most of functions twice # 1) astropy.table.pprint._format_funcs gets populated # 2) astropy.table.pprint._format_funcs gets used t = table_type([[1., 2.], [3, 4]], names=('a', 'b')) # mathematical function t['a'].format = lambda x: str(x * 3.) assert str(t['a']) == ' a \n---\n3.0\n6.0' assert str(t['a']) == ' a \n---\n3.0\n6.0' def test_column_format_callable(self, table_type): # run most of functions twice # 1) astropy.table.pprint._format_funcs gets populated # 2) astropy.table.pprint._format_funcs gets used t = table_type([[1., 2.], [3, 4]], names=('a', 'b')) # mathematical function class format: def __call__(self, x): return str(x * 3.) t['a'].format = format() assert str(t['a']) == ' a \n---\n3.0\n6.0' assert str(t['a']) == ' a \n---\n3.0\n6.0' def test_column_format_func_wrong_number_args(self, table_type): t = table_type([[1., 2.], [3, 4]], names=('a', 'b')) # function that expects wrong number of arguments def func(a, b): pass with pytest.raises(ValueError): t['a'].format = func def test_column_format_func_multiD(self, table_type): arr = [np.array([[1, 2], [10, 20]])] t = table_type(arr, names=['a']) # mathematical function t['a'].format = lambda x: str(x * 3.) outstr = ' a [2] \n------------\n 3.0 .. 6.0\n30.0 .. 60.0' assert str(t['a']) == outstr assert str(t['a']) == outstr def test_column_format_func_not_str(self, table_type): t = table_type([[1., 2.], [3, 4]], names=('a', 'b')) # mathematical function with pytest.raises(ValueError): t['a'].format = lambda x: x * 3 def test_column_alignment(self, table_type): t = table_type([[1], [2], [3], [4]], names=('long title a', 'long title b', 'long title c', 'long title d')) t['long title a'].format = '<' t['long title b'].format = '^' t['long title c'].format = '>' t['long title d'].format = '0=' assert str(t['long title a']) == 'long title a\n------------\n1 ' assert str(t['long title b']) == 'long title b\n------------\n 2 ' assert str(t['long title c']) == 'long title c\n------------\n 3' assert str(t['long title d']) == 'long title d\n------------\n000000000004' class TestFormatWithMaskedElements(): def test_column_format(self): t = Table([[1, 2, 3], [3, 4, 5]], names=('a', 'b'), masked=True) t['a'].mask = [True, False, True] # default (format=None) assert str(t['a']) == ' a \n---\n --\n 2\n --' # just a plain format string t['a'].format = '5.2f' assert str(t['a']) == ' a \n-----\n --\n 2.00\n --' # Old-style that is almost new-style t['a'].format = '{ %4.2f }' assert str(t['a']) == ' a \n--------\n --\n{ 2.00 }\n --' # New-style that is almost old-style t['a'].format = '%{0:}' assert str(t['a']) == ' a \n---\n --\n %2\n --' # New-style with extra spaces t['a'].format = ' {0:05d} ' assert str(t['a']) == ' a \n-------\n --\n 00002 \n --' # New-style has precedence t['a'].format = '%4.2f {0:}' assert str(t['a']) == ' a \n-------\n --\n%4.2f 2\n --' def test_column_format_with_threshold_masked_table(self): from astropy import conf with conf.set_temp('max_lines', 8): t = Table([np.arange(20)], names=['a'], masked=True) t['a'].format = '%{0:}' t['a'].mask[0] = True t['a'].mask[-1] = True assert str(t['a']).splitlines() == [' a ', '---', ' --', ' %1', '...', '%18', ' --', 'Length = 20 rows'] t['a'].format = '{ %4.2f }' assert str(t['a']).splitlines() == [' a ', '---------', ' --', ' { 1.00 }', ' ...', '{ 18.00 }', ' --', 'Length = 20 rows'] def test_column_format_func(self): # run most of functions twice # 1) astropy.table.pprint._format_funcs gets populated # 2) astropy.table.pprint._format_funcs gets used t = Table([[1., 2., 3.], [3, 4, 5]], names=('a', 'b'), masked=True) t['a'].mask = [True, False, True] # mathematical function t['a'].format = lambda x: str(x * 3.) assert str(t['a']) == ' a \n---\n --\n6.0\n --' assert str(t['a']) == ' a \n---\n --\n6.0\n --' def test_column_format_func_with_special_masked(self): # run most of functions twice # 1) astropy.table.pprint._format_funcs gets populated # 2) astropy.table.pprint._format_funcs gets used t = Table([[1., 2., 3.], [3, 4, 5]], names=('a', 'b'), masked=True) t['a'].mask = [True, False, True] # mathematical function def format_func(x): if x is np.ma.masked: return '!!' else: return str(x * 3.) t['a'].format = format_func assert str(t['a']) == ' a \n---\n !!\n6.0\n !!' assert str(t['a']) == ' a \n---\n !!\n6.0\n !!' def test_column_format_callable(self): # run most of functions twice # 1) astropy.table.pprint._format_funcs gets populated # 2) astropy.table.pprint._format_funcs gets used t = Table([[1., 2., 3.], [3, 4, 5]], names=('a', 'b'), masked=True) t['a'].mask = [True, False, True] # mathematical function class format: def __call__(self, x): return str(x * 3.) t['a'].format = format() assert str(t['a']) == ' a \n---\n --\n6.0\n --' assert str(t['a']) == ' a \n---\n --\n6.0\n --' def test_column_format_func_wrong_number_args(self): t = Table([[1., 2.], [3, 4]], names=('a', 'b'), masked=True) t['a'].mask = [True, False] # function that expects wrong number of arguments def func(a, b): pass with pytest.raises(ValueError): t['a'].format = func # but if all are masked, it never gets called t['a'].mask = [True, True] assert str(t['a']) == ' a \n---\n --\n --' def test_column_format_func_multiD(self): arr = [np.array([[1, 2], [10, 20]])] t = Table(arr, names=['a'], masked=True) t['a'].mask[0, 1] = True t['a'].mask[1, 1] = True # mathematical function t['a'].format = lambda x: str(x * 3.) outstr = ' a [2] \n----------\n 3.0 .. --\n30.0 .. --' assert str(t['a']) == outstr assert str(t['a']) == outstr def test_pprint_npfloat32(): """ Test for #148, that np.float32 cannot by itself be formatted as float, but has to be converted to a python float. """ dat = np.array([1., 2.], dtype=np.float32) t = Table([dat], names=['a']) t['a'].format = '5.2f' assert str(t['a']) == ' a \n-----\n 1.00\n 2.00' def test_pprint_py3_bytes(): """ Test for #1346 and #4944. Make sure a bytestring (dtype=S) in Python 3 is printed correctly (without the "b" prefix like b'string'). """ val = bytes('val', encoding='utf-8') blah = 'bläh'.encode('utf-8') dat = np.array([val, blah], dtype=[('col', 'S10')]) t = table.Table(dat) assert t['col'].pformat() == ['col ', '----', ' val', 'bläh'] def test_pprint_nameless_col(): """Regression test for #2213, making sure a nameless column can be printed using None as the name. """ col = table.Column([1., 2.]) assert str(col).startswith('None') def test_html(): """Test HTML printing""" dat = np.array([1., 2.], dtype=np.float32) t = Table([dat], names=['a']) lines = t.pformat(html=True) assert lines == [f'', '', '', '', '
a
1.0
2.0
'] lines = t.pformat(html=True, tableclass='table-striped') assert lines == [ f'', '', '', '', '
a
1.0
2.0
'] lines = t.pformat(html=True, tableclass=['table', 'table-striped']) assert lines == [ f'', '', '', '', '
a
1.0
2.0
'] def test_align(): t = simple_table(2, kinds='iS') assert t.pformat() == [' a b ', '--- ---', ' 1 b', ' 2 c'] # Use column format attribute t['a'].format = '<' assert t.pformat() == [' a b ', '--- ---', '1 b', '2 c'] # Now override column format attribute with various combinations of align tpf = [' a b ', '--- ---', ' 1 b ', ' 2 c '] for align in ('^', ['^', '^'], ('^', '^')): assert tpf == t.pformat(align=align) assert t.pformat(align='<') == [' a b ', '--- ---', '1 b ', '2 c '] assert t.pformat(align='0=') == [' a b ', '--- ---', '001 00b', '002 00c'] assert t.pformat(align=['<', '^']) == [' a b ', '--- ---', '1 b ', '2 c '] # Now use fill characters. Stress the system using a fill # character that is the same as an align character. t = simple_table(2, kinds='iS') assert t.pformat(align='^^') == [' a b ', '--- ---', '^1^ ^b^', '^2^ ^c^'] assert t.pformat(align='^>') == [' a b ', '--- ---', '^^1 ^^b', '^^2 ^^c'] assert t.pformat(align='^<') == [' a b ', '--- ---', '1^^ b^^', '2^^ c^^'] # Complicated interaction (same as narrative docs example) t1 = Table([[1.0, 2.0], [1, 2]], names=['column1', 'column2']) t1['column1'].format = '#^.2f' assert t1.pformat() == ['column1 column2', '------- -------', '##1.00# 1', '##2.00# 2'] assert t1.pformat(align='!<') == ['column1 column2', '------- -------', '1.00!!! 1!!!!!!', '2.00!!! 2!!!!!!'] assert t1.pformat(align=[None, '!<']) == ['column1 column2', '------- -------', '##1.00# 1!!!!!!', '##2.00# 2!!!!!!'] # Zero fill t['a'].format = '+d' assert t.pformat(align='0=') == [' a b ', '--- ---', '+01 00b', '+02 00c'] with pytest.raises(ValueError): t.pformat(align=['fail']) with pytest.raises(TypeError): t.pformat(align=0) with pytest.raises(TypeError): t.pprint(align=0) # Make sure pprint() does not raise an exception t.pprint() with pytest.raises(ValueError): t.pprint(align=['<', '<', '<']) with pytest.raises(ValueError): t.pprint(align='x=') def test_auto_format_func(): """Test for #5802 (fix for #5800 where format_func key is not unique)""" t = Table([[1, 2] * u.m]) t['col0'].format = '%f' t.pformat() # Force caching of format function qt = QTable(t) qt.pformat() # Generates exception prior to #5802 def test_decode_replace(): """ Test printing a bytestring column with a value that fails decoding to utf-8 and gets replaced by U+FFFD. See https://docs.python.org/3/library/codecs.html#codecs.replace_errors """ t = Table([[b'Z\xf0']]) assert t.pformat() == ['col0', '----', ' Z\ufffd'] class TestColumnsShowHide: """Tests of show and hide table columns""" def setup_method(self): self.t = simple_table(size=1, cols=4, kinds='i') @pytest.mark.parametrize('attr', ('pprint_exclude_names', 'pprint_include_names')) def test_basic(self, attr): t = self.t assert repr(getattr(Table, attr)) == f'' t_show_hide = getattr(t, attr) assert repr(t_show_hide) == f'' # Default value is None assert t_show_hide() is None def test_slice(self): t = self.t t.pprint_include_names = 'a' t.pprint_exclude_names = 'b' t2 = t[0:1] assert t2.pprint_include_names() == ('a',) assert t2.pprint_exclude_names() == ('b',) def test_copy(self): t = self.t t.pprint_include_names = 'a' t.pprint_exclude_names = 'b' t2 = t.copy() assert t2.pprint_include_names() == ('a',) assert t2.pprint_exclude_names() == ('b',) t2.pprint_include_names = 'c' t2.pprint_exclude_names = 'd' assert t.pprint_include_names() == ('a',) assert t.pprint_exclude_names() == ('b',) assert t2.pprint_include_names() == ('c',) assert t2.pprint_exclude_names() == ('d',) @pytest.mark.parametrize('attr', ('pprint_exclude_names', 'pprint_include_names')) @pytest.mark.parametrize('value', ('z', ['a', 'z'])) def test_setting(self, attr, value): t = self.t t_show_hide = getattr(t, attr) # Expected attribute value ('z',) or ('a', 'z') exp = (value,) if isinstance(value, str) else tuple(value) # Context manager, can include column names that do not exist with t_show_hide.set(value): assert t_show_hide() == exp assert t.meta['__attributes__'] == {attr: exp} assert t_show_hide() is None # Setting back to None clears out meta assert t.meta == {} # Do `t.pprint_include_names/hide = value` setattr(t, attr, value) assert t_show_hide() == exp # Clear attribute t_show_hide.set(None) assert t_show_hide() is None # Now use set() method t_show_hide.set(value) assert t_show_hide() == exp with t_show_hide.set(None): assert t_show_hide() is None assert t.meta == {} assert t_show_hide() == exp @pytest.mark.parametrize('attr', ('pprint_exclude_names', 'pprint_include_names')) @pytest.mark.parametrize('value', ('z', ['a', 'z'], ('a', 'z'))) def test_add_remove(self, attr, value): t = self.t t_show_hide = getattr(t, attr) # Expected attribute value ('z') or ('a', 'z') exp = (value,) if isinstance(value, str) else tuple(value) # add() method for str or list of str t_show_hide.add(value) assert t_show_hide() == exp # Adding twice has no effect t_show_hide.add(value) assert t_show_hide() == exp # Remove values (str or list of str). Reverts to None if all names are # removed. t_show_hide.remove(value) assert t_show_hide() is None # Remove just one name, possibly leaving a name. t_show_hide.add(value) t_show_hide.remove('z') assert t_show_hide() == (None if value == 'z' else ('a',)) # Cannot remove name not in the list t_show_hide.set(['a', 'z']) with pytest.raises(ValueError, match=f'x not in {attr}'): t_show_hide.remove(('x', 'z')) @pytest.mark.parametrize('attr', ('pprint_exclude_names', 'pprint_include_names')) def test_rename(self, attr): t = self.t t_hide_show = getattr(t, attr) t_hide_show.set(['a', 'b']) t.rename_column('a', 'aa') assert t_hide_show() == ('aa', 'b') @pytest.mark.parametrize('attr', ('pprint_exclude_names', 'pprint_include_names')) def test_remove(self, attr): t = self.t t_hide_show = getattr(t, attr) t_hide_show.set(['a', 'b']) del t['a'] assert t_hide_show() == ('b',) def test_serialization(self): # Serialization works for ECSV. Currently fails for FITS, works with # HDF5. t = self.t t.pprint_exclude_names = ['a', 'y'] t.pprint_include_names = ['b', 'z'] out = StringIO() ascii.write(t, out, format='ecsv') t2 = ascii.read(out.getvalue(), format='ecsv') assert t2.pprint_exclude_names() == ('a', 'y') assert t2.pprint_include_names() == ('b', 'z') def test_output(self): """Test that pprint_include/exclude_names actually changes the print output""" t = self.t exp = [' b d ', '--- ---', ' 2 4'] with t.pprint_exclude_names.set(['a', 'c']): out = t.pformat_all() assert out == exp with t.pprint_include_names.set(['b', 'd']): out = t.pformat_all() assert out == exp with t.pprint_exclude_names.set(['a', 'c']): out = t.pformat_all() assert out == exp with t.pprint_include_names.set(['b', 'd']): out = t.pformat_all() assert out == exp # Mixture (not common in practice but possible). Note, the trailing # backslash instead of parens is needed for Python < 3.9. See: # https://bugs.python.org/issue12782. with t.pprint_include_names.set(['b', 'c', 'd']), \ t.pprint_exclude_names.set(['c']): out = t.pformat_all() assert out == exp def test_output_globs(self): """Test that pprint_include/exclude_names works with globs (fnmatch)""" t = self.t t['a2'] = 1 t['a23'] = 2 # Show only the a* columns exp = [' a a2 a23', '--- --- ---', ' 1 1 2'] with t.pprint_include_names.set('a*'): out = t.pformat_all() assert out == exp # Show a* but exclude a?? exp = [' a a2', '--- ---', ' 1 1'] with t.pprint_include_names.set('a*'), t.pprint_exclude_names.set('a??'): out = t.pformat_all() assert out == exp # Exclude a?? exp = [' a b c d a2', '--- --- --- --- ---', ' 1 2 3 4 1'] with t.pprint_exclude_names.set('a??'): out = t.pformat_all() assert out == exp