internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: wright-group/WrightTools

Issue:
from_PyCMDS should check version and system to determine if d1, d2, and d3 variables need to be scaled 
Helps to bypass legacy problems involving  wright-group/PyCMDS#210 .


Discussion:
If scaling is needed, the scaling should be applied and an attribute added to reflect the scaling.

Resolving patch:
diff --git a/WrightTools/data/_pycmds.py b/WrightTools/data/_pycmds.py
--- a/WrightTools/data/_pycmds.py
+++ b/WrightTools/data/_pycmds.py
@@ -146,7 +146,7 @@ def from_PyCMDS(filepath, name=None, parent=None, verbose=True) -> Data:
                     if tolerance is None:
                         break
                     if "d" in name:
-                        # This is a hack because delay is particularly 
+                        # This is a hack because delay is particularly
                         # unreliable in tolerance. And 3 fs vs 3 ps is a huge
                         # difference... KFS 2019-2-27
                         if units == "fs":
@@ -197,6 +197,23 @@ def from_PyCMDS(filepath, name=None, parent=None, verbose=True) -> Data:
     for a, u in zip(data.axes, headers["axis units"]):
         if u is not None:
             a.convert(u)
+    if (
+        headers["system name"] == "fs"
+        and int(headers["PyCMDS version"].split(".")[0]) == 0
+        and int(headers["PyCMDS version"].split(".")[1]) < 10
+    ):
+        # in versions of PyCMDS up to (and including) 0.9.0
+        # there was an incorrect hard-coded conversion factor between mm and fs
+        # this ONLY applied to Newport MFA stages
+        # we apply this correction knowing that Newport MFAs were only used on the "fs" system
+        # and knowing that the Newport MFAs were always assigned as "d1", "d2" and "d3"
+        # ---Blaise 2019-04-09
+        for delay in ("d1", "d2", "d3", "d1_points", "d2_points", "d3_points"):
+            if delay not in data.variable_names:
+                continue
+            data[delay][:] *= 6000.671281903963041 / 6671.281903963041
+            if verbose:
+                print(f"Correction factor applied to {delay}")
     # return
     if verbose:
         print("data created at {0}".format(data.fullpath))


Test patch:
diff --git a/tests/data/from_PyCMDS.py b/tests/data/from_PyCMDS.py
--- a/tests/data/from_PyCMDS.py
+++ b/tests/data/from_PyCMDS.py
@@ -52,6 +52,17 @@ def test_wm_w2_w1_000():
     data.close()
 
 
+def test_d1_d2_000():
+    p = datasets.PyCMDS.d1_d2_000
+    data = wt.data.from_PyCMDS(p)
+    assert data.shape == (101, 101)
+    assert data.axis_expressions == ("d1", "d2")
+    # Test for correction factor applied
+    assert data.d1.max() < 230
+    assert data.d1.min() > -230
+    data.close()
+
+
 def test_wm_w2_w1_001():
     p = datasets.PyCMDS.wm_w2_w1_001
     data = wt.data.from_PyCMDS(p)
@@ -77,8 +88,8 @@ def test_ps_delay():
     assert data.shape == (11, 15, 15)
     assert data.axis_expressions == ("d1", "w2", "w1")
     data.close()
-    
-    
+
+
 def test_ps_delay_together():
     p = os.path.join(here, "test_data", "ps_delay_together.data")
     data = wt.data.from_PyCMDS(p)
Repository: wright-group/WrightTools

Issue:
print_tree should print value and units for variables with size 1



Discussion:

Resolving patch:
diff --git a/WrightTools/_dataset.py b/WrightTools/_dataset.py
--- a/WrightTools/_dataset.py
+++ b/WrightTools/_dataset.py
@@ -117,9 +117,12 @@ def _clear_array_attributes_cache(self):
     @property
     def _leaf(self):
         out = self.natural_name
+        if self.size == 1:
+            out += f" = {self.points}"
         if self.units is not None:
             out += " ({0})".format(self.units)
-        out += " {0}".format(self.shape)
+        if self.size != 1:
+            out += " {0}".format(self.shape)
         return out
 
     @property


