Source code for gammapy.utils.testing
# Licensed under a 3-clause BSD style license - see LICENSE.rst
"""Utilities for testing"""
from __future__ import absolute_import, division, print_function, unicode_literals
import sys
import os
import pytest
from astropy.time import Time
from astropy.coordinates import SkyCoord
from numpy.testing import assert_allclose
from ..data import DataManager
from ..datasets import gammapy_extra
__all__ = [
'requires_dependency',
'requires_data',
'assert_wcs_allclose',
'assert_skycoord_allclose',
'assert_time_allclose',
]
# Cache for `requires_dependency`
_requires_dependency_cache = dict()
[docs]def requires_dependency(name):
"""Decorator to declare required dependencies for tests.
Examples
--------
::
from gammapy.utils.testing import requires_dependency
@requires_dependency('scipy')
def test_using_scipy():
import scipy
...
"""
if name in _requires_dependency_cache:
skip_it = _requires_dependency_cache[name]
else:
try:
__import__(name)
skip_it = False
except ImportError:
skip_it = True
_requires_dependency_cache[name] = skip_it
reason = 'Missing dependency: {}'.format(name)
return pytest.mark.skipif(skip_it, reason=reason)
def has_hess_test_data():
"""Check if the user has HESS data for testing.
"""
if not DataManager.DEFAULT_CONFIG_FILE.is_file():
return False
try:
dm = DataManager()
# TODO: add checks on availability of datasets used in the tests ...
return True
except:
return False
def has_data(name):
"""Is a certain set of data available?
"""
if name == 'gammapy-extra':
from ..datasets import gammapy_extra
return gammapy_extra.is_available
elif name == 'hess':
return has_hess_test_data()
elif name == 'hgps':
return ('HGPS_DATA' in os.environ) and ('HGPS_ANALYSIS' in os.environ)
elif name == 'gamma-cat':
return ('GAMMA_CAT' in os.environ)
elif name == 'fermi-lat':
return ('GAMMAPY_FERMI_LAT_DATA' in os.environ)
else:
raise ValueError('Invalid name: {}'.format(name))
[docs]def requires_data(name):
"""Decorator to declare required data for tests.
Examples
--------
::
from gammapy.utils.testing import requires_data
from gammapy.datasets import gammapy_extra
@requires_data('gammapy-extra')
def test_using_data_files():
filename = gammapy_extra.filename('...')
...
"""
skip_it = not has_data(name)
reason = 'Missing data: {}'.format(name)
return pytest.mark.skipif(skip_it, reason=reason)
def run_cli(cli, args, exit_code=0):
"""Run Click command line tool.
Thin wrapper around `click.testing.CliRunner`
that prints info to stderr if the command fails.
Parameters
----------
cli : click.Command
Click command
args : list of str
Argument list
exit_code : int
Expected exit code of the command
Returns
-------
result : `click.testing.Result`
Result
"""
from click.testing import CliRunner
result = CliRunner().invoke(cli, args, catch_exceptions=False)
if result.exit_code != exit_code:
sys.stderr.write('Exit code mismatch!\n')
sys.stderr.write('Ouput:\n')
sys.stderr.write(result.output)
return result
# https://pytest.org/latest/tmpdir.html#the-tmpdir-factory-fixture
@pytest.fixture
def data_manager():
test_register = gammapy_extra.filename('datasets/data-register.yaml')
dm = DataManager.from_yaml(test_register)
return dm
[docs]def assert_wcs_allclose(wcs1, wcs2):
"""Assert all-close for `~astropy.wcs.WCS`
"""
# TODO: implement properly
assert_allclose(wcs1.wcs.cdelt, wcs2.wcs.cdelt)
[docs]def assert_skycoord_allclose(actual, desired):
"""Assert all-close for `~astropy.coordinates.SkyCoord`.
- Frames can be different, aren't checked at the moment.
"""
assert isinstance(actual, SkyCoord)
assert isinstance(desired, SkyCoord)
assert_allclose(actual.data.lon.value, desired.data.lon.value)
assert_allclose(actual.data.lat.value, desired.data.lat.value)
[docs]def assert_time_allclose(actual, desired):
"""Assert that two `astropy.time.Time` objects are almost the same."""
assert isinstance(actual, Time)
assert isinstance(desired, Time)
assert_allclose(actual.value, desired.value)
assert actual.scale == desired.scale
assert actual.format == desired.format
def mpl_savefig_check():
"""Call matplotlib savefig for the current figure.
This will trigger a render of the Figure, which can sometimes
raise errors if there is a problem; i.e. we call this at the
end of every plotting test for now.
This is writing to an in-memory byte buffer, i.e. is faster
than writing to disk.
"""
import matplotlib.pyplot as plt
from io import BytesIO
plt.savefig(BytesIO(), format='png')