Repository: saulpw/visidata

Issue:
save_xlsx: null values become the string "None"
**Small description**

Setting `--null-value` in either direction doesn't help, so I suspect it isn't just that `options.null_value` is set to `None`.

I found this during the batch conversion. There's code below.

**Expected result**

An empty string (or the `options.null_value`) is more reasonable than `None`, for this conversion. But I can't set an empty string, with `--null-value`.

**Actual result with screenshot**

In lieu of a screenshot, I have console output.

```console
> vd -f json -b --save-filetype=xlsx -o nones.xlsx <<< '[{"foo":"None","bar":null}]'
opening - as json
saving 1 sheets to nones.xlsx as xlsx
Pay attention.
nones.xlsx save finished
> vd -f xlsx -b --save-filetype=json -o - nones.xlsx +:-:: | jq
opening nones.xlsx as xlsx
Let your best be for your friend.
saving 1 sheets to - as json
[
  {
    "foo": "None",
    "bar": "None"
  }
]
```

<details>

<summary>Testing with `--null-value`</summary>

```
> vd -f json -b --save-filetype=xlsx --cmdlog-histfile=vd.log --null-value "None" -o nones.xlsx <<< '[{"foo":"None","bar":null}]'
opening - as json
saving 1 sheets to nones.xlsx as xlsx
Stop this moment, I tell you!
nones.xlsx save finished
> vd -f xlsx -b --save-filetype=json --null-value "" -o - nones.xlsx +:-:: | jq
opening nones.xlsx as xlsx
Listen.
saving 1 sheets to - as json
[
  {
    "foo": "None",
    "bar": "None"
  }
]
> vd -f xlsx -b --save-filetype=json --null-value "None" -o - nones.xlsx +:-:: | jq
opening nones.xlsx as xlsx
Was I the same when I got up this morning?
saving 1 sheets to - as json
[
  {
    "foo": "None",
    "bar": "None"
  }
]
> vd -f json -b --save-filetype=xlsx --cmdlog-histfile=vd.log --null-value "" -o nones.xlsx <<< '[{"foo":"None","bar":null}]'
opening - as json
saving 1 sheets to nones.xlsx as xlsx
Listen.
nones.xlsx save finished
> vd -f xlsx -b --save-filetype=json --null-value "" -o - nones.xlsx +:-:: | jq
opening nones.xlsx as xlsx
I wonder what they'll do next!
saving 1 sheets to - as json
[
  {
    "foo": "None",
    "bar": "None"
  }
]
> vd -f xlsx -b --save-filetype=json --null-value "None" -o - nones.xlsx +:-:: | jq
opening nones.xlsx as xlsx
What are you thinking of?
saving 1 sheets to - as json
[
  {
    "foo": "None",
    "bar": "None"
  }
]
```

</details>

**Steps to reproduce with sample data and a .vd**

This was all done within `--batch` mode (and setting `--cmdlog-histfile` resulted in no output).

**Additional context**

I'm pretty sure this is due to naive serialization of the python value.

```python
>>> f"{None}"
'None'
```

Version

```
saul.pw/VisiData v2.9.1
```

As it happens, I'm interested in extending the `save_xlsx` functionality to create Tables (there is support in `openpyxl`). If I get round to that sooner rather than later, I'll look to fix this first.


Discussion:

Resolving patch:
diff --git a/visidata/loaders/xlsx.py b/visidata/loaders/xlsx.py
--- a/visidata/loaders/xlsx.py
+++ b/visidata/loaders/xlsx.py
@@ -138,7 +138,9 @@ def save_xlsx(vd, p, *sheets):
 
             row = []
             for col, v in dispvals.items():
-                if col.type == date:
+                if v is None:
+                    v = ""
+                elif col.type == date:
                     v = datetime.datetime.fromtimestamp(int(v.timestamp()))
                 elif not vd.isNumeric(col):
                     v = str(v)


Test patch: