Skip to content

Commit

Permalink
Merge pull request #2751 from nabobalis/0.9
Browse files Browse the repository at this point in the history
[0.9] v0.9.3 backports
  • Loading branch information
nabobalis committed Sep 12, 2018
2 parents eded238 + f0405ae commit ae91b90
Show file tree
Hide file tree
Showing 19 changed files with 176 additions and 44 deletions.
30 changes: 16 additions & 14 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
skip-check: &skip-check
name: Check for [ci skip]
command: bash .circleci/early_exit.sh

apt-run: &apt-install
name: Install apt packages
command: |
sudo apt update
sudo apt install -y graphviz
apt update
apt install -y graphviz build-essential
pip-run: &pip-install
docs-install: &docs-install
name: Install Python dependencies
command: |
python3 -m venv venv
. venv/bin/activate
pip install -q -r requirements/docs.txt
pip install -r requirements/docs.txt
version: 2
jobs:
egg-info-36:
egg-info-27:
docker:
- image: circleci/python:3.6
- image: circleci/python:2.7
steps:
- checkout
- run: python setup.py egg_info
Expand All @@ -27,25 +29,25 @@ jobs:
- checkout
- run: python setup.py egg_info

egg-info-27:
egg-info-36:
docker:
- image: circleci/python:2.7
- image: circleci/python:3.6
steps:
- checkout
- run: python setup.py egg_info

html-docs:
docker:
- image: circleci/python:3.6
- image: continuumio/miniconda3
steps:
- restore_cache:
keys: sample-data-v1

- checkout
- run: *skip-check
- run: *apt-install
- run: *pip-install
- run: venv/bin/python setup.py build_docs -w 2> /dev/null

- run: *docs-install
- run: python setup.py build_docs -w
- store_artifacts:
path: docs/_build/html

Expand Down
7 changes: 7 additions & 0 deletions .circleci/early_exit.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash

commitmessage=$(git log --pretty=%B -n 1)
if [[ $commitmessage = *"[ci skip]"* ]] || [[ $commitmessage = *"[skip ci]"* ]]; then
echo "Skipping build because [ci skip] found in commit message"
circleci step halt
fi
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ env:
- MAIN_CMD='python setup.py'
- SETUP_CMD='test --coverage'
- CONDA_CHANNELS='sunpy'
- CONDA_DEPENDENCIES='openjpeg Cython jinja2 scipy matplotlib mock requests beautifulsoup4 sqlalchemy scikit-image pytest-mock lxml pyyaml pandas nomkl pytest-astropy suds-jurko glymur pytest-xdist dask drms sphinx-astropy pytest-cov hypothesis'
- CONDA_DEPENDENCIES='openjpeg Cython jinja2 scipy matplotlib mock requests beautifulsoup4 sqlalchemy scikit-image pytest-mock lxml pyyaml pandas pytest-astropy suds-jurko glymur pytest-xdist dask drms sphinx-astropy pytest-cov hypothesis'
- PIP_DEPENDENCIES='pytest-rerunfailures sunpy-sphinx-theme pytest-sugar'
- EVENT_TYPE='push pull_request cron'
- MPLBACKEND='agg'
Expand Down
19 changes: 19 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
Sunpy 0.9.3 (2018-09-12)
========================

Bug Fixes
---------

- Correctly import `~astropy.units.allclose` based on astropy version. This means that `sunpy.coordinates` will import when pytest is not installed. (`#2702 <https://github.com/sunpy/sunpy/pull/2702>`__)
- Raise an error when transforming between HPC and HCC frames if the observer is not the same. (`#2725 <https://github.com/sunpy/sunpy/pull/2725>`__)
- Do not attempt to save a FITS header comment for a keyword which is not in the header. This prevents an error on saving some maps after the metadata had been modified but not the comments. (`#2748 <https://github.com/sunpy/sunpy/pull/2748>`__)
- Add support for `HMIMap` objects as input to `sunpy.instr.aia.aiaprep()`. (`#2749 <https://github.com/sunpy/sunpy/pull/2749>`__)


Improved Documentation
----------------------

- Add contribution guidelines for the sunpy example gallery. (`#2682 <https://github.com/sunpy/sunpy/pull/2682>`__)
- Clean up the docstring for `sunpy.physics.differential_rotation.solar_rotate_coordinate` to make the example clearer. (`#2708 <https://github.com/sunpy/sunpy/pull/2708>`__)


Sunpy 0.9.2 (2018-07-27)
========================

