prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  from_solis:  import fails when no metadata
  It is possible to export asc image from Solis software without metadata (clearly this is not preferred, but it should be handled gracefully).  
  
  from_solis assumes "Data and Time" field exists in metadata (for attrs timestamp).  Fall back on file creation date as an alternative.   
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `WrightTools/data/_solis.py`
  Content:
  ```
  1 """Andor."""
  2 
  3 
  4 # --- import --------------------------------------------------------------------------------------
  5 
  6 
  7 import os
  8 import pathlib
  9 import time
  10 
  11 import numpy as np
  12 
  13 from ._data import Data
  14 from .. import exceptions as wt_exceptions
  15 from ..kit import _timestamp as timestamp
  16 
  17 
  18 # --- define --------------------------------------------------------------------------------------
  19 
  20 
  21 __all__ = ["from_Solis"]
  22 
  23 
  24 # --- from function -------------------------------------------------------------------------------
  25 
  26 
  27 def from_Solis(filepath, name=None, parent=None, verbose=True) -> Data:
  28     """Create a data object from Andor Solis software (ascii exports).
  29 
  30     Parameters
  31     ----------
  32     filepath : path-like
  33         Path to file (should be .asc format).
  34         Can be either a local or remote file (http/ftp).
  35         Can be compressed with gz/bz2, decompression based on file name.
  36     name : string (optional)
  37         Name to give to the created data object. If None, filename is used.
  38         Default is None.
  39     parent : WrightTools.Collection (optional)
  40         Collection to place new data object within. Default is None.
  41     verbose : boolean (optional)
  42         Toggle talkback. Default is True.
  43 
  44     Returns
  45     -------
  46     data
  47         New data object.
  48     """
  49     # parse filepath
  50     filestr = os.fspath(filepath)
  51     filepath = pathlib.Path(filepath)
  52 
  53     if not ".asc" in filepath.suffixes:
  54         wt_exceptions.WrongFileTypeWarning.warn(filepath, ".asc")
  55     # parse name
  56     if not name:
  57         name = filepath.name.split(".")[0]
  58     # create data
  59     ds = np.DataSource(None)
  60     f = ds.open(filestr, "rt")
  61     axis0 = []
  62     arr = []
  63     attrs = {}
  64 
  65     line0 = f.readline().strip()[:-1]
  66     line0 = [float(x) for x in line0.split(",")]  # TODO: robust to space, tab, comma
  67     axis0.append(line0.pop(0))
  68     arr.append(line0)
  69 
  70     def get_frames(f, arr, axis0):
  71         axis0_written = False
  72         while True:
  73             line = f.readline().strip()[:-1]
  74             if len(line) == 0:
  75                 break
  76             else:
  77                 line = [float(x) for x in line.split(",")]
  78                 # signature of new frames is restart of axis0
  79                 if not axis0_written and (line[0] == axis0[0]):
  80                     axis0_written = True
  81                 if axis0_written:
  82                     line.pop(0)
  83                 else:
  84                     axis0.append(line.pop(0))
  85                 arr.append(line)
  86         return arr, axis0
  87 
  88     arr, axis0 = get_frames(f, arr, axis0)
  89     nframes = len(arr) // len(axis0)
  90 
  91     i = 0
  92     while i < 3:
  93         line = f.readline().strip()
  94         if len(line) == 0:
  95             i += 1
  96         else:
  97             try:
  98                 key, val = line.split(":", 1)
  99             except ValueError:
  100                 pass
  101             else:
  102                 attrs[key.strip()] = val.strip()
  103 
  104     f.close()
  105     created = attrs["Date and Time"]  # is this UTC?
  106     created = time.strptime(created, "%a %b %d %H:%M:%S %Y")
  107     created = timestamp.TimeStamp(time.mktime(created)).RFC3339
  108 
  109     kwargs = {"name": name, "kind": "Solis", "source": filestr, "created": created}
  110     if parent is None:
  111         data = Data(**kwargs)
  112     else:
  113         data = parent.create_data(**kwargs)
  114 
  115     axis0 = np.array(axis0)
  116     if float(attrs["Grating Groove Density (l/mm)"]) == 0:
  117         xname = "xindex"
  118         xunits = None
  119     else:
  120         xname = "wm"
  121         xunits = "nm"
  122     axes = [xname, "yindex"]
  123 
  124     if nframes == 1:
  125         arr = np.array(arr)
  126         data.create_variable(name=xname, values=axis0[:, None], units=xunits)
  127         data.create_variable(name="yindex", values=np.arange(arr.shape[-1])[None, :], units=None)
  128     else:
  129         arr = np.array(arr).reshape(nframes, len(axis0), len(arr[0]))
  130         data.create_variable(name="frame", values=np.arange(nframes)[:, None, None], units=None)
  131         data.create_variable(name=xname, values=axis0[None, :, None], units=xunits)
  132         data.create_variable(
  133             name="yindex", values=np.arange(arr.shape[-1])[None, None, :], units=None
  134         )
  135         axes = ["frame"] + axes
  136 
  137     data.transform(*axes)
  138     arr /= float(attrs["Exposure Time (secs)"])
  139     # signal has units of Hz because time normalized
  140     data.create_channel(name="signal", values=arr, signed=False, units="Hz")
  141 
  142     for key, val in attrs.items():
  143         data.attrs[key] = val
  144 
  145     # finish
  146     if verbose:
  147         print("data created at {0}".format(data.fullpath))
  148         print("  axes: {0}".format(data.axis_names))
  149         print("  shape: {0}".format(data.shape))
  150     return data
  151
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/WrightTools/data/_solis.py b/WrightTools/data/_solis.py
  --- a/WrightTools/data/_solis.py
  +++ b/WrightTools/data/_solis.py
  @@ -7,6 +7,7 @@
   import os
   import pathlib
   import time
  +import warnings
   
   import numpy as np
   
  @@ -43,8 +44,20 @@
   
       Returns
       -------
  -    data
  +    data : WrightTools.Data
           New data object.
  +        Channels: `signal`.  If exposure time is in metadata, signal is given as a count rate (Hz).
  +        Variables, Axes: `yindex` and `xindex` (no grating) or `wm` (grating)
  +
  +    Notes
  +    -----
  +    When exporting as ascii, including metadata is optional.
  +    It is _strongly recommended_ that you include metadata in exports.
  +    Metadata informs the image creation date, exposure time, and axes.
  +    However, if metadata is not present, this importer will make its best guesses to populate these fields accurately.
  +
  +    Saving processed data (e.g. vertically-binned data) in Solis software can remove/omit important metadata, so we advise exporting the raw camera images.
  +
       """
       # parse filepath
       filestr = os.fspath(filepath)
  @@ -102,9 +115,17 @@
                   attrs[key.strip()] = val.strip()
   
       f.close()
  -    created = attrs["Date and Time"]  # is this UTC?
  -    created = time.strptime(created, "%a %b %d %H:%M:%S %Y")
  -    created = timestamp.TimeStamp(time.mktime(created)).RFC3339
  +
  +    try:
  +        created = attrs["Date and Time"]  # is this UTC?
  +        created = time.strptime(created, "%a %b %d %H:%M:%S %Y")
  +        created = timestamp.TimeStamp(time.mktime(created)).RFC3339
  +    except KeyError:  # use file creation time
  +        created = os.stat(filepath).st_mtime
  +        created = timestamp.TimeStamp(created).RFC3339
  +        warnings.warn(
  +            f"{filepath.name} has no 'Date and Time' field: using file modified time instead: {created}"
  +        )
   
       kwargs = {"name": name, "kind": "Solis", "source": filestr, "created": created}
       if parent is None:
  @@ -113,7 +134,15 @@
           data = parent.create_data(**kwargs)
   
       axis0 = np.array(axis0)
  -    if float(attrs["Grating Groove Density (l/mm)"]) == 0:
  +    try:
  +        groove_density = float(attrs["Grating Groove Density (l/mm)"])
  +    except KeyError:  # assume no grating
  +        warnings.warn(
  +            f"{filepath.name} has no 'Grating Groove Density (1/mm)' field: guessing x axis units."
  +        )
  +        groove_density = isinstance(axis0[0], float)
  +
  +    if groove_density == 0:
           xname = "xindex"
           xunits = None
       else:
  @@ -135,9 +164,17 @@
           axes = ["frame"] + axes
   
       data.transform(*axes)
  -    arr /= float(attrs["Exposure Time (secs)"])
  -    # signal has units of Hz because time normalized
  -    data.create_channel(name="signal", values=arr, signed=False, units="Hz")
  +    try:
  +        exposure_time = float(attrs["Exposure Time (secs)"])
  +        if exposure_time == 0:
  +            raise ZeroDivisionError
  +        arr /= exposure_time
  +    except (KeyError, ZeroDivisionError) as e:  # do not normalize
  +        warnings.warn(f"{filepath.name} camera signal cannot be given as a count rate.")
  +        data.create_channel(name="signal", values=arr, signed=False)
  +    else:
  +        # signal has units of Hz because time normalized
  +        data.create_channel(name="signal", values=arr, signed=False, units="Hz")
   
       for key, val in attrs.items():
           data.attrs[key] = val
  
verification_info: {"golden_diff": "diff --git a/WrightTools/data/_solis.py b/WrightTools/data/_solis.py\n--- a/WrightTools/data/_solis.py\n+++ b/WrightTools/data/_solis.py\n@@ -7,6 +7,7 @@\n import os\n import pathlib\n import time\n+import warnings\n \n import numpy as np\n \n@@ -43,8 +44,20 @@\n \n     Returns\n     -------\n-    data\n+    data : WrightTools.Data\n         New data object.\n+        Channels: `signal`.  If exposure time is in metadata, signal is given as a count rate (Hz).\n+        Variables, Axes: `yindex` and `xindex` (no grating) or `wm` (grating)\n+\n+    Notes\n+    -----\n+    When exporting as ascii, including metadata is optional.\n+    It is _strongly recommended_ that you include metadata in exports.\n+    Metadata informs the image creation date, exposure time, and axes.\n+    However, if metadata is not present, this importer will make its best guesses to populate these fields accurately.\n+\n+    Saving processed data (e.g. vertically-binned data) in Solis software can remove/omit important metadata, so we advise exporting the raw camera images.\n+\n     \"\"\"\n     # parse filepath\n     filestr = os.fspath(filepath)\n@@ -102,9 +115,17 @@\n                 attrs[key.strip()] = val.strip()\n \n     f.close()\n-    created = attrs[\"Date and Time\"]  # is this UTC?\n-    created = time.strptime(created, \"%a %b %d %H:%M:%S %Y\")\n-    created = timestamp.TimeStamp(time.mktime(created)).RFC3339\n+\n+    try:\n+        created = attrs[\"Date and Time\"]  # is this UTC?\n+        created = time.strptime(created, \"%a %b %d %H:%M:%S %Y\")\n+        created = timestamp.TimeStamp(time.mktime(created)).RFC3339\n+    except KeyError:  # use file creation time\n+        created = os.stat(filepath).st_mtime\n+        created = timestamp.TimeStamp(created).RFC3339\n+        warnings.warn(\n+            f\"{filepath.name} has no 'Date and Time' field: using file modified time instead: {created}\"\n+        )\n \n     kwargs = {\"name\": name, \"kind\": \"Solis\", \"source\": filestr, \"created\": created}\n     if parent is None:\n@@ -113,7 +134,15 @@\n         data = parent.create_data(**kwargs)\n \n     axis0 = np.array(axis0)\n-    if float(attrs[\"Grating Groove Density (l/mm)\"]) == 0:\n+    try:\n+        groove_density = float(attrs[\"Grating Groove Density (l/mm)\"])\n+    except KeyError:  # assume no grating\n+        warnings.warn(\n+            f\"{filepath.name} has no 'Grating Groove Density (1/mm)' field: guessing x axis units.\"\n+        )\n+        groove_density = isinstance(axis0[0], float)\n+\n+    if groove_density == 0:\n         xname = \"xindex\"\n         xunits = None\n     else:\n@@ -135,9 +164,17 @@\n         axes = [\"frame\"] + axes\n \n     data.transform(*axes)\n-    arr /= float(attrs[\"Exposure Time (secs)\"])\n-    # signal has units of Hz because time normalized\n-    data.create_channel(name=\"signal\", values=arr, signed=False, units=\"Hz\")\n+    try:\n+        exposure_time = float(attrs[\"Exposure Time (secs)\"])\n+        if exposure_time == 0:\n+            raise ZeroDivisionError\n+        arr /= exposure_time\n+    except (KeyError, ZeroDivisionError) as e:  # do not normalize\n+        warnings.warn(f\"{filepath.name} camera signal cannot be given as a count rate.\")\n+        data.create_channel(name=\"signal\", values=arr, signed=False)\n+    else:\n+        # signal has units of Hz because time normalized\n+        data.create_channel(name=\"signal\", values=arr, signed=False, units=\"Hz\")\n \n     for key, val in attrs.items():\n         data.attrs[key] = val\n", "issue": "from_solis:  import fails when no metadata\nIt is possible to export asc image from Solis software without metadata (clearly this is not preferred, but it should be handled gracefully).  \r\n\r\nfrom_solis assumes \"Data and Time\" field exists in metadata (for attrs timestamp).  Fall back on file creation date as an alternative.   \n", "before_files": [{"content": "\"\"\"Andor.\"\"\"\n\n\n# --- import --------------------------------------------------------------------------------------\n\n\nimport os\nimport pathlib\nimport time\n\nimport numpy as np\n\nfrom ._data import Data\nfrom .. import exceptions as wt_exceptions\nfrom ..kit import _timestamp as timestamp\n\n\n# --- define --------------------------------------------------------------------------------------\n\n\n__all__ = [\"from_Solis\"]\n\n\n# --- from function -------------------------------------------------------------------------------\n\n\ndef from_Solis(filepath, name=None, parent=None, verbose=True) -> Data:\n    \"\"\"Create a data object from Andor Solis software (ascii exports).\n\n    Parameters\n    ----------\n    filepath : path-like\n        Path to file (should be .asc format).\n        Can be either a local or remote file (http/ftp).\n        Can be compressed with gz/bz2, decompression based on file name.\n    name : string (optional)\n        Name to give to the created data object. If None, filename is used.\n        Default is None.\n    parent : WrightTools.Collection (optional)\n        Collection to place new data object within. Default is None.\n    verbose : boolean (optional)\n        Toggle talkback. Default is True.\n\n    Returns\n    -------\n    data\n        New data object.\n    \"\"\"\n    # parse filepath\n    filestr = os.fspath(filepath)\n    filepath = pathlib.Path(filepath)\n\n    if not \".asc\" in filepath.suffixes:\n        wt_exceptions.WrongFileTypeWarning.warn(filepath, \".asc\")\n    # parse name\n    if not name:\n        name = filepath.name.split(\".\")[0]\n    # create data\n    ds = np.DataSource(None)\n    f = ds.open(filestr, \"rt\")\n    axis0 = []\n    arr = []\n    attrs = {}\n\n    line0 = f.readline().strip()[:-1]\n    line0 = [float(x) for x in line0.split(\",\")]  # TODO: robust to space, tab, comma\n    axis0.append(line0.pop(0))\n    arr.append(line0)\n\n    def get_frames(f, arr, axis0):\n        axis0_written = False\n        while True:\n            line = f.readline().strip()[:-1]\n            if len(line) == 0:\n                break\n            else:\n                line = [float(x) for x in line.split(\",\")]\n                # signature of new frames is restart of axis0\n                if not axis0_written and (line[0] == axis0[0]):\n                    axis0_written = True\n                if axis0_written:\n                    line.pop(0)\n                else:\n                    axis0.append(line.pop(0))\n                arr.append(line)\n        return arr, axis0\n\n    arr, axis0 = get_frames(f, arr, axis0)\n    nframes = len(arr) // len(axis0)\n\n    i = 0\n    while i < 3:\n        line = f.readline().strip()\n        if len(line) == 0:\n            i += 1\n        else:\n            try:\n                key, val = line.split(\":\", 1)\n            except ValueError:\n                pass\n            else:\n                attrs[key.strip()] = val.strip()\n\n    f.close()\n    created = attrs[\"Date and Time\"]  # is this UTC?\n    created = time.strptime(created, \"%a %b %d %H:%M:%S %Y\")\n    created = timestamp.TimeStamp(time.mktime(created)).RFC3339\n\n    kwargs = {\"name\": name, \"kind\": \"Solis\", \"source\": filestr, \"created\": created}\n    if parent is None:\n        data = Data(**kwargs)\n    else:\n        data = parent.create_data(**kwargs)\n\n    axis0 = np.array(axis0)\n    if float(attrs[\"Grating Groove Density (l/mm)\"]) == 0:\n        xname = \"xindex\"\n        xunits = None\n    else:\n        xname = \"wm\"\n        xunits = \"nm\"\n    axes = [xname, \"yindex\"]\n\n    if nframes == 1:\n        arr = np.array(arr)\n        data.create_variable(name=xname, values=axis0[:, None], units=xunits)\n        data.create_variable(name=\"yindex\", values=np.arange(arr.shape[-1])[None, :], units=None)\n    else:\n        arr = np.array(arr).reshape(nframes, len(axis0), len(arr[0]))\n        data.create_variable(name=\"frame\", values=np.arange(nframes)[:, None, None], units=None)\n        data.create_variable(name=xname, values=axis0[None, :, None], units=xunits)\n        data.create_variable(\n            name=\"yindex\", values=np.arange(arr.shape[-1])[None, None, :], units=None\n        )\n        axes = [\"frame\"] + axes\n\n    data.transform(*axes)\n    arr /= float(attrs[\"Exposure Time (secs)\"])\n    # signal has units of Hz because time normalized\n    data.create_channel(name=\"signal\", values=arr, signed=False, units=\"Hz\")\n\n    for key, val in attrs.items():\n        data.attrs[key] = val\n\n    # finish\n    if verbose:\n        print(\"data created at {0}\".format(data.fullpath))\n        print(\"  axes: {0}\".format(data.axis_names))\n        print(\"  shape: {0}\".format(data.shape))\n    return data\n", "path": "WrightTools/data/_solis.py"}], "after_files": [{"content": "\"\"\"Andor.\"\"\"\n\n\n# --- import --------------------------------------------------------------------------------------\n\n\nimport os\nimport pathlib\nimport time\nimport warnings\n\nimport numpy as np\n\nfrom ._data import Data\nfrom .. import exceptions as wt_exceptions\nfrom ..kit import _timestamp as timestamp\n\n\n# --- define --------------------------------------------------------------------------------------\n\n\n__all__ = [\"from_Solis\"]\n\n\n# --- from function -------------------------------------------------------------------------------\n\n\ndef from_Solis(filepath, name=None, parent=None, verbose=True) -> Data:\n    \"\"\"Create a data object from Andor Solis software (ascii exports).\n\n    Parameters\n    ----------\n    filepath : path-like\n        Path to file (should be .asc format).\n        Can be either a local or remote file (http/ftp).\n        Can be compressed with gz/bz2, decompression based on file name.\n    name : string (optional)\n        Name to give to the created data object. If None, filename is used.\n        Default is None.\n    parent : WrightTools.Collection (optional)\n        Collection to place new data object within. Default is None.\n    verbose : boolean (optional)\n        Toggle talkback. Default is True.\n\n    Returns\n    -------\n    data : WrightTools.Data\n        New data object.\n        Channels: `signal`.  If exposure time is in metadata, signal is given as a count rate (Hz).\n        Variables, Axes: `yindex` and `xindex` (no grating) or `wm` (grating)\n\n    Notes\n    -----\n    When exporting as ascii, including metadata is optional.\n    It is _strongly recommended_ that you include metadata in exports.\n    Metadata informs the image creation date, exposure time, and axes.\n    However, if metadata is not present, this importer will make its best guesses to populate these fields accurately.\n\n    Saving processed data (e.g. vertically-binned data) in Solis software can remove/omit important metadata, so we advise exporting the raw camera images.\n\n    \"\"\"\n    # parse filepath\n    filestr = os.fspath(filepath)\n    filepath = pathlib.Path(filepath)\n\n    if not \".asc\" in filepath.suffixes:\n        wt_exceptions.WrongFileTypeWarning.warn(filepath, \".asc\")\n    # parse name\n    if not name:\n        name = filepath.name.split(\".\")[0]\n    # create data\n    ds = np.DataSource(None)\n    f = ds.open(filestr, \"rt\")\n    axis0 = []\n    arr = []\n    attrs = {}\n\n    line0 = f.readline().strip()[:-1]\n    line0 = [float(x) for x in line0.split(\",\")]  # TODO: robust to space, tab, comma\n    axis0.append(line0.pop(0))\n    arr.append(line0)\n\n    def get_frames(f, arr, axis0):\n        axis0_written = False\n        while True:\n            line = f.readline().strip()[:-1]\n            if len(line) == 0:\n                break\n            else:\n                line = [float(x) for x in line.split(\",\")]\n                # signature of new frames is restart of axis0\n                if not axis0_written and (line[0] == axis0[0]):\n                    axis0_written = True\n                if axis0_written:\n                    line.pop(0)\n                else:\n                    axis0.append(line.pop(0))\n                arr.append(line)\n        return arr, axis0\n\n    arr, axis0 = get_frames(f, arr, axis0)\n    nframes = len(arr) // len(axis0)\n\n    i = 0\n    while i < 3:\n        line = f.readline().strip()\n        if len(line) == 0:\n            i += 1\n        else:\n            try:\n                key, val = line.split(\":\", 1)\n            except ValueError:\n                pass\n            else:\n                attrs[key.strip()] = val.strip()\n\n    f.close()\n\n    try:\n        created = attrs[\"Date and Time\"]  # is this UTC?\n        created = time.strptime(created, \"%a %b %d %H:%M:%S %Y\")\n        created = timestamp.TimeStamp(time.mktime(created)).RFC3339\n    except KeyError:  # use file creation time\n        created = os.stat(filepath).st_mtime\n        created = timestamp.TimeStamp(created).RFC3339\n        warnings.warn(\n            f\"{filepath.name} has no 'Date and Time' field: using file modified time instead: {created}\"\n        )\n\n    kwargs = {\"name\": name, \"kind\": \"Solis\", \"source\": filestr, \"created\": created}\n    if parent is None:\n        data = Data(**kwargs)\n    else:\n        data = parent.create_data(**kwargs)\n\n    axis0 = np.array(axis0)\n    try:\n        groove_density = float(attrs[\"Grating Groove Density (l/mm)\"])\n    except KeyError:  # assume no grating\n        warnings.warn(\n            f\"{filepath.name} has no 'Grating Groove Density (1/mm)' field: guessing x axis units.\"\n        )\n        groove_density = isinstance(axis0[0], float)\n\n    if groove_density == 0:\n        xname = \"xindex\"\n        xunits = None\n    else:\n        xname = \"wm\"\n        xunits = \"nm\"\n    axes = [xname, \"yindex\"]\n\n    if nframes == 1:\n        arr = np.array(arr)\n        data.create_variable(name=xname, values=axis0[:, None], units=xunits)\n        data.create_variable(name=\"yindex\", values=np.arange(arr.shape[-1])[None, :], units=None)\n    else:\n        arr = np.array(arr).reshape(nframes, len(axis0), len(arr[0]))\n        data.create_variable(name=\"frame\", values=np.arange(nframes)[:, None, None], units=None)\n        data.create_variable(name=xname, values=axis0[None, :, None], units=xunits)\n        data.create_variable(\n            name=\"yindex\", values=np.arange(arr.shape[-1])[None, None, :], units=None\n        )\n        axes = [\"frame\"] + axes\n\n    data.transform(*axes)\n    try:\n        exposure_time = float(attrs[\"Exposure Time (secs)\"])\n        if exposure_time == 0:\n            raise ZeroDivisionError\n        arr /= exposure_time\n    except (KeyError, ZeroDivisionError) as e:  # do not normalize\n        warnings.warn(f\"{filepath.name} camera signal cannot be given as a count rate.\")\n        data.create_channel(name=\"signal\", values=arr, signed=False)\n    else:\n        # signal has units of Hz because time normalized\n        data.create_channel(name=\"signal\", values=arr, signed=False, units=\"Hz\")\n\n    for key, val in attrs.items():\n        data.attrs[key] = val\n\n    # finish\n    if verbose:\n        print(\"data created at {0}\".format(data.fullpath))\n        print(\"  axes: {0}\".format(data.axis_names))\n        print(\"  shape: {0}\".format(data.shape))\n    return data\n", "path": "WrightTools/data/_solis.py"}]}