Skip to content

BUG: a failing io.fits test #18880

@neutrinoceros

Description

@neutrinoceros
pytest astropy/io/fits/tests/test_fitsdiff.py::TestFITSDiff_script::test_path -ra --run-slow
Detailled output
astropy/io/fits/tests/test_fitsdiff.py F                                                                                                                                                                     [100%]

===================================================================================================== FAILURES =====================================================================================================
__________________________________________________________________________________________ TestFITSDiff_script.test_path ___________________________________________________________________________________________

self = <astropy.io.fits.diff.FITSDiff object at 0x1056d75c0>, a = '/Users/clm/dev/orgs/astropy-project/coordinated/astropy/astropy/io/fits/tests/data/lzw.fits.Z'
b = '/Users/clm/dev/orgs/astropy-project/coordinated/astropy/astropy/io/fits/tests/data/lzw.fits.Z', ignore_hdus = [], ignore_keywords = [], ignore_comments = [], ignore_fields = [], numdiffs = 10, rtol = 0.0
atol = 0.0, ignore_blanks = True, ignore_blank_cards = True

    def __init__(
        self,
        a,
        b,
        ignore_hdus=[],
        ignore_keywords=[],
        ignore_comments=[],
        ignore_fields=[],
        numdiffs=10,
        rtol=0.0,
        atol=0.0,
        ignore_blanks=True,
        ignore_blank_cards=True,
    ):
        """
        Parameters
        ----------
        a : str or `HDUList`
            The filename of a FITS file on disk, or an `HDUList` object.

        b : str or `HDUList`
            The filename of a FITS file on disk, or an `HDUList` object to
            compare to the first file.

        ignore_hdus : sequence, optional
            HDU names to ignore when comparing two FITS files or HDU lists; the
            presence of these HDUs and their contents are ignored.  Wildcard
            strings may also be included in the list.

        ignore_keywords : sequence, optional
            Header keywords to ignore when comparing two headers; the presence
            of these keywords and their values are ignored.  Wildcard strings
            may also be included in the list.

        ignore_comments : sequence, optional
            A list of header keywords whose comments should be ignored in the
            comparison.  May contain wildcard strings as with ignore_keywords.

        ignore_fields : sequence, optional
            The (case-insensitive) names of any table columns to ignore if any
            table data is to be compared.

        numdiffs : int, optional
            The number of pixel/table values to output when reporting HDU data
            differences.  Though the count of differences is the same either
            way, this allows controlling the number of different values that
            are kept in memory or output.  If a negative value is given, then
            numdiffs is treated as unlimited (default: 10).

        rtol : float, optional
            The relative difference to allow when comparing two float values
            either in header values, image arrays, or table columns
            (default: 0.0). Values which satisfy the expression

            .. math::

                \\left| a - b \\right| > \\text{atol} + \\text{rtol} \\cdot \\left| b \\right|

            are considered to be different.
            The underlying function used for comparison is `numpy.allclose`.

            .. versionadded:: 2.0

        atol : float, optional
            The allowed absolute difference. See also ``rtol`` parameter.

            .. versionadded:: 2.0

        ignore_blanks : bool, optional
            Ignore extra whitespace at the end of string values either in
            headers or data. Extra leading whitespace is not ignored
            (default: True).

        ignore_blank_cards : bool, optional
            Ignore all cards that are blank, i.e. they only contain
            whitespace (default: True).
        """
        if isinstance(a, (str, os.PathLike)):
            try:
>               a = fitsopen(a)
                    ^^^^^^^^^^^