Expand Down
4 changes: 3 additions & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ environment:
# /E:ON and /V:ON options are not enabled in the batch script intepreter
# See: https://stackoverflow.com/a/13751649/163740
CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\ci-helpers\\appveyor\\windows_sdk.cmd"
CONDA_CHANNELS: "conda-forge astropy-ci-extras"
CONDA_CHANNELS: "conda-forge"
CONDA_DEPENDENCIES: "scipy matplotlib mock pandas requests beautifulsoup4 sqlalchemy scikit-image pytest-mock suds-jurko glymur drms"
PIP_DEPENDENCIES: "hypothesis sunpy-sphinx-theme pytest-astropy"
NUMPY_VERSION: "stable"
Expand All @@ -32,6 +32,8 @@ install:
- "powershell ci-helpers/appveyor/install-miniconda.ps1"
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
- "activate test"
- "conda remove --force pillow"
- "pip install pillow"

# Not a .NET project, we build SunPy in the install step instead
build: false
Expand Down
1 change: 0 additions & 1 deletion changelog/2702.bugfix.rst

This file was deleted.

23 changes: 23 additions & 0 deletions docs/dev_guide/example_gallery.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.. _example_gallery:


Example Gallery
===============

The purpose of the page is to describe the contribution guidelines for the
`SunPy Example Gallery <http://docs.sunpy.org/en/stable/generated/gallery/index.html>`_.
All potential contributors to the SunPy Example Gallery should read and abide by
the following guidelines.

Contribution Guidelines
-----------------------

- The title of the example should be short yet descriptive and emphasize the goal of the example. Try to make the title appeal to a broad audience and avoid referencing a specific instrument, catalog, or anything wavelength dependent.
- Each example should begin with a paragraph that gives a brief overview of the entire example, including relevant astronomy concepts, and motivates the described functionality.
- The examples must be compatible with the versions supported by the last major release of the SunPy core package (i.e. Python >= 3.6).
- All the examples must be fully PEP8 compliant, we recommend using one of the many PEP8 linters that are available (autopep8, pylint, flake8 as some examples).
- Wherever possible, the examples should include linked references with links pointing to the appropriate DOI or ADS entry.
- The example should include links to relevant documentation pages.
- Each example should, where possible, include at least one image, map, or plot to use as the icon in the Example Gallery.
- The examples should avoid using acronyms without defining them first (e.g. Virtual Solar Observatory, or VSO). Similarly complex jargon should be avoided unless clearly explained.
- There should be a good variety of examples for each section (simple and more complex to cater for different levels).
1 change: 1 addition & 0 deletions docs/dev_guide/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ We currently recommend the :ref:`newcomers` as the place to start.
documentation
tests
stability
example_gallery
11 changes: 7 additions & 4 deletions docs/guide/acquiring_data/fido.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ Finding and Downloading Data using Fido
---------------------------------------

This guide outlines how to search for and download data using SunPy's
Federated Internet Data Obtainer...or more usually (and
sanely) referred to as Fido. `Fido <sunpy.net.fido_factory.UnifiedDownloaderFactory>` is a unified interface for searching
Federated Internet Data Obtainer...or more usually (and sanely) referred to as Fido.
`Fido <sunpy.net.fido_factory.UnifiedDownloaderFactory>` is a unified interface for searching
and fetching solar physics data irrespective of the underlying
client or webservice through which the data is obtained, e.g. VSO,
JSOC, etc. It therefore supplies a single, easy and consistent way to
client or webservice through which the data is obtained, e.g. VSO_,
JSOC_, etc. It therefore supplies a single, easy and consistent way to
obtain most forms of solar physics data.

Import
Expand Down Expand Up @@ -232,3 +232,6 @@ data to a subdirectory named after the instrument, use

You can see the list of options that can be specified in path for all the files
to be downloaded with ``results.response_block_properties``.

.. _VSO: https://sdac.virtualsolar.org/cgi/search
.. _JSOC: http://jsoc.stanford.edu/
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
builtins._ASTROPY_PACKAGE_NAME_ = PACKAGENAME

# VERSION should be PEP386 compatible (https://www.python.org/dev/peps/pep-0386)
VERSION = '0.9.2'
VERSION = '0.9.3'

# Indicates if this version is a release version
RELEASE = 'dev' not in VERSION
Expand Down
38 changes: 35 additions & 3 deletions sunpy/coordinates/tests/test_transformations.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

import astropy.units as u
from astropy.tests.helper import quantity_allclose, assert_quantity_allclose
from astropy.coordinates import SkyCoord, get_body_barycentric, HeliocentricTrueEcliptic, Angle
from astropy.coordinates import (SkyCoord, get_body_barycentric, HeliocentricTrueEcliptic, Angle,
ConvertError)
from astropy.time import Time

