Repository: wright-group/WrightTools

Issue:
rename methods
`data.rename_channel` and `data.rename_axis`

accept kwargs with key oldname and value newname

if newname already in names and not ALSO being renamed, raise helpful exception

remember to call `data._update`

not necessarily clear how to handle `axis.label_seed`


Discussion:
we can probably also move to raising an exception in `_update` if natural naming is broken (see #280)
_update already contains the following:

```
if len(all_names) == len(set(all_names)):
            pass
        else:
            print('axis, constant, and channel names must all be unique')
            return
```

This should can (and probably should) be changed to an actual exception, but the check is there.

Should rename_channel and rename_axis be different functions, or should they be the same function, which would allow you to swap names between channels and axes in a single step
I have also made the executive decision to use plural names, since these allow for plural changing, if others have opinions on the matter, please say so
I think plural names make sense

I can see arguments for either one or two methods. obviously 2 methods is what came naturally to me, but one is fine as well. that said, I really hope people don't start naming their channels things like `w1`...

Resolving patch:
diff --git a/WrightTools/data/_data.py b/WrightTools/data/_data.py
--- a/WrightTools/data/_data.py
+++ b/WrightTools/data/_data.py
@@ -1203,12 +1203,10 @@ def m(self, abs_data, channel=0, this_exp='TG', indices=None, m=None, bounds_err
 
         Notes
         -----
-
         m-factors originally derived by Carlson and Wright. [1]_
 
         References
         ----------
-
         .. [1] **Absorption and Coherent Interference Effects in Multiply Resonant
                Four-Wave Mixing Spectroscopy**
                Roger J. Carlson, and John C. Wright
@@ -1520,6 +1518,30 @@ def remove_channel(self, channel):
         # finish
         self._update()
 
+    def rename_attrs(self, **kwargs):
+        """Rename a set of attributes.
+
+        Keyword Arguments
+        -----------------
+        Each argument should have the key of a current axis or channel,
+            and a value which is a string of its new name.
+
+        The name will be set to str(val), and its natural naming identifier
+        will be wt.kit.string2identifier(str(val))
+        """
+        changed = kwargs.keys()
+        for k, v in kwargs.items():
+            if getattr(self, k).__class__ not in (Channel, Axis):
+                raise TypeError("Attribute for key %s: expected {Channel, Axis}, got %s" %
+                                (k, getattr(self, k).__class__))
+            if v not in changed and hasattr(self, v):
+                raise wt_exceptions.NameNotUniqueError(v)
+        for k, v in kwargs.items():
+            axis = getattr(self, k)
+            axis.name = str(v)
+            delattr(self, k)
+        self._update()
+
     def save(self, filepath=None, verbose=True):
         """Save using the `pickle`__ module.
 
diff --git a/WrightTools/exceptions.py b/WrightTools/exceptions.py
--- a/WrightTools/exceptions.py
+++ b/WrightTools/exceptions.py
@@ -44,6 +44,21 @@ def __init__(self, path):
         Exception.__init__(self, message)
 
 
+class NameNotUniqueError(Exception):
+    """NameNotUniqueError."""
+
+    def __init__(self, name):
+        """Format a Name Not Unique Error.
+
+        Parameters
+        ----------
+        name : string
+            Name of an attribute which causes a duplication.
+        """
+        message = 'Name {} results in a duplicate'.format(name)
+        Exception.__init__(self, message)
+
+
 # --- custom warnings -----------------------------------------------------------------------------
 
 


Test patch:
diff --git a/tests/data/rename_attrs.py b/tests/data/rename_attrs.py
new file mode 100644
--- /dev/null
+++ b/tests/data/rename_attrs.py
@@ -0,0 +1,30 @@
+"""test rename_attrs."""
+
+
+# --- import --------------------------------------------------------------------------------------
+
+
+import WrightTools as wt
+from WrightTools import datasets
+
+
+# --- test ----------------------------------------------------------------------------------------
+
+
+def test_rename():
+    p = datasets.PyCMDS.wm_w2_w1_000
+    data = wt.data.from_PyCMDS(p)
+    data.rename_attrs(w1='w2', w2='w1')
+    assert data.shape == (35, 11, 11)
+    assert data.axis_names == ['wm', 'w1', 'w2']
+
+
+def test_error():
+    p = datasets.PyCMDS.wm_w2_w1_000
+    data = wt.data.from_PyCMDS(p)
+    try:
+        data.rename_attrs(w1='w2')
+    except wt.exceptions.NameNotUniqueError:
+        assert True
+    else:
+        assert False