astropy/io/fits/diff.py:293:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
astropy/io/fits/hdu/hdulist.py:227: in fitsopen
    return HDUList.fromfile(
astropy/io/fits/hdu/hdulist.py:491: in fromfile
    return cls._readfrom(
astropy/io/fits/hdu/hdulist.py:1174: in _readfrom
    fileobj = _File(
astropy/io/fits/file.py:240: in __init__
    self._open_filename(fileobj, mode, overwrite)
astropy/io/fits/file.py:700: in _open_filename
    if not self._try_read_compressed(self.name, magic, mode, ext=ext):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <astropy.io.fits.file._File None>, obj_or_name = '/Users/clm/dev/orgs/astropy-project/coordinated/astropy/astropy/io/fits/tests/data/lzw.fits.Z', magic = b'\x1f\x9d\x90S\x924', mode = 'readonly'
ext = '.Z'

    def _try_read_compressed(self, obj_or_name, magic, mode, ext=""):
        """Attempt to determine if the given file is compressed."""
        is_ostream = mode == "ostream"
        if (is_ostream and ext == ".gz") or magic.startswith(GZIP_MAGIC):
            if mode == "append":
                raise OSError(
                    "'append' mode is not supported with gzip files."
                    "Use 'update' mode instead"
                )
            # Handle gzip files
            kwargs = {"mode": IO_FITS_MODES[mode]}
            if isinstance(obj_or_name, str):
                kwargs["filename"] = obj_or_name
            else:
                kwargs["fileobj"] = obj_or_name
            self._file = gzip.GzipFile(**kwargs)
            self.compression = "gzip"
        elif (is_ostream and ext == ".zip") or magic.startswith(PKZIP_MAGIC):
            # Handle zip files
            self._open_zipfile(self.name, mode)
            self.compression = "zip"
        elif (is_ostream and ext == ".bz2") or magic.startswith(BZIP2_MAGIC):
            # Handle bzip2 files
            if mode in ["update", "append"]:
                raise OSError(
                    "update and append modes are not supported with bzip2 files"
                )
            if not HAS_BZ2:
                raise ModuleNotFoundError(
                    "This Python installation does not provide the bz2 module."
                )
            # bzip2 only supports 'w' and 'r' modes
            bzip2_mode = "w" if is_ostream else "r"
            self._file = bz2.BZ2File(obj_or_name, mode=bzip2_mode)
            self.compression = "bzip2"
        elif (is_ostream and ext == ".xz") or magic.startswith(LZMA_MAGIC):
            # Handle lzma files
            if mode in ["update", "append"]:
                raise OSError(
                    "update and append modes are not supported with lzma files"
                )
            if not HAS_LZMA:
                raise ModuleNotFoundError(
                    "This Python installation does not provide the lzma module."
                )
            lzma_mode = "w" if is_ostream else "r"
            self._file = lzma.LZMAFile(obj_or_name, mode=lzma_mode)
            self.compression = "lzma"
        elif (is_ostream and ext == ".Z") or magic.startswith(LZW_MAGIC):
            # Handle LZW files
            if mode in ["update", "append", "ostream"]:
                raise OSError(f"{mode} mode not supported with LZW files")
            if not HAS_UNCOMPRESSPY:
>               raise ModuleNotFoundError(
                    "The optional package uncompresspy is necessary for reading"
                    " LZW compressed files (.Z extension)."
                )
E               ModuleNotFoundError: The optional package uncompresspy is necessary for reading LZW compressed files (.Z extension).

astropy/io/fits/file.py:604: ModuleNotFoundError

The above exception was the direct cause of the following exception:

self = <astropy.io.fits.tests.test_fitsdiff.TestFITSDiff_script object at 0x105655790>, capsys = <_pytest.capture.CaptureFixture object at 0x1056dcc20>

    @pytest.mark.slow
    def test_path(self, capsys):
        os.mkdir(self.temp("sub/"))
        tmp_b = self.temp("sub/ascii.fits")

        tmp_g = self.temp("sub/group.fits")
        tmp_h = self.data("group.fits")
        with hdulist.fitsopen(tmp_h) as hdu_b:
            hdu_b.writeto(tmp_g)

        writeto(tmp_b, np.arange(100).reshape(10, 10))

        # one modified file and a directory
        assert fitsdiff.main(["-q", self.data_dir, tmp_b]) == 1
        assert fitsdiff.main(["-q", tmp_b, self.data_dir]) == 1

        # two directories
        tmp_d = self.temp("sub/")
        assert fitsdiff.main(["-q", self.data_dir, tmp_d]) == 1
        assert fitsdiff.main(["-q", tmp_d, self.data_dir]) == 1
>       assert fitsdiff.main(["-q", self.data_dir, self.data_dir]) == 0
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

astropy/io/fits/tests/test_fitsdiff.py:259:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
astropy/io/fits/scripts/fitsdiff.py:401: in main
    diff = fits.diff.FITSDiff(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <astropy.io.fits.diff.FITSDiff object at 0x1056d75c0>, a = '/Users/clm/dev/orgs/astropy-project/coordinated/astropy/astropy/io/fits/tests/data/lzw.fits.Z'
b = '/Users/clm/dev/orgs/astropy-project/coordinated/astropy/astropy/io/fits/tests/data/lzw.fits.Z', ignore_hdus = [], ignore_keywords = [], ignore_comments = [], ignore_fields = [], numdiffs = 10, rtol = 0.0
atol = 0.0, ignore_blanks = True, ignore_blank_cards = True

    def __init__(
        self,
        a,
        b,
        ignore_hdus=[],
        ignore_keywords=[],
        ignore_comments=[],
        ignore_fields=[],
        numdiffs=10,
        rtol=0.0,
        atol=0.0,
        ignore_blanks=True,
        ignore_blank_cards=True,
    ):
        """
        Parameters
        ----------
        a : str or `HDUList`
            The filename of a FITS file on disk, or an `HDUList` object.

        b : str or `HDUList`
            The filename of a FITS file on disk, or an `HDUList` object to
            compare to the first file.

        ignore_hdus : sequence, optional
            HDU names to ignore when comparing two FITS files or HDU lists; the
            presence of these HDUs and their contents are ignored.  Wildcard
            strings may also be included in the list.

        ignore_keywords : sequence, optional
            Header keywords to ignore when comparing two headers; the presence
            of these keywords and their values are ignored.  Wildcard strings
            may also be included in the list.

        ignore_comments : sequence, optional
            A list of header keywords whose comments should be ignored in the
            comparison.  May contain wildcard strings as with ignore_keywords.

        ignore_fields : sequence, optional
            The (case-insensitive) names of any table columns to ignore if any
            table data is to be compared.

        numdiffs : int, optional
            The number of pixel/table values to output when reporting HDU data
            differences.  Though the count of differences is the same either
            way, this allows controlling the number of different values that
            are kept in memory or output.  If a negative value is given, then
            numdiffs is treated as unlimited (default: 10).

        rtol : float, optional
            The relative difference to allow when comparing two float values
            either in header values, image arrays, or table columns
            (default: 0.0). Values which satisfy the expression

            .. math::

                \\left| a - b \\right| > \\text{atol} + \\text{rtol} \\cdot \\left| b \\right|

            are considered to be different.
            The underlying function used for comparison is `numpy.allclose`.

            .. versionadded:: 2.0

        atol : float, optional
            The allowed absolute difference. See also ``rtol`` parameter.

            .. versionadded:: 2.0

        ignore_blanks : bool, optional
            Ignore extra whitespace at the end of string values either in
            headers or data. Extra leading whitespace is not ignored
            (default: True).

        ignore_blank_cards : bool, optional
            Ignore all cards that are blank, i.e. they only contain
            whitespace (default: True).
        """
        if isinstance(a, (str, os.PathLike)):
            try:
                a = fitsopen(a)
            except Exception as exc:
>               raise OSError(f"error opening file a ({a})") from exc
E               OSError: error opening file a (/Users/clm/dev/orgs/astropy-project/coordinated/astropy/astropy/io/fits/tests/data/lzw.fits.Z)

astropy/io/fits/diff.py:295: OSError

bisected to 92b38ae (#17960), which was merged more than 6 months ago.
While the test is rarely run, because it's marked as @pytest.mark.slow, I don't understand why I'm only seeing it in logs now.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions