diff --git a/eido/_version.py b/eido/_version.py index fe404ae..01ef120 100644 --- a/eido/_version.py +++ b/eido/_version.py @@ -1 +1 @@ -__version__ = "0.2.5" +__version__ = "0.2.6" diff --git a/eido/output_formatters.py b/eido/output_formatters.py index f9d2486..a3ff58f 100644 --- a/eido/output_formatters.py +++ b/eido/output_formatters.py @@ -112,6 +112,11 @@ def _convert_sample_to_row( else: value = sample.get(attribute) + if isinstance(value, float) and value != value: + # pandas (>=3.0) yields float('nan') instead of None for missing + # values when a Sample's attributes originate from a DataFrame + value = None + sample_row.append(value or "") return ",".join(sample_row) diff --git a/requirements/requirements-all.txt b/requirements/requirements-all.txt index c4a845f..7c16b30 100644 --- a/requirements/requirements-all.txt +++ b/requirements/requirements-all.txt @@ -1,6 +1,6 @@ importlib-metadata; python_version < '3.10' jsonschema>=3.0.1 logmuse>=0.2.5 -pandas<3.0.0 +pandas peppy>=0.40.7 ubiquerg>=0.5.2 diff --git a/tests/test_conversions.py b/tests/test_conversions.py index a4aad8c..4a827ff 100644 --- a/tests/test_conversions.py +++ b/tests/test_conversions.py @@ -4,6 +4,7 @@ pep_conversion_plugins, convert_project, ) +from eido.output_formatters import MultilineOutputFormatter import peppy @@ -104,3 +105,30 @@ def test_multiple_subsamples(self, test_multiple_subs): "yaml-samples", ) assert isinstance(conversion["samples"], str) + + +class TestMultilineOutputFormatterMissingValues: + """ + Under pandas >=3.0 a missing attribute reaches the formatter as float('nan') + rather than as an empty string, which used to raise TypeError from the join. + """ + + def test_missing_attribute_becomes_empty_field(self): + sample = peppy.Sample({"sample": "frog_1", "fasta": float("nan")}) + + assert MultilineOutputFormatter.format([sample]) == "sample,fasta\nfrog_1,\n" + + def test_missing_subsample_attribute_becomes_empty_field(self): + # Merging a subsample table that lacks a column produces a list of nan + sample = peppy.Sample( + { + "sample": "frog_1", + "fasta": [float("nan"), float("nan")], + "subsample_name": ["0", "1"], + } + ) + + assert ( + MultilineOutputFormatter.format([sample]) + == "sample,fasta\nfrog_1,\nfrog_1,\n" + )