Test patch:
Repository: wright-group/WrightTools

Issue:
h5py deprecation: will default to read-only in 3.0
Currently defaults to "append"

```
/home/kyle/venvs/source/WrightTools/WrightTools/_open.py:56: H5pyDeprecationWarning: The default file mode will change to 'r' (read-only) in h5py 3.0. To suppress this warning, pass the mode you need to h5py.File(), or set the global default h5.get_config().default_file_mode, or set the environment variable H5PY_DEFAULT_READONLY=1. Available modes are: 'r', 'r+', 'w', 'w-'/'x', 'a'. See the docs for details.
```

```
_group.py
156:        if isinstance(filepath, h5py.File):
184:            file = h5py.File(p, "a")
395:        h5py.File(filepath)

_open.py
56:    f = h5py.File(filepath)
```


Looks like only two lines where this needs to be fixed, and the `_open` one may be perfectly fine as "r", as far as I know, that is only used to read attrs to determine which constructor to call. 


Discussion:

Resolving patch:
diff --git a/WrightTools/_group.py b/WrightTools/_group.py
--- a/WrightTools/_group.py
+++ b/WrightTools/_group.py
@@ -392,7 +392,7 @@ def save(self, filepath=None, overwrite=False, verbose=True):
                 raise wt_exceptions.FileExistsError(filepath)
 
         # copy to new file
-        h5py.File(filepath)
+        h5py.File(filepath, "w")
         new = Group(filepath=filepath, edit_local=True)
         # attrs
         for k, v in self.attrs.items():
diff --git a/WrightTools/_open.py b/WrightTools/_open.py
--- a/WrightTools/_open.py
+++ b/WrightTools/_open.py
@@ -53,9 +53,10 @@ def open(filepath, edit_local=False):
             with ds.open(str(filepath), "rb") as f:
                 tff.write(f.read())
         filepath = tf[1]
-    f = h5py.File(filepath)
+    f = h5py.File(filepath, "r")
     class_name = f["/"].attrs["class"]
     name = f["/"].attrs["name"]
+    f.close()
     if class_name == "Data":
         obj = wt_data.Data(filepath=str(filepath), name=name, edit_local=True)
     elif class_name == "Collection":
diff --git a/logo/logo.py b/logo/logo.py
--- a/logo/logo.py
+++ b/logo/logo.py
@@ -39,7 +39,7 @@
 
 # get arrays
 p = os.path.join(here, "peak.h5")
-h5 = h5py.File(p)
+h5 = h5py.File(p, "r")
 xi = np.array(h5["yi"])
 yi = np.array(h5["xi"])
 zi = np.transpose(np.array(h5["zi"]))


Test patch:
Repository: wright-group/WrightTools

Issue:
consider using NumExpr as alternative to eval
Within the units library, we use eval.

https://github.com/wright-group/WrightTools/blob/master/WrightTools/units.py#L96-L135

We could use NumExpr... our usage case seems to be exactly what the package was made for.

https://numexpr.readthedocs.io/en/latest/user_guide.html


Discussion:

Resolving patch:
diff --git a/WrightTools/units.py b/WrightTools/units.py
--- a/WrightTools/units.py
+++ b/WrightTools/units.py
@@ -5,9 +5,10 @@
 
 
 import collections
+import warnings
 
 import numpy as np
-import warnings
+import numexpr
 
 
 # --- define --------------------------------------------------------------------------------------
@@ -20,7 +21,7 @@
 angle = {"rad": ["x", "x", r"rad"], "deg": ["x/57.2958", "57.2958*x", r"deg"]}
 
 # delay units (native: fs)
