Repository: skypyproject/skypy

Issue:
Tests that require skypy-data are not skipped if it is not installed
**Describe the bug**
The tests [`test_load_spectral_data`](https://github.com/skypyproject/skypy/blob/master/skypy/galaxy/tests/test_spectrum.py) and [`test_spectral_data_input`](https://github.com/skypyproject/skypy/blob/master/skypy/utils/tests/test_decorators.py) require [`skypy-data`](https://github.com/skypyproject/skypy-data) but are not skipped if it is not installed leading to test failures.

**Expected behaviour**
These tests should be skipped if `skypy-data` is not installed. As an example see how the `HAS_SPECUITLS` flag is used in [`test_spectrum.py`](https://github.com/skypyproject/skypy/blob/master/skypy/galaxy/tests/test_spectrum.py) to similarly skip some tests when `specutils` is no installed.

**To Reproduce**
```
pip install skypy==0.3rc2 pytest-astropy pytest-rerunfailures specutils
pytest --pyargs skypy.galaxy.tests.test_spectrum skypy.utils.tests.test_decorators
```

Discussion:

Patch:
diff --git a/skypy/galaxy/_spectrum_loaders.py b/skypy/galaxy/_spectrum_loaders.py
index 1c7d01e..e66cc54 100644
--- a/skypy/galaxy/_spectrum_loaders.py
+++ b/skypy/galaxy/_spectrum_loaders.py
@@ -1,7 +1,6 @@
 '''Implementations for spectrum loaders.'''
 
 import numpy as np
-import specutils
 import astropy.utils.data
 import astropy.table
 from astropy import __version__ as astropy_version
@@ -11,6 +10,13 @@ import os
 import urllib
 from pkg_resources import resource_filename
 
+# this file is only ever imported when specutils is present
+# but without the try/except pytest will fail when doctests are discovered
+try:
+    import specutils
+except ImportError:
+    pass
+
 
 def download_file(url, cache=True):
     '''download_file with some specific settings'''
diff --git a/skypy/galaxy/spectrum.py b/skypy/galaxy/spectrum.py
index 5083aa7..8b4a400 100644
--- a/skypy/galaxy/spectrum.py
+++ b/skypy/galaxy/spectrum.py
@@ -14,6 +14,20 @@ __all__ = [
     'magnitudes_from_templates',
 ]
 
+try:
+    __import__('specutils')
+except ImportError:
+    HAS_SPECUTILS = False
+else:
+    HAS_SPECUTILS = True
+
+try:
+    __import__('skypy-data')
+except ImportError:
+    HAS_SKYPY_DATA = False
+else:
+    HAS_SKYPY_DATA = True
+
 
 def dirichlet_coefficients(redshift, alpha0, alpha1, z1=1., weight=None):
     r"""Dirichlet-distributed SED coefficients.
@@ -141,7 +155,7 @@ def mag_ab(spectrum, bandpass, redshift=None):
     Get B-band magnitudes for the kcorrect spec templaces using auto-loading
     of known spectral data:
     >>> from skypy.galaxy.spectrum import mag_ab
-    >>> mag_B = mag_ab('kcorrect_spec', 'Johnson_B')
+    >>> mag_B = mag_ab('kcorrect_spec', 'Johnson_B')  # doctest: +SKIP
 
     '''
 


Test patch:
diff --git a/skypy/galaxy/tests/test_spectrum.py b/skypy/galaxy/tests/test_spectrum.py
index 961a8ec..06dacf9 100644
--- a/skypy/galaxy/tests/test_spectrum.py
+++ b/skypy/galaxy/tests/test_spectrum.py
@@ -1,13 +1,7 @@
 import numpy as np
 import scipy.stats
 import pytest
-
-try:
-    import specutils
-except ImportError:
-    HAS_SPECUTILS = False
-else:
-    HAS_SPECUTILS = True
+from skypy.galaxy.spectrum import HAS_SPECUTILS, HAS_SKYPY_DATA
 
 
 @pytest.mark.flaky
@@ -74,18 +68,18 @@ def test_sampling_coefficients():
 def test_mag_ab_standard_source():
 
     from astropy import units
-
+    from specutils import Spectrum1D
     from skypy.galaxy.spectrum import mag_ab
 
     # create a bandpass
     bp_lam = np.logspace(0, 4, 1000)*units.AA
     bp_tx = np.exp(-((bp_lam - 1000*units.AA)/(100*units.AA))**2)*units.dimensionless_unscaled
-    bp = specutils.Spectrum1D(spectral_axis=bp_lam, flux=bp_tx)
+    bp = Spectrum1D(spectral_axis=bp_lam, flux=bp_tx)
 
     # test that the AB standard source has zero magnitude
     lam = np.logspace(0, 4, 1000)*units.AA
     flam = 0.10884806248538730623*units.Unit('erg s-1 cm-2 AA')/lam**2
-    spec = specutils.Spectrum1D(spectral_axis=lam, flux=flam)
+    spec = Spectrum1D(spectral_axis=lam, flux=flam)
 
     m = mag_ab(spec, bp)
 
@@ -96,18 +90,18 @@ def test_mag_ab_standard_source():
 def test_mag_ab_redshift_dependence():
 
     from astropy import units
-
+    from specutils import Spectrum1D
     from skypy.galaxy.spectrum import mag_ab
 
     # make a wide tophat bandpass
     bp_lam = np.logspace(-10, 10, 3)*units.AA
     bp_tx = np.ones(3)*units.dimensionless_unscaled
-    bp = specutils.Spectrum1D(spectral_axis=bp_lam, flux=bp_tx)
+    bp = Spectrum1D(spectral_axis=bp_lam, flux=bp_tx)
 
     # create a narrow gaussian source
     lam = np.logspace(0, 3, 1000)*units.AA
     flam = np.exp(-((lam - 100*units.AA)/(10*units.AA))**2)*units.Unit('erg s-1 cm-2 AA-1')
-    spec = specutils.Spectrum1D(spectral_axis=lam, flux=flam)
+    spec = Spectrum1D(spectral_axis=lam, flux=flam)
 
     # array of redshifts
     z = np.linspace(0, 1, 11)
@@ -124,6 +118,7 @@ def test_mag_ab_multi():
 
     from astropy import units
     from skypy.galaxy.spectrum import mag_ab
+    from specutils import Spectrum1D
 
     # 5 redshifts
     z = np.linspace(0, 1, 5)
@@ -133,13 +128,13 @@ def test_mag_ab_multi():
     bp_mean = np.array([[1000], [2000]]) * units.AA
     bp_width = np.array([[100], [10]]) * units.AA
     bp_tx = np.exp(-((bp_lam-bp_mean)/bp_width)**2)*units.dimensionless_unscaled
-    bp = specutils.Spectrum1D(spectral_axis=bp_lam, flux=bp_tx)
+    bp = Spectrum1D(spectral_axis=bp_lam, flux=bp_tx)
 
     # 3 Flat Spectra
     lam = np.logspace(0, 4, 1000)*units.AA
     A = np.array([[2], [3], [4]])
     flam = A * 0.10884806248538730623*units.Unit('erg s-1 cm-2 AA')/lam**2
-    spec = specutils.Spectrum1D(spectral_axis=lam, flux=flam)
+    spec = Spectrum1D(spectral_axis=lam, flux=flam)
 
     # Compare calculated magnitudes with truth
     magnitudes = mag_ab(spec, bp, z)
@@ -154,17 +149,18 @@ def test_template_spectra():
     from astropy import units
     from skypy.galaxy.spectrum import mag_ab, magnitudes_from_templates
     from astropy.cosmology import Planck15
+    from specutils import Spectrum1D
 
     # 3 Flat Templates
     lam = np.logspace(0, 4, 1000)*units.AA
     A = np.array([[2], [3], [4]])
     flam = A * 0.10884806248538730623*units.Unit('erg s-1 cm-2 AA')/lam**2
-    spec = specutils.Spectrum1D(spectral_axis=lam, flux=flam)
+    spec = Spectrum1D(spectral_axis=lam, flux=flam)
 
     # Gaussian bandpass
     bp_lam = np.logspace(0, 4, 1000)*units.AA
     bp_tx = np.exp(-((bp_lam - 1000*units.AA)/(100*units.AA))**2)*units.dimensionless_unscaled
-    bp = specutils.Spectrum1D(spectral_axis=bp_lam, flux=bp_tx)
+    bp = Spectrum1D(spectral_axis=bp_lam, flux=bp_tx)
 
     # Each test galaxy is exactly one of the templates
     coefficients = np.diag(np.ones(3))
@@ -198,19 +194,20 @@ def test_stellar_mass_from_reference_band():
 
     from astropy import units
     from skypy.galaxy.spectrum import mag_ab, stellar_mass_from_reference_band
+    from specutils import Spectrum1D
 
     # Gaussian bandpass
     bp_lam = np.logspace(0, 4, 1000) * units.AA
     bp_mean = 1000 * units.AA
     bp_width = 100 * units.AA
     bp_tx = np.exp(-((bp_lam-bp_mean)/bp_width)**2)*units.dimensionless_unscaled
-    band = specutils.Spectrum1D(spectral_axis=bp_lam, flux=bp_tx)
+    band = Spectrum1D(spectral_axis=bp_lam, flux=bp_tx)
 
     # 3 Flat template spectra
     lam = np.logspace(0, 4, 1000)*units.AA
     A = np.array([[2], [3], [4]])
     flam = A * 0.10884806248538730623*units.Unit('erg s-1 cm-2 AA')/lam**2
-    templates = specutils.Spectrum1D(spectral_axis=lam, flux=flam)
+    templates = Spectrum1D(spectral_axis=lam, flux=flam)
 
     # Absolute magnitudes for each template
     Mt = mag_ab(templates, band)
@@ -231,7 +228,8 @@ def test_stellar_mass_from_reference_band():
     np.testing.assert_allclose(stellar_mass, truth)
 
 
-@pytest.mark.skipif(not HAS_SPECUTILS, reason='test requires specutils')
+@pytest.mark.skipif(not HAS_SPECUTILS or not HAS_SKYPY_DATA,
+                    reason='test requires specutils and skypy-data')
 def test_load_spectral_data():
 
     from skypy.galaxy.spectrum import load_spectral_data
@@ -268,11 +266,11 @@ def test_combine_spectra():
 
     from skypy.galaxy._spectrum_loaders import combine_spectra
     from astropy import units
+    from specutils import Spectrum1D, SpectrumList
 
-    a = specutils.Spectrum1D(spectral_axis=[1., 2., 3.]*units.AA,
-                             flux=[1., 2., 3.]*units.Jy)
-    b = specutils.Spectrum1D(spectral_axis=[1e-10, 2e-10, 3e-10]*units.m,
-                             flux=[4e-23, 5e-23, 6e-23]*units.Unit('erg s-1 cm-2 Hz-1'))
+    a = Spectrum1D(spectral_axis=[1., 2., 3.]*units.AA, flux=[1., 2., 3.]*units.Jy)
+    b = Spectrum1D(spectral_axis=[1e-10, 2e-10, 3e-10]*units.m,
+                   flux=[4e-23, 5e-23, 6e-23]*units.Unit('erg s-1 cm-2 Hz-1'))
 
     assert np.allclose(a.spectral_axis, b.spectral_axis, atol=0, rtol=1e-10)
 
@@ -280,22 +278,21 @@ def test_combine_spectra():
     assert a == combine_spectra(None, a)
 
     ab = combine_spectra(a, b)
-    assert isinstance(ab, specutils.Spectrum1D)
+    assert isinstance(ab, Spectrum1D)
     assert ab.shape == (2, 3)
     assert ab.flux.unit == units.Jy
     assert np.allclose([[1, 2, 3], [4, 5, 6]], ab.flux.value)
 
     abb = combine_spectra(ab, b)
-    assert isinstance(ab, specutils.Spectrum1D)
+    assert isinstance(ab, Spectrum1D)
     assert abb.shape == (3, 3)
     assert abb.flux.unit == units.Jy
     assert np.allclose([[1, 2, 3], [4, 5, 6], [4, 5, 6]], abb.flux.value)
 
-    c = specutils.Spectrum1D(spectral_axis=[1., 2., 3., 4.]*units.AA,
-                             flux=[1., 2., 3., 4.]*units.Jy)
+    c = Spectrum1D(spectral_axis=[1., 2., 3., 4.]*units.AA, flux=[1., 2., 3., 4.]*units.Jy)
 
     ac = combine_spectra(a, c)
-    assert isinstance(ac, specutils.SpectrumList)
+    assert isinstance(ac, SpectrumList)
 
     aca = combine_spectra(ac, a)
-    assert isinstance(aca, specutils.SpectrumList)
+    assert isinstance(aca, SpectrumList)
diff --git a/skypy/utils/tests/test_decorators.py b/skypy/utils/tests/test_decorators.py
index a1a0758..4615d89 100644
--- a/skypy/utils/tests/test_decorators.py
+++ b/skypy/utils/tests/test_decorators.py
@@ -1,5 +1,6 @@
 import numpy as np
 import pytest
+from skypy.galaxy.spectrum import HAS_SPECUTILS, HAS_SKYPY_DATA
 
 
 def test_uses_default_cosmology():
@@ -82,6 +83,8 @@ def test_dependent_argument():
             pass
 
 
+@pytest.mark.skipif(not HAS_SPECUTILS or not HAS_SKYPY_DATA,
+                    reason='test requires specutils and skypy-data')
 def test_spectral_data_input():
 
     from astropy import units