New Upstream Snapshot - python-spectral

Ready changes

Summary

Merged new upstream version: 0.23.1+git20221113.1.0659ee7 (was: 0.22.4+git20220217.1.2606503).

Resulting package

Built on 2022-12-19T08:18 (took 19m32s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-snapshots python3-spectral

Lintian Result

Diff

diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml
deleted file mode 100644
index 0209380..0000000
--- a/.github/workflows/python-package.yml
+++ /dev/null
@@ -1,41 +0,0 @@
-# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
-# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
-
-name: Unit Tests
-
-on:
-  push:
-    branches: [ master ]
-  pull_request:
-    branches: [ master ]
-
-jobs:
-  build:
-
-    runs-on: ubuntu-latest
-    strategy:
-      fail-fast: false
-      matrix:
-        python-version: [2.7, 3.6, 3.7, 3.8, 3.9]
-
-    steps:
-    - uses: actions/checkout@v2
-    - name: Set up Python ${{ matrix.python-version }}
-      uses: actions/setup-python@v2
-      with:
-        python-version: ${{ matrix.python-version }}
-    - name: Install dependencies
-      run: |
-        python -m pip install --upgrade pip
-        python -m pip install flake8 numpy pytest
-        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
-        git clone https://github.com/spectralpython/sample-data.git ~/spectral_data
-    - name: Lint with flake8
-      run: |
-        # stop the build if there are Python syntax errors or undefined names
-        flake8 . --count --select=E9,F63,F7,F822 --show-source --statistics
-        # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
-        flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
-    - name: Run unit tests
-      run: |
-        SPECTRAL_DATA=~/spectral_data python -m spectral.tests.run
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index d5d587f..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,10 +0,0 @@
-*.py[cod]
-dist/
-spectral.egg-info/
-build/
-*#
-*~
-TAGS
-.project
-.pydevproject
-spectral_test_files/
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index bc98fc3..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-language: python
-sudo: false
-
-python: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9"]
-matrix:
-  include:
-    - python: 2.6
-      dist: trusty
-    - python: 3.3
-      dist: trusty
-
-install:
-  - pip install numpy
-  - python setup.py install
-
-before_script:
-  - git clone https://github.com/spectralpython/sample-data.git ~/spectral_data
-script: SPECTRAL_DATA=~/spectral_data python -m spectral.tests.run
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..de30dcc
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,29 @@
+Metadata-Version: 2.1
+Name: spectral
+Version: 0.23.1
+Summary: Spectral Python (SPy) is a Python module for hyperspectral image processing.
+Home-page: http://spectralpython.net
+Download-URL: https://github.com/spectralpython/spectral/releases/latest
+Author: Thomas Boggs
+Author-email: thomas.boggs@gmail.com
+License: MIT
+Platform: Platform-Independent
+Classifier: Development Status :: 4 - Beta
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Environment :: Console
+Classifier: Natural Language :: English
+Classifier: Intended Audience :: Science/Research
+Classifier: Topic :: Scientific/Engineering :: Image Recognition
+Classifier: Topic :: Scientific/Engineering :: GIS
+Classifier: Topic :: Scientific/Engineering :: Information Analysis
+Classifier: Topic :: Scientific/Engineering :: Visualization
+License-File: LICENSE.txt
+
+Spectral Python (SPy) is a pure Python module for
+processing hyperspectral image data (imaging spectroscopy data). It has
+functions for reading, displaying, manipulating, and classifying hyperspectral
+imagery. SPy is Free, Open Source Software (FOSS) distributed under the MIT
+License.
diff --git a/VERSIONS.txt b/VERSIONS.txt
index 3dae2d3..4c95ca3 100644
--- a/VERSIONS.txt
+++ b/VERSIONS.txt
@@ -1,3 +1,34 @@
+================================================================================
+SPy 0.23.1
+================================================================================
+Release date: 2022.10.02
+
+Bug Fixes
+---------
+
+* [#143] Eigen{values,vectors} in a `GaussianStats` weren't sorted in
+  descencding order, which is inconsistent with `PrincipalComponents`.
+* [#144] `SpyFile.load` was failing on Windows because numpy versions
+  there did not support complex256.
+* [#145] `unmix` was failing, due to an invalid reference to "np.inv"
+
+================================================================================
+SPy 0.23
+================================================================================
+Release date: 2022.09.09
+
+Changes
+-------
+
+* `calc_stats` and `mean_cov` produce consistent results for 2D input
+* [#135] Complex data types in ENVI files are not converted to scalars
+
+Bug Fixes
+---------
+
+* [#142] Fixed incorrect outer window mean for rx, ace, and matched_filter
+* [#136, #140] Avoid deprecation warnings
+
 ================================================================================
 SPy 0.22.4
 ================================================================================
diff --git a/debian/changelog b/debian/changelog
index 52ffe86..252146f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+python-spectral (0.23.1+git20221113.1.0659ee7-1) UNRELEASED; urgency=low
+
+  * New upstream snapshot.
+  * New upstream snapshot.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Mon, 19 Dec 2022 08:07:00 -0000
+
 python-spectral (0.22.4-1) unstable; urgency=medium
 
   [ Neil Williams ]
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..8bfd5a1
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,4 @@
+[egg_info]
+tag_build = 
+tag_date = 0
+
diff --git a/spectral.egg-info/PKG-INFO b/spectral.egg-info/PKG-INFO
new file mode 100644
index 0000000..de30dcc
--- /dev/null
+++ b/spectral.egg-info/PKG-INFO
@@ -0,0 +1,29 @@
+Metadata-Version: 2.1
+Name: spectral
+Version: 0.23.1
+Summary: Spectral Python (SPy) is a Python module for hyperspectral image processing.
+Home-page: http://spectralpython.net
+Download-URL: https://github.com/spectralpython/spectral/releases/latest
+Author: Thomas Boggs
+Author-email: thomas.boggs@gmail.com
+License: MIT
+Platform: Platform-Independent
+Classifier: Development Status :: 4 - Beta
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Environment :: Console
+Classifier: Natural Language :: English
+Classifier: Intended Audience :: Science/Research
+Classifier: Topic :: Scientific/Engineering :: Image Recognition
+Classifier: Topic :: Scientific/Engineering :: GIS
+Classifier: Topic :: Scientific/Engineering :: Information Analysis
+Classifier: Topic :: Scientific/Engineering :: Visualization
+License-File: LICENSE.txt
+
+Spectral Python (SPy) is a pure Python module for
+processing hyperspectral image data (imaging spectroscopy data). It has
+functions for reading, displaying, manipulating, and classifying hyperspectral
+imagery. SPy is Free, Open Source Software (FOSS) distributed under the MIT
+License.
diff --git a/spectral.egg-info/SOURCES.txt b/spectral.egg-info/SOURCES.txt
new file mode 100644
index 0000000..f536250
--- /dev/null
+++ b/spectral.egg-info/SOURCES.txt
@@ -0,0 +1,92 @@
+LICENSE.txt
+MANIFEST.in
+README.rst
+VERSIONS.txt
+setup.py
+spectral/__init__.py
+spectral/config.py
+spectral/image.py
+spectral/spectral.py
+spectral.egg-info/PKG-INFO
+spectral.egg-info/SOURCES.txt
+spectral.egg-info/dependency_links.txt
+spectral.egg-info/requires.txt
+spectral.egg-info/top_level.txt
+spectral/algorithms/__init__.py
+spectral/algorithms/algorithms.py
+spectral/algorithms/classifiers.py
+spectral/algorithms/clustering.py
+spectral/algorithms/continuum.py
+spectral/algorithms/detectors.py
+spectral/algorithms/perceptron.py
+spectral/algorithms/resampling.py
+spectral/algorithms/spatial.py
+spectral/algorithms/spymath.py
+spectral/algorithms/transforms.py
+spectral/database/__init__.py
+spectral/database/aster.py
+spectral/database/ecostress.py
+spectral/database/spectral_database.py
+spectral/database/usgs.py
+spectral/graphics/__init__.py
+spectral/graphics/colorscale.py
+spectral/graphics/graphics.py
+spectral/graphics/hypercube.py
+spectral/graphics/ndwindow.py
+spectral/graphics/rasterwindow.py
+spectral/graphics/spygnuplot.py
+spectral/graphics/spypylab.py
+spectral/graphics/spywxpython.py
+spectral/graphics/spywxpythonthread.py
+spectral/io/__init__.py
+spectral/io/aviris.py
+spectral/io/bilfile.py
+spectral/io/bipfile.py
+spectral/io/bsqfile.py
+spectral/io/envi.py
+spectral/io/erdas.py
+spectral/io/spyfile.py
+spectral/tests/__init__.py
+spectral/tests/classifiers.py
+spectral/tests/continuum.py
+spectral/tests/database.py
+spectral/tests/detectors.py
+spectral/tests/dimensionality.py
+spectral/tests/envi.py
+spectral/tests/iterators.py
+spectral/tests/memmap.py
+spectral/tests/run.py
+spectral/tests/spatial.py
+spectral/tests/spyfile.py
+spectral/tests/spymath.py
+spectral/tests/spytest.py
+spectral/tests/transforms.py
+spectral/tests/data/92AV3C.spc
+spectral/tests/data/ecostress/a.spectrum.txt
+spectral/tests/data/ecostress/b.spectrum.txt
+spectral/tests/data/ecostress/c.spectrum.txt
+spectral/tests/data/usgs/ASCIIdata/liba/liba_Bandpass_(FWHM)_ASDFR_SR.txt
+spectral/tests/data/usgs/ASCIIdata/liba/liba_Bandpass_(FWHM)_AVIRIS_1996_um.txt
+spectral/tests/data/usgs/ASCIIdata/liba/liba_Bandpass_(FWHM)_BECK_Beckman_um.txt
+spectral/tests/data/usgs/ASCIIdata/liba/liba_Bandpass_(FWHM)_NIC4_Nicolet_um.txt
+spectral/tests/data/usgs/ASCIIdata/liba/liba_Wavelengths_ASD_0.35-2.5_um.txt
+spectral/tests/data/usgs/ASCIIdata/liba/liba_Wavelengths_AVIRIS_1996_0.37-2.5_um.txt
+spectral/tests/data/usgs/ASCIIdata/liba/liba_Wavelengths_BECK_Beckman_0.2-3.0_um.txt
+spectral/tests/data/usgs/ASCIIdata/liba/liba_Wavelengths_NIC4_Nicolet_1.12-216um.txt
+spectral/tests/data/usgs/ASCIIdata/liba/ChapterB_b0/liba_Material_a_b0_0_ASDFRa_AREF.txt
+spectral/tests/data/usgs/ASCIIdata/liba/ChapterB_b0/liba_Material_a_b0_1_NIC4a_RREF.txt
+spectral/tests/data/usgs/ASCIIdata/liba/ChapterB_b0/liba_Material_a_b0_2-way_trans_RefStd_NIC4aa_TRAN.txt
+spectral/tests/data/usgs/ASCIIdata/liba/ChapterD_d0/liba_MaterialD_00_AVIRISb_RTGC.txt
+spectral/tests/data/usgs/ASCIIdata/liba/ChapterD_d0/liba_MaterialD_01_BECKa_AREF.txt
+spectral/tests/data/usgs/ASCIIdata/libc/libc_Bandpass_(FWHM)_Landsat8_(7_bands)_nm.txt
+spectral/tests/data/usgs/ASCIIdata/libc/libc_Bandpass_(FWHM)_Landsat8_(7_bands)_um.txt
+spectral/tests/data/usgs/ASCIIdata/libc/libc_SRF_Band_2_Landsat8_Blue.txt
+spectral/tests/data/usgs/ASCIIdata/libc/libc_Wavelengths_Landsat8_(7_bands)_microns.txt
+spectral/tests/data/usgs/ASCIIdata/libc/libc_Wavelengths_Landsat8oli_SpecRespFunction.txt
+spectral/tests/data/usgs/ASCIIdata/libc/ChapterB_b0/libc_Material_a_b0_0_ASDFRa_AREF.txt
+spectral/tests/data/usgs/ASCIIdata/libc/ChapterD_d0/libc_MaterialD_1_ASDFRa_AREF.txt
+spectral/tests/data/usgs/ASCIIdata/libc/ChapterD_d0/libc_MaterialD_2_AVIRISb_RTGC.txt
+spectral/utilities/__init__.py
+spectral/utilities/errors.py
+spectral/utilities/python23.py
+spectral/utilities/status.py
\ No newline at end of file
diff --git a/spectral.egg-info/dependency_links.txt b/spectral.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/spectral.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/spectral.egg-info/requires.txt b/spectral.egg-info/requires.txt
new file mode 100644
index 0000000..24ce15a
--- /dev/null
+++ b/spectral.egg-info/requires.txt
@@ -0,0 +1 @@
+numpy
diff --git a/spectral.egg-info/top_level.txt b/spectral.egg-info/top_level.txt
new file mode 100644
index 0000000..7e1faa4
--- /dev/null
+++ b/spectral.egg-info/top_level.txt
@@ -0,0 +1 @@
+spectral
diff --git a/spectral/__init__.py b/spectral/__init__.py
index 43a5f18..a8f5046 100644
--- a/spectral/__init__.py
+++ b/spectral/__init__.py
@@ -4,7 +4,7 @@ Basic package setup and global imports.
 
 from __future__ import absolute_import, division, print_function, unicode_literals
 
-__version__ = '0.22.4'
+__version__ = '0.23.1'
 
 import sys
 if sys.byteorder == 'little':
@@ -16,6 +16,8 @@ BSQ = 0
 BIL = 1
 BIP = 2
 
+COMPLEX_SIZES = [64, 128, 256]
+
 from .utilities.errors import SpyException
 from .config import SpySettings, spy_colors
 settings = SpySettings()
diff --git a/spectral/algorithms/algorithms.py b/spectral/algorithms/algorithms.py
index 88752ab..567a5c5 100644
--- a/spectral/algorithms/algorithms.py
+++ b/spectral/algorithms/algorithms.py
@@ -171,8 +171,8 @@ def mean_cov(image, mask=None, index=None):
 
         `image` (ndarrray, :class:`~spectral.Image`, or :class:`spectral.Iterator`):
 
-            If an ndarray, it should have shape `MxNxB` and the mean &
-            covariance will be calculated for each band (third dimension).
+            If an ndarray, it should have 2 or 3 dimensions and the mean &
+            covariance will be calculated for the last dimension.
 
         `mask` (ndarray):
 
@@ -214,6 +214,10 @@ def mean_cov(image, mask=None, index=None):
         X = image.astype(np.float64)
         if X.ndim == 3:
             X = image.reshape(-1, image.shape[-1]).T
+        elif X.ndim == 2:
+            X = image.T
+        else:
+            raise ValueError('ndarray must have 2 or 3 dimensions.')
         if mask is not None:
             mask = mask.ravel()
             if index is not None:
@@ -782,6 +786,10 @@ class GaussianStats(object):
     def principal_components(self):
         if self._pcs is None:
             (evals, evecs) = np.linalg.eigh(self._cov)
+            # numpy says eigenvalues may not be sorted so we'll sort them.
+            ii = list(reversed(np.argsort(evals)))
+            evals = evals[ii]
+            evecs = evecs[:, ii]
             self._pcs = PrincipalComponents(evals, evecs, self)
         return self._pcs
 
@@ -813,8 +821,8 @@ def calc_stats(image, mask=None, index=None, allow_nan=False):
 
         `image` (ndarrray, :class:`~spectral.Image`, or :class:`spectral.Iterator`):
 
-            If an ndarray, it should have shape `MxNxB` and the mean &
-            covariance will be calculated for each band (third dimension).
+            If an ndarray, it should have 2 or 3 dimensions and the mean &
+            covariance will be calculated for the last dimension.
 
         `mask` (ndarray):
 
@@ -1204,11 +1212,11 @@ def bdist_terms(a, b):
                             A 2-tuple of the linear and quadratic terms
     '''
     m = a.stats.mean - b.stats.mean
-    avgCov = (a.stats.cov + b.stats.cov) / 2
+    avg_cov = (a.stats.cov + b.stats.cov) / 2
 
-    lin_term = (1 / 8.) * np.dot(np.transpose(m), np.dot(np.inv(avgCov), m))
+    lin_term = (1 / 8.) * np.dot(np.transpose(m), np.dot(np.linalg.inv(avg_cov), m))
 
-    quad_term = 0.5 * (log_det(avgCov)
+    quad_term = 0.5 * (log_det(avg_cov)
                        - 0.5 * a.stats.log_det_cov
                        - 0.5 * b.stats.log_det_cov)
 
@@ -1313,7 +1321,7 @@ def unmix(data, members):
     members = members.astype(float)
     # Calculate the pseudo inverse
     pi = np.dot(members, np.transpose(members))
-    pi = np.dot(np.inv(pi), members)
+    pi = np.dot(np.linalg.inv(pi), members)
 
     (M, N, B) = data.shape
     unmixed = np.zeros((M, N, members.shape[0]), float)
diff --git a/spectral/algorithms/spatial.py b/spectral/algorithms/spatial.py
index 5b4b4e6..e94b75c 100644
--- a/spectral/algorithms/spatial.py
+++ b/spectral/algorithms/spatial.py
@@ -472,8 +472,8 @@ class WindowedGaussianBackgroundMapper(object):
                     mean_out = np.mean(image[outer[0]: outer[1],
                                              outer[2]: outer[3]].reshape(-1, B),
                                              axis=0)
-                    mean_in = np.mean(image[outer[0]: outer[1],
-                                            outer[2]: outer[3]].reshape(-1, B),
+                    mean_in = np.mean(image[inner[0]: inner[1],
+                                            inner[2]: inner[3]].reshape(-1, B),
                                             axis=0)
                     mean = mean_out * (float(N_tot) / (N_tot - N_in)) - \
                            mean_in * (float(N_in) / (N_tot - N_in))
diff --git a/spectral/algorithms/transforms.py b/spectral/algorithms/transforms.py
index ba06035..fb068a6 100644
--- a/spectral/algorithms/transforms.py
+++ b/spectral/algorithms/transforms.py
@@ -4,7 +4,10 @@ Base classes for various types of transforms.
 
 from __future__ import absolute_import, division, print_function, unicode_literals
 
-import collections
+try:
+    from collections.abc import Callable
+except:
+    from collections import Callable
 import numpy as np
 
 
@@ -85,7 +88,7 @@ class LinearTransform:
         __init__.
         '''
         if not isinstance(X, np.ndarray):
-            if hasattr(X, 'transform') and isinstance(X.transform, collections.Callable):
+            if hasattr(X, 'transform') and isinstance(X.transform, Callable):
                 return X.transform(self)
             else:
                 raise TypeError('Unable to apply transform to object.')
diff --git a/spectral/database/ecostress.py b/spectral/database/ecostress.py
index 664c13b..6c2c08b 100644
--- a/spectral/database/ecostress.py
+++ b/spectral/database/ecostress.py
@@ -194,7 +194,7 @@ class EcostressDatabase(AsterDatabase):
                                   s['particle size'], sampleNum, s['owner'],
                                   s['origin'], phase, s['description'])
 
-            instrument = os.path.basename(f).split('.')[1]
+            instrument = os.path.basename(f).split('.')[-3]
             environment = 'lab'
             m = sig.measurement
 
diff --git a/spectral/graphics/rasterwindow.py b/spectral/graphics/rasterwindow.py
index 2a51e53..f23ce50 100644
--- a/spectral/graphics/rasterwindow.py
+++ b/spectral/graphics/rasterwindow.py
@@ -8,6 +8,8 @@ import logging
 import wx
 from spectral.graphics.graphics import SpyWindow
 
+from ..utilities.python23 import tobytes
+
 logger = logging.getLogger('spectral')
 
 class RasterWindow(wx.Frame, SpyWindow):
@@ -26,7 +28,7 @@ class RasterWindow(wx.Frame, SpyWindow):
 
         img = wx.EmptyImage(rgb.shape[0], rgb.shape[1])
         img = wx.EmptyImage(rgb.shape[1], rgb.shape[0])
-        img.SetData(rgb.tostring())
+        img.SetData(tobytes(rgb))
         self.bmp = img.ConvertToBitmap()
         self.kwargs = kwargs
         wx.Frame.__init__(self, parent, index, title,
diff --git a/spectral/image.py b/spectral/image.py
index d51f1b2..be3449d 100644
--- a/spectral/image.py
+++ b/spectral/image.py
@@ -118,11 +118,11 @@ class ImageArray(np.ndarray, Image):
     def _parent_getitem(self, args):
         return np.ndarray.__getitem__(self, args)
 
-    def read_band(self, i):
+    def read_band(self, band):
         '''
         For compatibility with SpyFile objects. Returns arr[:,:,i].squeeze()
         '''
-        return np.asarray(self[:, :, i].squeeze())
+        return np.asarray(self[:, :, band].squeeze())
 
     def read_bands(self, bands):
         '''For SpyFile compatibility. Equivlalent to arr.take(bands, 2)'''
@@ -161,7 +161,7 @@ class ImageArray(np.ndarray, Image):
 
     def read_datum(self, i, j, k):
         '''For SpyFile compatibility. Equivlalent to arr[i, j, k]'''
-        return np.asscalar(self[i, j, k])
+        return self[i, j, k]
 
     def load(self):
         '''For compatibility with SpyFile objects. Returns self'''
diff --git a/spectral/io/envi.py b/spectral/io/envi.py
index 0846624..fc00d2b 100644
--- a/spectral/io/envi.py
+++ b/spectral/io/envi.py
@@ -23,7 +23,7 @@ import warnings
 
 import spectral as spy
 from ..spectral import BandInfo
-from ..utilities.python23 import IS_PYTHON3, is_string
+from ..utilities.python23 import IS_PYTHON3, is_string, tobytes
 from ..utilities.errors import SpyException
 from .bilfile import BilFile
 from .bipfile import BipFile
@@ -681,7 +681,7 @@ def _write_image(hdr_file, data, header, **kwargs):
     # bufsize = data.shape[0] * data.shape[1] * np.dtype(dtype).itemsize
     bufsize = data.shape[0] * data.shape[1] * data.dtype.itemsize
     fout = builtins.open(img_file, 'wb', bufsize)
-    fout.write(data.tostring())
+    fout.write(tobytes(data))
     fout.close()
 
 
diff --git a/spectral/io/spyfile.py b/spectral/io/spyfile.py
index 0619ae3..8e435de 100644
--- a/spectral/io/spyfile.py
+++ b/spectral/io/spyfile.py
@@ -196,7 +196,14 @@ class SpyFile(Image):
         for k in list(kwargs.keys()):
             if k not in ('dtype', 'scale'):
                 raise ValueError('Invalid keyword %s.' % str(k))
-        dtype = kwargs.get('dtype', ImageArray.format)
+        cnames = ['complex{}'.format(s) for s in spy.COMPLEX_SIZES]
+        ctypes = [np.dtype(n).name for n in cnames if hasattr(np, n)]
+        if 'dtype' in kwargs:
+            dtype = kwargs['dtype']
+        elif np.dtype(self.dtype).name in ctypes:
+            dtype = self.dtype
+        else:
+            dtype = ImageArray.format
         data = array.array(typecode('b'))
         self.fid.seek(self.offset)
         data.fromfile(self.fid, self.nrows * self.ncols *
@@ -210,7 +217,8 @@ class SpyFile(Image):
             npArray = npArray.transpose([1, 2, 0])
         else:
             npArray.shape = (self.nrows, self.ncols, self.nbands)
-        npArray = npArray.astype(dtype)
+        if np.dtype(dtype).name != npArray.dtype.name:
+            npArray = npArray.astype(dtype)
         if self.scale_factor != 1 and kwargs.get('scale', True):
             npArray = npArray / float(self.scale_factor)
         imarray = ImageArray(npArray, self)
diff --git a/spectral/tests/data/usgs/ASCIIdata/libc/errorbars/ignore.txt b/spectral/tests/data/usgs/ASCIIdata/libc/errorbars/ignore.txt
deleted file mode 100644
index a3252f2..0000000
--- a/spectral/tests/data/usgs/ASCIIdata/libc/errorbars/ignore.txt
+++ /dev/null
@@ -1 +0,0 @@
-THIS_SHOULD_NOT_BE_PARSED
diff --git a/spectral/tests/spyfile.py b/spectral/tests/spyfile.py
index 6ac8981..54f7889 100644
--- a/spectral/tests/spyfile.py
+++ b/spectral/tests/spyfile.py
@@ -17,17 +17,19 @@ from __future__ import division, print_function, unicode_literals
 import itertools
 import numpy as np
 import os
-
+import warnings
 
 import spectral as spy
 from spectral.io.spyfile import find_file_path, FileNotFoundError, SpyFile
 from spectral.tests import testdir
 from spectral.tests.spytest import SpyTest
 
+ENVI_COMPLEX_TEST_SIZES = [64, 28]
+
+assert_almost_equal = np.testing.assert_allclose
 
-def assert_almost_equal(a, b, **kwargs):
-    if not np.allclose(a, b, **kwargs):
-        raise Exception('NOPE')
+def assert_allclose (a, b, **kwargs):
+    np.testing.assert_allclose(np.array(a), np.array(b), **kwargs)
 
 class SpyFileTest(SpyTest):
     '''Tests that SpyFile methods read data correctly from files.'''
@@ -144,14 +146,14 @@ class SpyFileTest(SpyTest):
         data = self.image.load()
         spyf = self.image
 
-        load_assert = np.allclose
+        load_assert = assert_allclose
         load_assert(data[i, j, k], self.value)
         first_band = spyf[:, :, 0]
         load_assert(data[:, :, 0], first_band)
         # This is checking if different ImageArray and SpyFile indexing
         # results are the same shape, so we can't just reuse the already
         # loaded first band.
-        load_assert(data[:, 0, 0], spyf[:, 0, 0])
+        load_assert(data[:, 0, 0].squeeze(), spyf[:, 0, 0].squeeze())
         load_assert(data[0, 0, 0], spyf[0, 0, 0])
         load_assert(data[0, 0], spyf[0, 0])
         load_assert(data[-1, -1, -1], spyf[-1, -1, -1])
@@ -267,7 +269,7 @@ class SpyFileTestSuite(object):
             os.mkdir(testdir)
         image = spy.open_image(self.filename)
         basename = os.path.join(testdir,
-                                os.path.splitext(self.filename)[0])
+                                os.path.splitext(os.path.split(self.filename)[-1])[0])
         interleaves = ('bil', 'bip', 'bsq')
         ends = ('big', 'little')
         cases = itertools.product(interleaves, self.dtypes, ends)
@@ -298,17 +300,51 @@ class SpyFileTestSuite(object):
                 test = SpyFileTest(testimg, self.datum, self.value)
                 test.run()
 
+def create_complex_test_files(dtypes):
+    '''Create test files with complex data'''
+    if not os.path.isdir(testdir):
+        os.mkdir(testdir)
+    tests = []
+    shape = (100, 200, 64)
+    datum = (33, 44, 25)
+    for t in dtypes:
+        X = np.array(np.random.rand(*shape) + 1j * np.random.rand(*shape),
+                     dtype=t)
+        fname = os.path.join(testdir, 'test_{}.hdr'.format(t))
+        spy.envi.save_image(fname, X)
+        tests.append((fname, datum, X[datum]))
+    return tests
 
 def run():
     tests = [('92AV3C.lan', (99, 99, 99), 2057.0)]
-#    tests = [('92AV3C.lan', (99, 99, 99), 2057.0),
-#             ('f970619t01p02_r02_sc04.a.rfl', (99, 99, 99), 0.2311),
-#             ('cup95eff.int.hdr', (99, 99, 33), 0.1842)]
     for (fname, datum, value) in tests:
         try:
             check = find_file_path(fname)
             suite = SpyFileTestSuite(fname, datum, value,
-                                     dtypes=('i2', 'i4', 'f4', 'f8'))
+                                     dtypes=('i2', 'i4', 'f4', 'f8', 'c8', 'c16'))
+            suite.run()
+        except FileNotFoundError:
+            print('File "%s" not found. Skipping.' % fname)
+
+    # Run tests for complex data types
+
+    # Only test complex sizes supported by numpy and ENVI.
+    dtypes = []
+    for s in [s for s in spy.COMPLEX_SIZES if s in ENVI_COMPLEX_TEST_SIZES]:
+        t = 'complex{}'.format(s)
+        if hasattr(np, t):
+            dtypes.append(t)
+        else:
+            # This is unlikely to happen because numpy currently supports
+            # more complex types than ENVI
+            warnings.warn('numpy does not support {}. Skipping test.'.format(t))
+
+    tests = create_complex_test_files(dtypes)
+    for (dtype, (fname, datum, value)) in zip(dtypes, tests):
+        try:
+            check = find_file_path(fname)
+            suite = SpyFileTestSuite(fname, datum, value,
+                                     dtypes=(dtype,))
             suite.run()
         except FileNotFoundError:
             print('File "%s" not found. Skipping.' % fname)
diff --git a/spectral/tests/spytest.py b/spectral/tests/spytest.py
index 957b371..5ae61c6 100644
--- a/spectral/tests/spytest.py
+++ b/spectral/tests/spytest.py
@@ -4,7 +4,10 @@ Base class for all tests.
 
 from __future__ import absolute_import, division, print_function, unicode_literals
 
-import collections
+try:
+    from collections.abc import Callable
+except:
+    from collections import Callable
 import sys
 
 class SpyTest(object):
@@ -39,7 +42,7 @@ class SpyTest(object):
                 pass
         null = NullStdOut()
         methods = [getattr(self, s) for s in sorted(dir(self)) if s.startswith('test_')]
-        methods = [m for m in methods if isinstance(m, collections.Callable)]
+        methods = [m for m in methods if isinstance(m, Callable)]
         stdout = sys.stdout
         for method in methods:
             print(format('Testing ' + method.__name__.split('_', 1)[-1],
diff --git a/spectral/tests/test_template.txt b/spectral/tests/test_template.txt
deleted file mode 100644
index 55daf48..0000000
--- a/spectral/tests/test_template.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-'''
-Runs unit tests for XXX.
-
-To run the unit tests, type the following from the system command line:
-
-    # python -m spectral.tests.XXX
-'''
-
-from __future__ import division, print_function, unicode_literals
-
-import numpy as np
-
-from numpy.testing import assert_allclose
-from spectral.tests.spytest import SpyTest
-
-
-class FooTest(SpyTest):
-    '''Tests various math functions.'''
-
-    def setup(self):
-        pass
-
-    def test_foo(self):
-        assert_allclose(1, 1)
-
-
-def run():
-    print('\n' + '-' * 72)
-    print('Running XXX tests.')
-    print('-' * 72)
-    test = FooTest()
-    test.run()
-
-if __name__ == '__main__':
-    from spectral.tests.run import parse_args, reset_stats, print_summary
-    parse_args()
-    reset_stats()
-    run()
-    print_summary()

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/lib/python3/dist-packages/spectral-0.23.1.egg-info/PKG-INFO
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/spectral-0.23.1.egg-info/dependency_links.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/spectral-0.23.1.egg-info/requires.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/spectral-0.23.1.egg-info/top_level.txt

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/lib/python3/dist-packages/spectral-0.22.4.egg-info/PKG-INFO
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/spectral-0.22.4.egg-info/dependency_links.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/spectral-0.22.4.egg-info/requires.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/spectral-0.22.4.egg-info/top_level.txt

No differences were encountered in the control files

More details

Full run details