-fs_per_mm = 3336.
+fs_per_mm = 3336.0
 delay = {
     "fs": ["x", "x", r"fs"],
     "ps": ["x*1e3", "x/1e3", r"ps"],
@@ -114,12 +115,12 @@ def converter(val, current_unit, destination_unit):
     for dic in dicts.values():
         if current_unit in dic.keys() and destination_unit in dic.keys():
             try:
-                native = eval(dic[current_unit][0])
+                native = numexpr.evaluate(dic[current_unit][0], {"x": x})
             except ZeroDivisionError:
                 native = np.inf
             x = native  # noqa: F841
             try:
-                out = eval(dic[destination_unit][1])
+                out = numexpr.evaluate(dic[destination_unit][1], {"x": x})
             except ZeroDivisionError:
                 out = np.inf
             return out


Test patch:
Repository: wright-group/WrightTools

Issue:
Symmetric square root does not correctly multiple by the sign factor when the output array is supplied
https://github.com/wright-group/WrightTools/blob/e875360573e8375f94ed4ed70a7d8dc02ab92bb5/WrightTools/kit/_calculate.py#L145-L165


Discussion:

Resolving patch:
diff --git a/WrightTools/kit/_calculate.py b/WrightTools/kit/_calculate.py
--- a/WrightTools/kit/_calculate.py
+++ b/WrightTools/kit/_calculate.py
@@ -137,8 +137,8 @@ def nm_width(center, width, units="wn") -> float:
     number
         Width in nm.
     """
-    red = wt_units.converter(center - width / 2., units, "nm")
-    blue = wt_units.converter(center + width / 2., units, "nm")
+    red = wt_units.converter(center - width / 2.0, units, "nm")
+    blue = wt_units.converter(center + width / 2.0, units, "nm")
     return red - blue
 
 
@@ -162,4 +162,5 @@ def symmetric_sqrt(x, out=None):
     """
     factor = np.sign(x)
     out = np.sqrt(np.abs(x), out=out)
-    return out * factor
+    out *= factor
+    return out
diff --git a/WrightTools/kit/_interpolate.py b/WrightTools/kit/_interpolate.py
--- a/WrightTools/kit/_interpolate.py
+++ b/WrightTools/kit/_interpolate.py
@@ -21,7 +21,7 @@
 # --- functions -----------------------------------------------------------------------------------
 
 
-def zoom2D(xi, yi, zi, xi_zoom=3., yi_zoom=3., order=3, mode="nearest", cval=0.):
+def zoom2D(xi, yi, zi, xi_zoom=3.0, yi_zoom=3.0, order=3, mode="nearest", cval=0.0):
     """Zoom a 2D array, with axes.
 
     Parameters
diff --git a/WrightTools/kit/_timestamp.py b/WrightTools/kit/_timestamp.py
--- a/WrightTools/kit/_timestamp.py
+++ b/WrightTools/kit/_timestamp.py
@@ -159,7 +159,7 @@ def RFC3339(self):
         format_string = "%Y-%m-%dT%H:%M:%S.%f"
         out = self.datetime.strftime(format_string)
         # timezone
-        if delta_sec == 0.:
+        if delta_sec == 0.0:
             out += "Z"
         else:
             if delta_sec > 0:


Test patch:
diff --git a/tests/kit/symmetric_sqrt.py b/tests/kit/symmetric_sqrt.py
--- a/tests/kit/symmetric_sqrt.py
+++ b/tests/kit/symmetric_sqrt.py
@@ -17,3 +17,11 @@ def test_numbers():
     for number in numbers:
         answer = wt.kit.symmetric_sqrt(number)
         assert answer == np.sign(number) * np.sqrt(np.abs(number))
+
+
+def test_no_reallocation():
+    a = np.linspace(-9, 9, 3)
+    out = np.empty_like(a)
+    ret = wt.kit.symmetric_sqrt(a, out=out)
+    assert out is ret
+    assert np.allclose(ret, [-3, 0, 3])
Repository: wright-group/WrightTools

Issue:
Calls to .convert() in split should have verbose=verbose kwarg
https://github.com/wright-group/WrightTools/blob/f7a264d9cb6953569541b190134fd2cf33fc8f6a/WrightTools/data/_data.py#L1675

https://github.com/wright-group/WrightTools/blob/f7a264d9cb6953569541b190134fd2cf33fc8f6a/WrightTools/data/_data.py#L1770


Discussion:

Resolving patch:
diff --git a/WrightTools/data/_data.py b/WrightTools/data/_data.py
--- a/WrightTools/data/_data.py
+++ b/WrightTools/data/_data.py
@@ -1672,7 +1672,7 @@ def split(
 
         self.transform(expression)
         if units:
-            self.convert(units)
+            self.convert(units, verbose=False)
 
         try:
             positions = [-np.inf] + sorted(list(positions)) + [np.inf]


Test patch:
Repository: wright-group/WrightTools

Issue:
mpl.color.ColorbarBase Deprecation warning
WrightTools v 3.3.1
mpl v 3.3.2

e.g.
```
import WrightTools as wt
import matplotlib as mpl

fig, gs = wt.artists.create_figure(cols=[1, "cbar"])
cax = fig.add_subplot(gs[1])
wt.artists.plot_colorbar(cax)
mpl.pyplot.show()
```
raises `MatplotlibDeprecationWarning`: Passing parameters norm and vmin/vmax simultaneously is deprecated since 3.3 and will become an error two minor releases later. Please pass vmin/vmax directly to the norm when creating it.

I believe the issues is `ColorBarBase` calls pcolormesh, which passes through the wt pcolormesh wrapper, which calls `_parse_limits` and returns vmin, vmax to the mpl pcolormesh call.



Discussion:
@ksunden do you have the background knowledge to fix this issue? 

Resolving patch:
diff --git a/WrightTools/artists/_base.py b/WrightTools/artists/_base.py
--- a/WrightTools/artists/_base.py
+++ b/WrightTools/artists/_base.py
@@ -82,6 +82,8 @@ def _apply_labels(
             self.set_ylabel(ylabel, fontsize=18)
 
     def _parse_limits(self, zi=None, data=None, channel_index=None, dynamic_range=False, **kwargs):
+        if "norm" in kwargs:
+            return kwargs
         if zi is not None:
             if "levels" in kwargs.keys():
                 levels = kwargs["levels"]


Test patch:
Repository: wright-group/WrightTools

Issue:
Matplotlib depreciation related to _helpers
```
c:\users\dmorrow\source\wrighttools\WrightTools\artists\_helpers.py:990: MatplotlibDeprecationWarning: 
The numRows attribute was deprecated in Matplotlib 3.4 and will be removed two minor releases later. Use get_gridspec().nrows instead.
  numRows = fig.axes[0].numRows
c:\users\dmorrow\source\wrighttools\WrightTools\artists\_helpers.py:996: MatplotlibDeprecationWarning: 
The numCols attribute was deprecated in Matplotlib 3.4 and will be removed two minor releases later. Use get_gridspec().ncols instead.
  numCols = fig.axes[0].numCols
```


Discussion:
@darienmorrow are you willing to PR this, it should just be the suggested replacement (which is the internal implementation anyway) on those two lines.

Does not, in my opinion, require additional tests, as behavior is not changed in any way, just not executing a warning.

Resolving patch:
diff --git a/WrightTools/artists/_helpers.py b/WrightTools/artists/_helpers.py
--- a/WrightTools/artists/_helpers.py
+++ b/WrightTools/artists/_helpers.py
@@ -987,13 +987,13 @@ def set_fig_labels(
     if fig is None:
         fig = plt.gcf()
     # interpret row
-    numRows = fig.axes[0].numRows
+    numRows = fig.axes[0].get_gridspec().nrows
     if isinstance(row, int):
         row %= numRows
         row = slice(0, row)
     row_start, row_stop, _ = row.indices(numRows)
     # interpret col
-    numCols = fig.axes[0].numCols
+    numCols = fig.axes[0].get_gridspec().ncols
     if isinstance(col, int):
         col %= numCols
         col = slice(col, -1)


Test patch:
Repository: wright-group/WrightTools

Issue:
Windows PermissionError for copy
It seems that our recent test failures all share that they call `data.copy()`. Not sure why this behavior has changed on CI recently, but it does appear that copy is not properly closing before reopening....


Discussion:

Resolving patch:
diff --git a/WrightTools/_group.py b/WrightTools/_group.py
--- a/WrightTools/_group.py
+++ b/WrightTools/_group.py
@@ -340,18 +340,16 @@ def copy(self, parent=None, name=None, verbose=True):
         if name is None:
             name = self.natural_name
         if parent is None:
-            from ._open import open as wt_open  # circular import
-
             new = Group()  # root of new tempfile
             # attrs
             new.attrs.update(self.attrs)
-            new.natural_name = name
             # children
             for k, v in self.items():
                 super().copy(v, new, name=v.natural_name)
             new.flush()
-            p = new.filepath
-            new = wt_open(p)
+            # Converts to appropriate Data/Collection object
+            new = new["/"]
+            new.natural_name = name
         else:
             # copy
             self.file.copy(self.name, parent, name=name)


Test patch:
diff --git a/tests/group/save.py b/tests/group/save.py
--- a/tests/group/save.py
+++ b/tests/group/save.py
@@ -104,8 +104,10 @@ def test_simple_copy():
     new = original.copy()
     assert original.fullpath != new.fullpath
     for k, v in original.attrs.items():
+        print(k)
         assert_equal(new.attrs[k], v)
     for k, v in original.items():
+        print(k)
         assert_equal(new[k], v)
     original.close()
     new.close()
Repository: wright-group/WrightTools

Issue:
artists._parse_limits : respect channel null for signed type
https://github.com/wright-group/WrightTools/blob/1660485e1ce2c7603af6d3e1500b01f9883625f4/WrightTools/artists/_base.py#L97

extents are measured wrt null, but null should be added back in for cmap limits



Discussion:

Resolving patch:
diff --git a/WrightTools/artists/_base.py b/WrightTools/artists/_base.py
--- a/WrightTools/artists/_base.py
+++ b/WrightTools/artists/_base.py
@@ -94,14 +94,15 @@ def _parse_limits(self, zi=None, data=None, channel_index=None, dynamic_range=Fa
                 vmax = np.nanmax(zi)
         elif data is not None:
             signed = data.channels[channel_index].signed
+            null = data.channels[channel_index].null
             if signed and dynamic_range:
-                vmin = -data.channels[channel_index].minor_extent
-                vmax = +data.channels[channel_index].minor_extent
+                vmin = -data.channels[channel_index].minor_extent + null
+                vmax = +data.channels[channel_index].minor_extent + null
             elif signed and not dynamic_range:
-                vmin = -data.channels[channel_index].major_extent
-                vmax = +data.channels[channel_index].major_extent
+                vmin = -data.channels[channel_index].major_extent + null
+                vmax = +data.channels[channel_index].major_extent + null
             else:
-                vmin = data.channels[channel_index].null
+                vmin = null
                 vmax = data.channels[channel_index].max()
         # don't overwrite
         if "vmin" not in kwargs.keys():


Test patch:
Repository: wright-group/WrightTools

Issue:
chop: respect axes order in method call
The recent overhaul of chop left behind an unintended bug where the axis order in the call was not respected e.g.
```
data.chop("y", "x")[0]
print(data.axis_names)
```
This should return ("y","x"), but it might return ("x", "y"), depending on the original transform. 



Discussion:

Resolving patch:
diff --git a/WrightTools/data/_data.py b/WrightTools/data/_data.py
--- a/WrightTools/data/_data.py
+++ b/WrightTools/data/_data.py
@@ -420,6 +420,8 @@ def chop(self, *args, at=None, parent=None, verbose=True) -> wt_collection.Colle
                 arg = arg.strip()
                 args[i] = wt_kit.string2identifier(arg, replace=operator_to_identifier)
 
+        transform_expression = [self._axes[self.axis_names.index(a)].expression for a in args]
+
         if at is None:
             at = {}
         # normalize the at keys to the natural name
@@ -457,6 +459,7 @@ def chop(self, *args, at=None, parent=None, verbose=True) -> wt_collection.Colle
             idx[np.array(removed_shape) == 1] = slice(None)
             idx[at_axes] = at_idx[at_axes]
             self._from_slice(idx, name=name, parent=out)
+            out[name].transform(*transform_expression)
         out.flush()
         # return
         if verbose:


Test patch:
diff --git a/tests/data/chop.py b/tests/data/chop.py
--- a/tests/data/chop.py
+++ b/tests/data/chop.py
@@ -123,6 +123,23 @@ def test_parent():
     assert chop.parent is parent
 
 
+def test_axes_order():
+    x = np.arange(6)
+    y = x[::2].copy()
+    z = x[::3].copy()
+    chan = np.arange(x.size * y.size * z.size).reshape(x.size, y.size, z.size).astype("float")
+    data = wt.data.Data(name="data")
+    data.create_channel("chan", values=chan, signed=False)
+    data.create_variable("x", values=x[:, None, None], units="wn")
+    data.create_variable("y", values=y[None, :, None], units="wn")
+    data.create_variable("z", values=z[None, None, :], units="wn")
+
+    data.transform("y", "x", "z")
+
+    d = data.chop("z", "x", at={"y": (2, "wn")})[0]
+    assert d.axis_names == ("z", "x")
+
+
 def test_transformed():
     x = np.arange(6)
     y = x[::2].copy()
@@ -174,6 +191,7 @@ def test_rmd_axis_full_shape():
 
 if __name__ == "__main__":
     test_transformed()
+    test_axes_order()
     test_2D_to_1D()
     test_3D_to_1D()
     test_3D_to_1D_at()
Repository: wright-group/WrightTools

Issue:
chop fails when axes do not span data shape
```
import WrightTools as wt
import numpy as np

x = np.arange(6)

d = wt.Data(name="test")
d.create_variable("x", values=x[:, None, None])
d.create_variable("y", values=x[None, :, None])
d.create_variable("z", values=x[None, None, :])
d.transform("x", "y")  # note no z

d.chop(0)
```

raises IndexError in chop:
```
~\wrighttools\WrightTools\data\_data.py in chop(self, at, parent, verbose, *args)
    458             idx = np.array(idx, dtype=object)
    459             idx[np.array(removed_shape) == 1] = slice(None)
--> 460             idx[at_axes] = at_idx[at_axes]
    461             self._from_slice(idx, name=name, parent=out)
    462             out[name].transform(*transform_expression)

IndexError: boolean index did not match indexed array along dimension 0; dimension is 3 but corresponding boolean dimension is 2
```

Looking into fix...



Discussion:
bug is in the new chop implementation of v3.4.5; previous wt versions work fine.

Resolving patch:
diff --git a/WrightTools/data/_data.py b/WrightTools/data/_data.py
--- a/WrightTools/data/_data.py
+++ b/WrightTools/data/_data.py
@@ -482,7 +482,7 @@ def _at_to_slice(self, **at) -> np.array:
         for k in at.keys():
             if k not in self.axis_names:
                 raise ValueError(f"Axis identifier {k} not in Axes: {self.axis_names}")
-        idx = np.array([slice(None)] * len(self._axes))
+        idx = np.array([slice(None)] * len(self.shape))
         for axis, point in at.items():
             point, units = point
             destination_units = self._axes[self.axis_names.index(axis)].units


Test patch:
diff --git a/tests/data/chop.py b/tests/data/chop.py
--- a/tests/data/chop.py
+++ b/tests/data/chop.py
@@ -186,12 +186,32 @@ def test_rmd_axis_full_shape():
     assert c[0].shape == (6, 3)
 
 
+def test_non_spanning_axes():
+    """axes do not span shape of data"""
+
+    x = np.arange(6)
+
+    d = wt.Data(name="test")
+    d.create_variable("x", values=x[:, None, None])
+    d.create_variable("y", values=x[None, ::2, None])
+    d.create_variable("z", values=x[None, None, ::3])
+    d.transform("x", "y")
+
+    c = d.chop(1)
+    assert c[0].axis_names == ("y",)
+    assert c[0].shape == d.shape[1:]
+
+    d.close()
+    c.close()
+
+
 # --- run -----------------------------------------------------------------------------------------
 
 
 if __name__ == "__main__":
     test_transformed()
     test_axes_order()
+    test_non_spanning_axes()
     test_2D_to_1D()
     test_3D_to_1D()
     test_3D_to_1D_at()