Preserve falsy values (0, False) in jira and latex exports#643
Preserve falsy values (0, False) in jira and latex exports#643koriyoshi2041 wants to merge 3 commits into
Conversation
The jira and latex serializers used a truthiness test (`if item`) to decide whether a cell is empty, so 0, 0.0, and False were exported as blank cells and silently lost. Only None and empty strings should render as blank, which is what the html format already does (`if item is not None`). Check `item not in (None, '')` instead so real falsy values are kept.
hugovk
left a comment
There was a problem hiding this comment.
This also changes the display of other falsy things.
With this script:
import tablib
# The fix itself: 0 and False are real values.
print(repr(tablib.Dataset([0, False, 'c']).jira))
# Finding 1: change is broader than 0/False — falsy containers/bytes now
# render their reprs instead of blank cells (jira and latex alike).
print(repr(tablib.Dataset([[], {}, 'c']).jira))
# Finding 2: b'' hits a bytes-vs-str comparison in `item not in (None, '')`
# — raises BytesWarning under -bb (master rendered a blank cell).
print(repr(tablib.Dataset([b'', 'c']).jira))main:
'| | |c|'
'| | |c|'
'| |c|'
PR:
'|0|False|c|'
'|[]|{}|c|'
"|b''|c|"
And if we run with bytes warnings: python -b repro.py:
main:
'| | |c|'
'| | |c|'
'| |c|'
PR:
'|0|False|c|'
'|[]|{}|c|'
/Users/hugo/github/tablib/src/tablib/formats/_jira.py:38: BytesWarning: Comparison between bytes and string
delimiter.join([str(item) if item not in (None, '') else ' ' for item in row]),
/Users/hugo/github/tablib/src/tablib/formats/_jira.py:38: BytesWarning: str() on a bytes instance
delimiter.join([str(item) if item not in (None, '') else ' ' for item in row]),
"|b''|c|"
| """ | ||
|
|
||
| new_row = [cls._escape_tex_reserved_symbols(str(item)) if item else '' | ||
| new_row = [cls._escape_tex_reserved_symbols(str(item)) if item not in (None, '') else '' |
There was a problem hiding this comment.
We can simplify this:
| new_row = [cls._escape_tex_reserved_symbols(str(item)) if item not in (None, '') else '' | |
| new_row = ['' if item is None else cls._escape_tex_reserved_symbols(str(item)) |
| return '{}{}{}'.format( | ||
| delimiter, | ||
| delimiter.join([str(item) if item else ' ' for item in row]), | ||
| delimiter.join([str(item) if item not in (None, '') else ' ' for item in row]), |
There was a problem hiding this comment.
| delimiter.join([str(item) if item not in (None, '') else ' ' for item in row]), | |
| delimiter.join([' ' if item in (None, '') else str(item) for item in row]), |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #643 +/- ##
==========================================
+ Coverage 93.14% 93.28% +0.13%
==========================================
Files 29 29
Lines 3226 3293 +67
==========================================
+ Hits 3005 3072 +67
Misses 221 221 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
| ) | ||
|
|
||
| @classmethod | ||
| def _is_empty_value(cls, item): |
There was a problem hiding this comment.
Move this to utils.py and deduplicate.
| if isinstance(item, (str, bytes, bytearray)): | ||
| return len(item) == 0 | ||
| if isinstance(item, (list, tuple, dict, set, frozenset)): | ||
| return len(item) == 0 |
There was a problem hiding this comment.
This could be a single:
if isinstance(item, (str, bytes, bytearray, list, tuple, dict, set, frozenset)) and len(item) == 0:
return True| delimiter | ||
| ) | ||
|
|
||
| @classmethod |
There was a problem hiding this comment.
cls is never used, can remove @classmethod and cls at the call site.
The JIRA and LaTeX serializers decide whether a cell is empty with a plain truthiness test:
So
0,0.0, andFalse— all valid data — are treated as missing and exported as blank cells, silently losing data. For exampletablib.Dataset([0, False, "c"]).jiraproduced| | |c|instead of|0|False|c|.The HTML format already does this correctly with
str(item) if item is not None else "", so "blank only for missing values" is the intended contract. This changes both serializers to testitem not in (None, ""), which keeps the existingNone/empty-string behaviour (still rendered blank) while preserving real falsy values.Added
test_jira_export_falsy_valuesandtest_latex_export_falsy_values; the existing*_none_*tests still pass.pytest -k "jira or latex"is green (12 passed).