from sunpy.coordinates import (Helioprojective, HeliographicStonyhurst,
Expand Down Expand Up @@ -73,7 +74,6 @@ def test_hpc_hpc_sc():


def test_hpc_hpc_null():

hpc_in = Helioprojective(0*u.arcsec, 0*u.arcsec)
hpc_out = Helioprojective()

Expand Down Expand Up @@ -210,4 +210,36 @@ def test_hgs_cartesian_rep_to_hgc():
assert_quantity_allclose(hgccoord_cart.lat, hgccoord_sph.lat)
assert_quantity_allclose(hgccoord_cart.lon, hgccoord_sph.lon)
assert_quantity_allclose(hgccoord_cart.radius, hgccoord_sph.radius)



def test_hcc_to_hpc_different_observer():
# This test checks transformation HCC->HPC in the case where the HCC and HPC frames are
# defined by different observers.
# NOTE: This test is currently expected to fail because the HCC<->HPC transformation does
# not account for observer location. It will be updated once this is fixed.
rsun = 1*u.m
D0 = 1*u.km
L0 = 1*u.deg
observer_1 = HeliographicStonyhurst(lat=0*u.deg, lon=0*u.deg, radius=D0)
observer_2 = HeliographicStonyhurst(lat=0*u.deg, lon=L0, radius=D0)
hcc_frame = Heliocentric(observer=observer_1)
hpc_frame = Helioprojective(observer=observer_2)
hcccoord = SkyCoord(x=rsun, y=rsun, z=rsun, frame=hcc_frame)
with pytest.raises(ConvertError):
hcccoord.transform_to(hpc_frame)


def test_hpc_to_hcc_different_observer():
# This test checks transformation HPC->HCC in the case where the HCC and HPC frames are
# defined by different observers.
# NOTE: This test is currently expected to fail because the HCC<->HPC transformation does
# not account for observer location. It will be updated once this is fixed.
D0 = 1*u.km
L0 = 1*u.deg
observer_1 = HeliographicStonyhurst(lat=0*u.deg, lon=0*u.deg, radius=D0)
observer_2 = HeliographicStonyhurst(lat=0*u.deg, lon=L0, radius=D0)
hcc_frame = Heliocentric(observer=observer_1)
hpc_frame = Helioprojective(observer=observer_2)
hpccoord = SkyCoord(Tx=0*u.arcsec, Ty=0*u.arcsec, frame=hpc_frame)
with pytest.raises(ConvertError):
hpccoord.transform_to(hcc_frame)
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
def test_hpc_hcc(Tx, Ty):
hpc = Helioprojective(Tx, Ty,
observer=HeliographicStonyhurst(0*u.deg, 0*u.deg, 1*u.AU))
hcc = hpc.transform_to(Heliocentric)
hcc = hpc.transform_to(Heliocentric(observer=HeliographicStonyhurst(0*u.deg, 0*u.deg, 1*u.AU)))
d0 = hpc.observer.radius

x, y, z = wcs.convert_hpc_hcc(Tx.value, Ty.value, angle_units='arcsec',
Expand Down
34 changes: 29 additions & 5 deletions sunpy/coordinates/transformations.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,19 @@ def _carrington_offset(obstime):
from .ephemeris import get_sun_L0
return get_sun_L0(obstime)


def _observers_are_equal(obs_1, obs_2, string_ok=False):
if string_ok:
if obs_1 == obs_2:
return True
if not (isinstance(obs_1, BaseCoordinateFrame) and isinstance(obs_2, BaseCoordinateFrame)):
raise ValueError("To compare two observers, both must be instances of BaseCoordinateFrame. "
"Cannot compare two observers {} and {}.".format(obs_1, obs_2))
return (quantity_allclose(obs_1.lat, obs_2.lat) and
quantity_allclose(obs_1.lon, obs_2.lon) and
quantity_allclose(obs_1.radius, obs_2.radius))


# =============================================================================
# ------------------------- Transformation Framework --------------------------
# =============================================================================
Expand Down Expand Up @@ -112,6 +125,13 @@ def hcc_to_hpc(helioccoord, heliopframe):
"""
Convert from Heliocentic Cartesian to Helioprojective Cartesian.
"""
if not _observers_are_equal(helioccoord.observer, heliopframe.observer):
raise ConvertError("Cannot directly transform heliocentric coordinates to "
"helioprojective coordinates for different "
"observers {} and {}. See discussion in this GH issue: "
"https://github.com/sunpy/sunpy/issues/2712. Try converting to "
"an intermediate heliographic Stonyhurst frame.".format(
helioccoord.observer, heliopframe.observer))

x = helioccoord.x.to(u.m)
y = helioccoord.y.to(u.m)
Expand All @@ -136,6 +156,14 @@ def hpc_to_hcc(heliopcoord, heliocframe):
"""
Convert from Helioprojective Cartesian to Heliocentric Cartesian.
"""
if not _observers_are_equal(heliopcoord.observer, heliocframe.observer):
raise ConvertError("Cannot directly transform helioprojective coordinates to "
"heliocentric coordinates for different "
"observers {} and {}. See discussion in this GH issue: "
"https://github.com/sunpy/sunpy/issues/2712. Try converting to "
"an intermediate heliographic Stonyhurst frame.".format(
heliopcoord.observer, heliocframe.observer))

if not isinstance(heliopcoord.observer, BaseCoordinateFrame):
raise ConvertError("Cannot transform helioprojective coordinates to "
"heliocentric coordinates for observer '{}' "
Expand Down Expand Up @@ -234,18 +262,14 @@ def hgs_to_hcc(heliogcoord, heliocframe):
return heliocframe.realize_frame(representation)



@frame_transform_graph.transform(FunctionTransform, Helioprojective,
Helioprojective)
def hpc_to_hpc(heliopcoord, heliopframe):
"""
This converts from HPC to HPC, with different observer location parameters.
It does this by transforming through HGS.
"""
if (heliopcoord.observer == heliopframe.observer or
(quantity_allclose(heliopcoord.observer.lat, heliopframe.observer.lat) and
quantity_allclose(heliopcoord.observer.lon, heliopframe.observer.lon) and
quantity_allclose(heliopcoord.observer.radius, heliopframe.observer.radius))):
if _observers_are_equal(heliopcoord.observer, heliopframe.observer, string_ok=True):
return heliopframe.realize_frame(heliopcoord._data)

if not isinstance(heliopframe.observer, BaseCoordinateFrame):
Expand Down
4 changes: 2 additions & 2 deletions sunpy/instr/aia.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import numpy as np
import astropy.units as u

from sunpy.map.sources.sdo import AIAMap
from sunpy.map.sources.sdo import AIAMap, HMIMap

__all__ = ['aiaprep']

Expand Down Expand Up @@ -42,7 +42,7 @@ def aiaprep(aiamap):
therefore differ from the original file.
"""

if not isinstance(aiamap, AIAMap):
if not isinstance(aiamap, (AIAMap, HMIMap)):
raise ValueError("Input must be an AIAMap")

# Target scale is 0.6 arcsec/pixel, but this needs to be adjusted if the map
Expand Down
8 changes: 5 additions & 3 deletions sunpy/instr/tests/test_aia.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
# functions


@pytest.fixture
def original():
return sunpy.map.Map(test.get_test_filepath("aia_171_level1.fits"))
@pytest.fixture(scope="module",
params=[test.get_test_filepath("aia_171_level1.fits"),
test.get_test_filepath("resampled_hmi.fits")])
def original(request):
return sunpy.map.Map(request.param)


@pytest.fixture
Expand Down
4 changes: 3 additions & 1 deletion sunpy/io/fits.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,9 @@ def write(fname, data, header, **kwargs):

if isinstance(key_comments, dict):
for k, v in key_comments.items():
fits_header.comments[k] = v
# Check that the Card for the comment exists before trying to write to it.
if k in fits_header:
fits_header.comments[k] = v
elif key_comments:
raise TypeError("KEYCOMMENTS must be a dictionary")

Expand Down
15 changes: 15 additions & 0 deletions sunpy/io/tests/test_fits.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,18 @@ def test_extract_waveunit_wavelnthcomment_parentheses():
# WAVELNTH comment is: "Observed wavelength (nm)"
waveunit = extract_waveunit(get_header(SVSM_IMAGE)[0])
assert waveunit == 'nm'


def test_simple_write(tmpdir):
data, header = sunpy.io.fits.read(AIA_171_IMAGE)[0]
outfile = tmpdir / "test.fits"
sunpy.io.fits.write(str(outfile), data, header)
assert outfile.exists()


def test_extra_comment_write(tmpdir):
data, header = sunpy.io.fits.read(AIA_171_IMAGE)[0]
header["KEYCOMMENTS"]["TEST"] = "Hello world"
outfile = tmpdir / "test.fits"
sunpy.io.fits.write(str(outfile), data, header)
assert outfile.exists()
2 changes: 1 addition & 1 deletion sunpy/net/jsoc/jsoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ def get_request(self, requests, path=None, overwrite=False, progress=True,

# We only download if all are finished
if not all([r.has_succeeded() for r in requests]):
raise NotExportedError("Can not download as not all the requests"
raise NotExportedError("Can not download as not all the requests "
"have been exported for download yet.")

# Ensure path has a {file} in it
Expand Down

0 comments on commit ae91b90

Please sign in to comment.