Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Here is a list of past and present much-appreciated contributors:
Joel Friedly
Josh Ourisman
Kenneth Reitz
kigland
Luca Beltrame
Luke Lee
Marc Abramowitz
Expand Down
3 changes: 2 additions & 1 deletion src/tablib/formats/_jira.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

Generates a Jira table from the dataset.
"""
from tablib.utils import is_empty_cell


class JIRAFormat:
Expand Down Expand Up @@ -35,6 +36,6 @@ def _get_header(cls, headers):
def _serialize_row(cls, row, delimiter='|'):
return '{}{}{}'.format(
delimiter,
delimiter.join([str(item) if item else ' ' for item in row]),
delimiter.join([' ' if is_empty_cell(item) else str(item) for item in row]),
delimiter
)
5 changes: 4 additions & 1 deletion src/tablib/formats/_latex.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"""
import re

from tablib.utils import is_empty_cell


class LATEXFormat:
title = 'latex'
Expand Down Expand Up @@ -117,7 +119,8 @@ def _serialize_row(cls, row):
:param row: single dataset row
"""

new_row = [cls._escape_tex_reserved_symbols(str(item)) if item else ''
new_row = ['' if is_empty_cell(item)
else cls._escape_tex_reserved_symbols(str(item))
for item in row]
return 6 * ' ' + ' & '.join(new_row) + ' \\\\'

Expand Down
10 changes: 10 additions & 0 deletions src/tablib/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
from io import BytesIO, StringIO


def is_empty_cell(value):
return (
value is None
or (
isinstance(value, (str, bytes, bytearray, list, tuple, dict, set, frozenset))
and len(value) == 0
)
)


def normalize_input(stream):
"""
Accept either a str/bytes stream or a file-like object and always return a
Expand Down
20 changes: 20 additions & 0 deletions tests/test_tablib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1772,6 +1772,18 @@ def test_latex_export_none_values(self):
self.assertIn('foo', output)
self.assertNotIn('None', output)

def test_latex_export_falsy_values(self):
# 0 and False are real values and must be rendered, not dropped.
output = tablib.Dataset([0, False, 90]).latex
self.assertIn('0 & False & 90', output)

def test_latex_export_empty_containers_and_bytes(self):
output = tablib.Dataset([[], {}, b'']).latex
self.assertIn(' & & ', output)
self.assertNotIn('[]', output)
self.assertNotIn('{}', output)
self.assertNotIn("b''", output)

def test_latex_escaping(self):
d = tablib.Dataset(['~', '^'])
output = d.latex
Expand Down Expand Up @@ -1902,6 +1914,14 @@ def test_jira_export_no_headers(self):
def test_jira_export_none_and_empty_values(self):
self.assertEqual('| | |c|', tablib.Dataset(['', None, 'c']).jira)

def test_jira_export_falsy_values(self):
# 0 and False are real values, not empty cells.
self.assertEqual('|0|False|c|', tablib.Dataset([0, False, 'c']).jira)

def test_jira_export_empty_containers_and_bytes(self):
self.assertEqual('| | |c|', tablib.Dataset([[], {}, 'c']).jira)
self.assertEqual('| |c|', tablib.Dataset([b'', 'c']).jira)

def test_jira_export_empty_dataset(self):
self.assertIsNotNone(tablib.Dataset().jira)

Expand Down