Skip to content

Please support os.PathLike #11579

Description

@olebole

Description

When I try to open a FITS file with a path like object which is not dircetly a pathlib.Path, I get a failure:

import os

class DummyPath(os.Pathlike):
    def __init__(self, path):
        self.path = path

    def __fspath__(self):
        return str(self.path)

With the normal open, this works fine:

>>> p = DummyPath('foo.txt')
>>> fp = open(p)
>>> print(fp.read()
A big brown fox

But it does not work with astropy.io.fits:

>>> from astropy.io import fits
>>> f = DummyPath('foo.fits')
>>> fits.open(f)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3/dist-packages/astropy/io/fits/hdu/hdulist.py", line 164, in fitsopen
    return HDUList.fromfile(name, mode, memmap, save_backup, cache,
  File "/usr/lib/python3/dist-packages/astropy/io/fits/hdu/hdulist.py", line 401, in fromfile
    return cls._readfrom(fileobj=fileobj, mode=mode, memmap=memmap,
  File "/usr/lib/python3/dist-packages/astropy/io/fits/hdu/hdulist.py", line 1052, in _readfrom
    fileobj = _File(fileobj, mode=mode, memmap=memmap, cache=cache)
  File "/usr/lib/python3/dist-packages/astropy/utils/decorators.py", line 535, in wrapper
    return function(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/astropy/io/fits/file.py", line 177, in __init__
    self._open_filelike(fileobj, mode, overwrite)
  File "/usr/lib/python3/dist-packages/astropy/io/fits/file.py", line 541, in _open_filelike
    raise OSError("File-like object does not have a 'write' "
OSError: File-like object does not have a 'write' method, required for mode 'ostream'.

Having os.PathLike supported would make it easy to implement f.e. a cache, where __fspath__() could handle the creation or download of a requested file before opening.

For fits, I would guess that the problem is that pathlib.Path is hardcoded:

# If fileobj is of type pathlib.Path
if isinstance(fileobj, pathlib.Path):
fileobj = str(fileobj)

This could be replaced with checking for os.PathLike, and accessing the string with __fspath__() instead, but there may be other places as well. A simple grep shows that isinstance(…, pathlib.Path) is used here:

  • io/registry.py
  • io/fits/util.py
  • io/fits/convenience.py
  • io/fits/file.py (this is the one shown above)
  • io/fits/diff.py
  • config/configuration.py

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions