Commit e3378d48 authored by Ole Streicher's avatar Ole Streicher

New upstream version 3.1.2

parent 02dd1337
3.1.2 (2019-02-23)
==================
Bug fixes
---------
astropy.coordinates
^^^^^^^^^^^^^^^^^^^
- Convert the default of ``QuantityAttribute``, thereby catching the error case
case of it being set to None at attribute creation, and giving a more useful
error message in the process. [#8300]
astropy.cosmology
^^^^^^^^^^^^^^^^^
- Fix elliptic analytical solution for comoving distance. Only
relevant for non-flat cosmologies without radiation and ``Om0`` > ``Ode0``.
[#8391]
astropy.modeling
^^^^^^^^^^^^^^^^
- Fixed slowness for certain compound models consisting of large numbers
of multi-input models [#8338, #8349]
astropy.visualization.wcsaxes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fix a bug that caused an error when passing an array with all values the same
to contour or contourf. [#8321]
- Fix a bug that caused contour and contourf to return None instead of the
contour set. [#8321]
3.1.1 (2018-12-31)
==================
......@@ -162,8 +199,6 @@ astropy.modeling
- Add a ``separability_matrix`` function which returns the correlation matrix
of inputs and outputs. [#7803]
- Fixed compatibility of ``JointFitter`` with the latest version of Numpy. [#7984]
- Add ``prior`` and ``posterior`` constraints to modeling parameters. These are
not used by any current fitters, but are provided to allow user code to
experiment with Bayesian fitters. [#7558]
......@@ -256,7 +291,7 @@ astropy.units
- Add complex numbers support for ``Quantity._repr_latex_``. [#7676]
- Add ``thermodynamic_temperature`` equivalency to convert between
Jy/beam and "thermodynamic temperature" for cosmology. [#7054]
Jy/sr and "thermodynamic temperature" for cosmology. [#7054]
- Add millibar unit. [#7863]
......@@ -1398,6 +1433,68 @@ Other Changes and Additions
2.0.12 (2019-02-23)
===================
New Features
------------
astropy.utils
^^^^^^^^^^^^^
- The ``deprecated_renamed_argument`` decorator now capable deprecating an
argument without renaming it. It also got a new ``alternative`` keyword
argument to suggest alternative functionality instead of the removed
one. [#8324]
Bug Fixes
---------
astropy.io.fits
^^^^^^^^^^^^^^^
- Fixed bug in ``ColDefs._init_from_array()`` that caused non-scalar unsigned
entries to not have the correct bzero value set. [#8353]
astropy.modeling
^^^^^^^^^^^^^^^^
- Fixed compatibility of ``JointFitter`` with the latest version of Numpy.
[#7984]
astropy.table
^^^^^^^^^^^^^
- Fix ``.quantity`` property of ``Column`` class for function-units (e.g.,
``dex``). Previously setting this was possible, but getting raised
an error. [#8425]
- Fixes a bug where initializing a new ``Table`` from the final row of an
existing ``Table`` failed. This happened when that row was generated using
the item index ``[-1]``. [#8422]
astropy.wcs
^^^^^^^^^^^
- Fix bug that caused ``WCS.has_celestial``, ``wcs_to_celestial_frame``, and
other functionality depending on it to fail in the presence of correlated
celestial and other axes. [#8420]
Other Changes and Additions
---------------------------
- Fixed ``make clean`` for the documentation on Windows to ensure it
properly removes the ``api`` and ``generated`` directories. [#8346]
- Updating bundled ``pytest-openfiles`` to v0.3.2. [#8434]
- Making ``ErfaWarning`` and ``ErfaError`` available via
``astropy.utils.exceptions``. [#8441]
2.0.11 (2018-12-31)
===================
......
Metadata-Version: 2.1
Name: astropy
Version: 3.1.1
Version: 3.1.2
Summary: Community-developed python astronomy tools
Home-page: http://astropy.org
Author: The Astropy Developers
......
......@@ -2,19 +2,53 @@
Astropy
=======
.. image:: https://img.shields.io/pypi/v/astropy.svg
:target: https://pypi.python.org/pypi/astropy
|Travis Status| |AppVeyor Status| |CircleCI Status| |Coverage Status| |PyPI Status| |Documentation Status|
Astropy (http://www.astropy.org) is a package intended to contain much of
the core functionality and some common tools needed for performing
astronomy and astrophysics with Python.
The Astropy Project (http://astropy.org/) is a community effort to develop a
single core package for Astronomy in Python and foster interoperability between
Python astronomy packages. This repository contains the core package which is
intended to contain much of the core functionality and some common tools needed
for performing astronomy and astrophysics with Python.
Releases are `registered on PyPI <http://pypi.python.org/pypi/astropy>`_,
and development is occurring at the
`project's github page <http://github.com/astropy/astropy>`_.
`project's GitHub page <http://github.com/astropy/astropy>`_.
For installation instructions, see the `online documentation <http://docs.astropy.org/>`_
or ``docs/install.rst`` in this source distribution.
or `docs/install.rst <docs/install.rst>`_ in this source distribution.
Contributing Code, Documentation, or Feedback
---------------------------------------------
The Astropy Project is made both by and for its users, so we welcome and encourage
contributions of many kinds. Our goal is to keep this a positive, inclusive,
successful, and growing community, by abiding with the
`Astropy Community Code of Conduct <http://www.astropy.org/about.html#codeofconduct>`_.
More detailed information on contributing to the project or submitting feedback
can be found on the `contributions <http://www.astropy.org/contribute.html>`_ page.
A `summary of contribution guidelines <CONTRIBUTING.md>`_ can also be used as a quick
reference when you're ready to start writing or validating code for submission.
Supporting the project
----------------------
|NumFOCUS| |Donate|
The Astropy Project is sponsored by NumFOCUS, a 501(c)(3) nonprofit in the
United States. You can donate to the project by using the link above, and this
donation will support our mission to promote sustainable high-level code base
for the astronomy community, open code development, educational materials, and
reproducible scientific research.
License
-------
Astropy is licensed under a 3-clause BSD style license - see the
`LICENSE.rst <LICENSE.rst>`_ file.
Notes for package managers
--------------------------
For system packagers: Please install Astropy with the command::
......@@ -23,47 +57,33 @@ For system packagers: Please install Astropy with the command::
This will prevent the astropy_helpers bootstrap script from attempting to
reach out to PyPI.
Project Status
--------------
.. image:: https://travis-ci.org/astropy/astropy.svg
.. |Travis Status| image:: https://travis-ci.org/astropy/astropy.svg
:target: https://travis-ci.org/astropy/astropy
:alt: Astropy's Travis CI Status
.. image:: https://circleci.com/gh/astropy/astropy.svg?style=svg
.. |CircleCI Status| image:: https://circleci.com/gh/astropy/astropy.svg?style=svg
:target: https://circleci.com/gh/astropy/astropy
:alt: Astropy's CircleCI Status
.. image:: https://codecov.io/gh/astropy/astropy/branch/master/graph/badge.svg
.. |AppVeyor Status| image:: https://ci.appveyor.com/api/projects/status/ym7lxajcs5qwm31e/branch/master?svg=true
:target: https://ci.appveyor.com/project/Astropy/astropy/branch/master
:alt: Astropy's Appveyor Status
.. |Coverage Status| image:: https://codecov.io/gh/astropy/astropy/branch/master/graph/badge.svg
:target: https://codecov.io/gh/astropy/astropy
:alt: Astropy's Coverage Status
.. image:: https://ci.appveyor.com/api/projects/status/ym7lxajcs5qwm31e/branch/master?svg=true
:target: https://ci.appveyor.com/project/Astropy/astropy/branch/master
:alt: Astropy's Appveyor Status
.. |PyPI Status| image:: https://img.shields.io/pypi/v/astropy.svg
:target: https://pypi.python.org/pypi/astropy
:alt: Astropy's PyPI Status
For an overview of the testing and build status of all packages associated
with the Astropy Project, see http://dashboard.astropy.org.
.. |Documentation Status| image:: https://readthedocs.org/projects/astropy/badge/?version=stable
:target: http://docs.astropy.org/en/stable/?badge=stable
:alt: Documentation Status
.. image:: https://img.shields.io/badge/powered%20by-NumFOCUS-orange.svg?style=flat&colorA=E1523D&colorB=007D8A
.. |NumFOCUS| image:: https://img.shields.io/badge/powered%20by-NumFOCUS-orange.svg?style=flat&colorA=E1523D&colorB=007D8A
:target: http://numfocus.org
:alt: Powered by NumFOCUS
Contributing Code, Documentation, or Feedback
---------------------------------------------
The Astropy project is made both by and for its users, so we welcome and encourage
contributions of many kinds. Our goal is to keep this a positive, inclusive,
successful, and growing community, by abiding with the
`Astropy Community Code of Conduct <http://www.astropy.org/about.html#codeofconduct>`_.
More detailed information on contributing to the project or submitting feedback
can be found on the `contributions <http://www.astropy.org/contribute.html>`_ page.
A `summary of contribution guidelines <CONTRIBUTING.md>`_ can also be used as a quick
reference when you're ready to start writing or validating code for submission.
License
-------
Astropy is licensed under a 3-clause BSD style license - see the
``LICENSE.rst`` file.
.. |Donate| image:: https://img.shields.io/badge/Donate-to%20Astropy-brightgreen.svg
:target: https://www.flipcause.com/widget/give_now/MjI1NA==
......@@ -45,18 +45,99 @@ import re
import subprocess as sp
import sys
__minimum_python_version__ = (3, 5)
if sys.version_info < __minimum_python_version__:
print("ERROR: Python {} or later is required by astropy-helpers".format(
__minimum_python_version__))
sys.exit(1)
from distutils import log
from distutils.debug import DEBUG
try:
from ConfigParser import ConfigParser, RawConfigParser
except ImportError:
from configparser import ConfigParser, RawConfigParser
import pkg_resources
from setuptools import Distribution
from setuptools.package_index import PackageIndex
# This is the minimum Python version required for astropy-helpers
__minimum_python_version__ = (3, 5)
# TODO: Maybe enable checking for a specific version of astropy_helpers?
DIST_NAME = 'astropy-helpers'
PACKAGE_NAME = 'astropy_helpers'
UPPER_VERSION_EXCLUSIVE = None
# Defaults for other options
DOWNLOAD_IF_NEEDED = True
INDEX_URL = 'https://pypi.python.org/simple'
USE_GIT = True
OFFLINE = False
AUTO_UPGRADE = True
# A list of all the configuration options and their required types
CFG_OPTIONS = [
('auto_use', bool), ('path', str), ('download_if_needed', bool),
('index_url', str), ('use_git', bool), ('offline', bool),
('auto_upgrade', bool)
]
# Start off by parsing the setup.cfg file
SETUP_CFG = ConfigParser()
if os.path.exists('setup.cfg'):
try:
SETUP_CFG.read('setup.cfg')
except Exception as e:
if DEBUG:
raise
log.error(
"Error reading setup.cfg: {0!r}\n{1} will not be "
"automatically bootstrapped and package installation may fail."
"\n{2}".format(e, PACKAGE_NAME, _err_help_msg))
# We used package_name in the package template for a while instead of name
if SETUP_CFG.has_option('metadata', 'name'):
parent_package = SETUP_CFG.get('metadata', 'name')
elif SETUP_CFG.has_option('metadata', 'package_name'):
parent_package = SETUP_CFG.get('metadata', 'package_name')
else:
parent_package = None
if SETUP_CFG.has_option('options', 'python_requires'):
python_requires = SETUP_CFG.get('options', 'python_requires')
# The python_requires key has a syntax that can be parsed by SpecifierSet
# in the packaging package. However, we don't want to have to depend on that
# package, so instead we can use setuptools (which bundles packaging). We
# have to add 'python' to parse it with Requirement.
from pkg_resources import Requirement
req = Requirement.parse('python' + python_requires)
# We want the Python version as a string, which we can get from the platform module
import platform
python_version = platform.python_version()
if not req.specifier.contains(python_version):
if parent_package is None:
print("ERROR: Python {} is required by this package".format(req.specifier))
else:
print("ERROR: Python {} is required by {}".format(req.specifier, parent_package))
sys.exit(1)
if sys.version_info < __minimum_python_version__:
if parent_package is None:
print("ERROR: Python {} or later is required by astropy-helpers".format(
__minimum_python_version__))
else:
print("ERROR: Python {} or later is required by astropy-helpers for {}".format(
__minimum_python_version__, parent_package))
sys.exit(1)
_str_types = (str, bytes)
......@@ -116,36 +197,6 @@ except:
# End compatibility imports...
# In case it didn't successfully import before the ez_setup checks
import pkg_resources
from setuptools import Distribution
from setuptools.package_index import PackageIndex
from distutils import log
from distutils.debug import DEBUG
# TODO: Maybe enable checking for a specific version of astropy_helpers?
DIST_NAME = 'astropy-helpers'
PACKAGE_NAME = 'astropy_helpers'
UPPER_VERSION_EXCLUSIVE = None
# Defaults for other options
DOWNLOAD_IF_NEEDED = True
INDEX_URL = 'https://pypi.python.org/simple'
USE_GIT = True
OFFLINE = False
AUTO_UPGRADE = True
# A list of all the configuration options and their required types
CFG_OPTIONS = [
('auto_use', bool), ('path', str), ('download_if_needed', bool),
('index_url', str), ('use_git', bool), ('offline', bool),
('auto_upgrade', bool)
]
class _Bootstrapper(object):
"""
Bootstrapper implementation. See ``use_astropy_helpers`` for parameter
......@@ -215,36 +266,20 @@ class _Bootstrapper(object):
@classmethod
def parse_config(cls):
if not os.path.exists('setup.cfg'):
return {}
cfg = ConfigParser()
try:
cfg.read('setup.cfg')
except Exception as e:
if DEBUG:
raise
log.error(
"Error reading setup.cfg: {0!r}\n{1} will not be "
"automatically bootstrapped and package installation may fail."
"\n{2}".format(e, PACKAGE_NAME, _err_help_msg))
return {}
if not cfg.has_section('ah_bootstrap'):
if not SETUP_CFG.has_section('ah_bootstrap'):
return {}
config = {}
for option, type_ in CFG_OPTIONS:
if not cfg.has_option('ah_bootstrap', option):
if not SETUP_CFG.has_option('ah_bootstrap', option):
continue
if type_ is bool:
value = cfg.getboolean('ah_bootstrap', option)
value = SETUP_CFG.getboolean('ah_bootstrap', option)
else:
value = cfg.get('ah_bootstrap', option)
value = SETUP_CFG.get('ah_bootstrap', option)
config[option] = value
......@@ -633,8 +668,8 @@ class _Bootstrapper(object):
# only if the submodule is initialized. We ignore this information for
# now
_git_submodule_status_re = re.compile(
'^(?P<status>[+-U ])(?P<commit>[0-9a-f]{40}) '
'(?P<submodule>\S+)( .*)?$')
r'^(?P<status>[+-U ])(?P<commit>[0-9a-f]{40}) '
r'(?P<submodule>\S+)( .*)?$')
# The stdout should only contain one line--the status of the
# requested submodule
......
......@@ -30,9 +30,12 @@ module (compiled as ``ufunc``), derived from the ``ufunc.c`` file.
import warnings
from ..utils.exceptions import AstropyUserWarning
from ..utils.misc import check_broadcast
# we import these exceptions from astropy locations instead of defining them
# in this file because otherwise there are circular dependencies
from ..utils.exceptions import ErfaError, ErfaWarning
import numpy
from . import ufunc
from .ufunc import (dt_eraASTROM, dt_eraLDBODY, dt_pv,
......@@ -48,17 +51,6 @@ __all__ = ['ErfaError', 'ErfaWarning',
# <---------------------------------Error-handling---------------------------->
class ErfaError(ValueError):
"""
A class for errors triggered by ERFA functions (status codes < 0)
"""
class ErfaWarning(AstropyUserWarning):
"""
A class for warnings triggered by ERFA functions (status codes > 0)
"""
STATUS_CODES = {} # populated below before each function that returns an int
......
......@@ -30,9 +30,12 @@ module (compiled as ``ufunc``), derived from the ``ufunc.c`` file.
import warnings
from ..utils.exceptions import AstropyUserWarning
from ..utils.misc import check_broadcast
# we import these exceptions from astropy locations instead of defining them
# in this file because otherwise there are circular dependencies
from ..utils.exceptions import ErfaError, ErfaWarning
import numpy
from . import ufunc
from .ufunc import (dt_eraASTROM, dt_eraLDBODY, dt_pv,
......@@ -48,17 +51,6 @@ __all__ = ['ErfaError', 'ErfaWarning',
# <---------------------------------Error-handling---------------------------->
class ErfaError(ValueError):
"""
A class for errors triggered by ERFA functions (status codes < 0)
"""
class ErfaWarning(AstropyUserWarning):
"""
A class for warnings triggered by ERFA functions (status codes > 0)
"""
STATUS_CODES = {} # populated below before each function that returns an int
......
......@@ -54,3 +54,4 @@ def pytest_unconfigure(config):
PYTEST_HEADER_MODULES['Cython'] = 'cython'
PYTEST_HEADER_MODULES['Scikit-image'] = 'skimage'
......@@ -278,9 +278,10 @@ class QuantityAttribute(Attribute):
"""
def __init__(self, default=None, secondary_attribute='', unit=None, shape=None):
super().__init__(default, secondary_attribute)
self.unit = unit
self.shape = shape
default = self.convert_input(default)[0]
super().__init__(default, secondary_attribute)
def convert_input(self, value):
"""
......@@ -303,6 +304,10 @@ class QuantityAttribute(Attribute):
ValueError
If the input is not valid for this attribute.
"""
if value is None:
raise TypeError('QuantityAttributes cannot be None, because None '
'is not a Quantity')
if np.all(value == 0) and self.unit is not None:
return u.Quantity(np.zeros(self.shape), self.unit), True
else:
......
......@@ -8,16 +8,18 @@ place to live
import io
import copy
import pytest
import numpy as np
from astropy import units as u
from astropy.coordinates import (AltAz, EarthLocation, SkyCoord, get_sun, ICRS, CIRS, ITRS,
GeocentricTrueEcliptic, Longitude, Latitude, GCRS, HCRS,
get_moon, FK4, FK4NoETerms, BaseCoordinateFrame,
QuantityAttribute, SphericalRepresentation,
UnitSphericalRepresentation, CartesianRepresentation)
from astropy.coordinates import (AltAz, EarthLocation, SkyCoord, get_sun, ICRS,
GeocentricTrueEcliptic, Longitude, Latitude, GCRS, HCRS, CIRS,
get_moon, FK4, FK4NoETerms, BaseCoordinateFrame, ITRS,
QuantityAttribute, UnitSphericalRepresentation,
SphericalRepresentation, CartesianRepresentation,
FunctionTransform)
from astropy.coordinates.sites import get_builtin_sites
from astropy.time import Time
from astropy.utils import iers
......@@ -610,3 +612,33 @@ def test_regression_8138():
newframe = GCRS()
sc2 = sc.transform_to(newframe)
assert newframe.is_equivalent_frame(sc2.frame)
def test_regression_8276():
from astropy.coordinates import baseframe
with pytest.raises(TypeError) as excinfo:
class MyFrame(BaseCoordinateFrame):
a = QuantityAttribute(unit=u.m)
# note that the remainder of this with clause does not get executed
# because an exception is raised here. A future PR is planned to
# allow the default to be left off, after which the rest of this
# test will get executed, so it is being left in place. See
# https://github.com/astropy/astropy/pull/8300 for more info
# we save the transform graph so that it doesn't acidentally mess with other tests
old_transform_graph = baseframe.frame_transform_graph
try:
baseframe.frame_transform_graph = copy.copy(baseframe.frame_transform_graph)
# as reported in 8276, this fails right here because registering the
# transform tries to create a frame attribute
@baseframe.frame_transform_graph.transform(FunctionTransform, MyFrame, AltAz)
def trans(my_frame_coord, altaz_frame):
pass
# should also be able to *create* the Frame at this point
MyFrame()
finally:
baseframe.frame_transform_graph = old_transform_graph
assert 'QuantityAttributes cannot be None' in str(excinfo.value)
......@@ -706,8 +706,8 @@ class CoordinateTransform(metaclass=ABCMeta):
hasattr(tosys, 'get_frame_attr_names')):
# the if statement is there so that non-frame things might be usable
# if it makes sense
for from_nm in fromsys.get_frame_attr_names():
if from_nm in tosys.get_frame_attr_names():
for from_nm in fromsys.frame_attributes.keys():
if from_nm in tosys.frame_attributes.keys():
overlap.append(from_nm)
def register(self, graph):
......
......@@ -1789,12 +1789,12 @@ class LambdaCDM(FLRW):
phi_z1 = phi_z(self._Om0, self._Ok0, kappa, y1, A, z1)
phi_z2 = phi_z(self._Om0, self._Ok0, kappa, y1, A, z2)
# Get lower-right 0<b<2 solution in Om, Ol plane.
# Get lower-right 0<b<2 solution in Om0, Ode0 plane.
# Fot the upper-left 0<b<2 solution the Big Bang didn't happen.
elif (0 < b) and (b < 2) and self._Om0 > self.Ol0:
def phi_z(Om0, Ok0, kappa, y1, A, z):
elif (0 < b) and (b < 2) and self._Om0 > self._Ode0:
def phi_z(Om0, Ok0, y1, y2, z):
return np.arcsin(np.sqrt((y1 - y2) /
(1 + z) * Om0 / abs(Ok0) + y1))
((1 + z) * Om0 / abs(Ok0) + y1)))
yb = cos(acos(1 - b) / 3)
yc = sqrt(3) * sin(acos(1 - b) / 3)
......
......@@ -1623,3 +1623,13 @@ def test_z_at_value_roundtrip():
fval = func(z)
assert allclose(z, funcs.z_at_value(func, fval, zmax=1.5),
rtol=2e-8)
@pytest.mark.skipif('not HAS_SCIPY')
def test_elliptic_comoving_distance_z1z2():
"""Regression test for #8388."""
cosmo = core.LambdaCDM(70., 2.3, 0.05, Tcmb0=0)
z = 0.2
assert allclose(cosmo.comoving_distance(z),
cosmo._integral_comoving_distance_z1z2(0., z))
assert allclose(cosmo._elliptic_comoving_distance_z1z2(0., z),
cosmo._integral_comoving_distance_z1z2(0., z))
......@@ -1423,11 +1423,11 @@ class ColDefs(NotifierMixin):
# Check for unsigned ints.
bzero = None
if 'I' in format and ftype == np.dtype('uint16'):
if 'I' in format and ftype.base == np.dtype('uint16'):
bzero = np.uint16(2**15)
elif 'J' in format and ftype == np.dtype('uint32'):
elif 'J' in format and ftype.base == np.dtype('uint32'):
bzero = np.uint32(2**31)
elif 'K' in format and ftype == np.dtype('uint64'):
elif 'K' in format and ftype.base == np.dtype('uint64'):
bzero = np.uint64(2**63)
c = Column(name=cname, format=format,
......
......@@ -439,7 +439,7 @@ class CompImageHDU(BinTableHDU):
quantize_method : int, optional
Floating point quantization dithering method; can be either
``NO_DITHER`` (-1), ``SUBTRACTIVE_DITHER_1`` (1; default), or
``NO_DITHER`` (-1; default), ``SUBTRACTIVE_DITHER_1`` (1), or
``SUBTRACTIVE_DITHER_2`` (2); see note below
dither_seed : int, optional
......
......@@ -8,7 +8,7 @@ import numpy as np
from numpy.testing import assert_allclose
from astropy.io.fits.column import (_parse_tdisp_format, _fortran_to_python_format,
python_to_tdisp)
python_to_tdisp)
from astropy.io.fits import HDUList, PrimaryHDU, BinTableHDU
......@@ -26,7 +26,7 @@ from astropy.time import Time, TimeDelta
from astropy.units.quantity import QuantityInfo
try:
import yaml # pylint: disable=W0611
import yaml # pylint: disable=W0611 # noqa
HAS_YAML = True
except ImportError:
HAS_YAML = False
......@@ -422,7 +422,7 @@ def test_convert_comment_convention(tmpdir):
Regression test for https://github.com/astropy/astropy/issues/6079
"""
filename = os.path.join(DATA, 'stddata.fits')
with pytest.warns(AstropyUserWarning, catch='hdu= was not specified but '
with pytest.warns(AstropyUserWarning, match='hdu= was not specified but '
'multiple tables are present'):
t = Table.read(filename)
......
......@@ -796,16 +796,14 @@ class TestHDUListFunctions(FitsTestCase):
hdu_b = fits.PrimaryHDU(data=arr_b)
hdu_b.writeto(self.temp('test_b.fits'), overwrite=True)
hdul_a = fits.open(self.temp('test_a.fits'), mode='update',
memmap=mmap_a)
hdul_b = fits.open(self.temp('test_b.fits'), memmap=mmap_b)
hdul_a[0].data = hdul_b[0].data
hdul_a.close()
hdul_b.close()
with fits.open(self.temp('test_a.fits'), mode='update',
memmap=mmap_a) as hdul_a:
with fits.open(self.temp('test_b.fits'),
memmap=mmap_b) as hdul_b:
hdul_a[0].data = hdul_b[0].data