Repository: wright-group/WrightTools

Issue:
`Data.save` : None type units improperly handled after save/open 
Using WrightTools ver. 3.2.7.
Minimal working example:
```
import WrightTools as wt
from WrightTools import datasets

temp = wt.data.from_Solis(datasets.Solis.xpos_ypos_fluorescence)
temp = temp.split("yindex", [500, 600])[1]
temp.save("test_split.wt5")

temp = wt.open("test_split.wt5")
temp = temp.split("yindex", [520, 580])[1]
```
Raises UnitsError (UnitsError(...), 'expected units of () (recieved None)')

The code does run successfully if the save and open commands are omitted.



Discussion:
Yup, seems to be getting str "None" instead of NoneType None

https://github.com/wright-group/WrightTools/blob/master/WrightTools/data/_data.py#L52

Fix would be around here, to (first do the .strip when it is definitely string) and then do `if units == "None": units=None`

Should also do so for constants in addition to axes

Should also add a test for the future.

Workaround is to do `temp.xindex.units = temp.yindex.units = None` prior to splitting

Resolving patch:
diff --git a/WrightTools/data/_data.py b/WrightTools/data/_data.py
--- a/WrightTools/data/_data.py
+++ b/WrightTools/data/_data.py
@@ -45,25 +45,29 @@ def __init__(self, *args, **kwargs):
         self._axes = []
         self._constants = []
         Group.__init__(self, *args, **kwargs)
-        # populate axes from attrs string
+        # populate axes, constants from attrs string
         for identifier in self.attrs.get("axes", []):
             identifier = identifier.decode()
             expression, units = identifier.split("{")
-            units = units.replace("}", "")
+            units = units.replace("}", "").strip()
+            if units == "None":
+                units = None
             # Should not be needed for wt5 >= 1.0.3, kept for opening older wt5 files.
             for i in identifier_to_operator.keys():
                 expression = expression.replace(i, identifier_to_operator[i])
             expression = expression.replace(" ", "")  # remove all whitespace
-            axis = Axis(self, expression, units.strip())
+            axis = Axis(self, expression, units)
             self._axes.append(axis)
         for identifier in self.attrs.get("constants", []):
             identifier = identifier.decode()
             expression, units = identifier.split("{")
-            units = units.replace("}", "")
+            units = units.replace("}", "").strip()
+            if units == "None":
+                units = None
             for i in identifier_to_operator.keys():
                 expression = expression.replace(i, identifier_to_operator[i])
             expression = expression.replace(" ", "")  # remove all whitespace
-            const = Constant(self, expression, units.strip())
+            const = Constant(self, expression, units)
             self._constants.append(const)
         self._current_axis_identities_in_natural_namespace = []
         self._on_constants_updated()


Test patch:
diff --git a/tests/data/init.py b/tests/data/init.py
new file mode 100644
--- /dev/null
+++ b/tests/data/init.py
@@ -0,0 +1,21 @@
+#! /usr/bin/env python3
+"""Test data __init__"""
+
+# --- import --------------------------------------------------------------------------------------
+
+
+import WrightTools as wt
+import numpy as np
+
+
+# --- test ----------------------------------------------------------------------------------------
+
+
+def test_axes_NoneType_units():
+    a = wt.Data()
+    a.create_variable("x", np.array([0]), units=None)
+    a.transform("x")
+    a = a.copy()
+    assert a.x.units is None
+    a.close()
+