def update(filename, data, *args, **kwargs): """ Update the specified extension with the input data/header. Parameters ---------- filename : file path, file object, or file like object File to update. If opened, mode must be update (rb+). An opened file object or `GzipFile` object will be closed upon return. data : array, table, or group data object the new data used for updating header : `Header` object (optional) The header associated with `data`. If `None`, an appropriate header will be created for the data object supplied. ext, extname, extver The rest of the arguments are flexible: the 3rd argument can be the header associated with the data. If the 3rd argument is not a `Header`, it (and other positional arguments) are assumed to be the extension specification(s). Header and extension specs can also be keyword arguments. For example:: >>> update(file, dat, hdr, 'sci') # update the 'sci' extension >>> update(file, dat, 3) # update the 3rd extension >>> update(file, dat, hdr, 3) # update the 3rd extension >>> update(file, dat, 'sci', 2) # update the 2nd SCI extension >>> update(file, dat, 3, header=hdr) # update the 3rd extension >>> update(file, dat, header=hdr, ext=5) # update the 5th extension kwargs Any additional keyword arguments to be passed to `pyfits.open`. """ # The arguments to this function are a bit tricker to deal with than others # in this module, since the documentation has promised that the header # argument can be an optional positional argument. if args and isinstance(args[0], Header): header = args[0] args = args[1:] else: header = None # The header can also be a keyword argument--if both are provided the # keyword takes precedence header = kwargs.pop('header', header) new_hdu = _makehdu(data, header) closed = fileobj_closed(filename) hdulist, _ext = _getext(filename, 'update', *args, **kwargs) hdulist[_ext] = new_hdu hdulist.close(closed=closed)
def _stat_filename_or_fileobj(filename): closed = fileobj_closed(filename) name = fileobj_name(filename) or '' try: loc = filename.tell() except AttributeError: loc = 0 noexist_or_empty = ((name and (not os.path.exists(name) or (os.path.getsize(name) == 0))) or (not name and loc == 0)) return name, closed, noexist_or_empty
def _open_fileobj(self, fileobj, mode): """Open a FITS file from a file object or a GzipFile object.""" closed = fileobj_closed(fileobj) fmode = fileobj_mode(fileobj) or PYTHON_MODES[mode] if not closed: # In some cases (like on Python 3) a file opened for appending # still shows a mode of 'r+', hence the extra check for the append # case if ((mode == 'append' and fmode not in ('ab+', 'rb+')) or (mode != 'append' and PYTHON_MODES[mode] != fmode)): raise ValueError( "Input mode '%s' (%s) does not match mode of the " "input file (%s)." % (mode, PYTHON_MODES[mode], fmode)) self.__file = fileobj elif isfile(fileobj): self.__file = fileobj_open(self.name, PYTHON_MODES[mode]) # Return to the beginning of the file--in Python 3 when opening in # append mode the file pointer is at the end of the file self.__file.seek(0) else: self.__file = gzip.open(self.name, PYTHON_MODES[mode])
def writeto(self, fileobj, output_verify='exception', clobber=False, checksum=False): """ Write the `HDUList` to a new file. Parameters ---------- fileobj : file path, file object or file-like object File to write to. If a file object, must be opened for append (ab+). output_verify : str Output verification option. Must be one of ``"fix"``, ``"silentfix"``, ``"ignore"``, ``"warn"``, or ``"exception"``. See :ref:`verify` for more info. clobber : bool When `True`, overwrite the output file if exists. checksum : bool When `True` adds both ``DATASUM`` and ``CHECKSUM`` cards to the headers of all HDU's written to the file. """ if (len(self) == 0): warnings.warn("There is nothing to write.") return self.verify(option=output_verify) # check if the file object is closed closed = fileobj_closed(fileobj) fmode = fileobj_mode(fileobj) or 'ab+' filename = fileobj_name(fileobj) # check if the output file already exists if (isfile(fileobj) or isinstance(fileobj, (basestring, gzip.GzipFile))): if (os.path.exists(filename) and os.path.getsize(filename) != 0): if clobber: warnings.warn("Overwriting existing file '%s'." % filename) if not closed: fileobj.close() os.remove(filename) else: raise IOError("File '%s' already exists." % filename) elif (hasattr(fileobj, 'len') and fileobj.len > 0): if clobber: warnings.warn("Overwriting existing file '%s'." % filename) name.truncate(0) else: raise IOError("File '%s' already exists." % filename) # make sure the EXTEND keyword is there if there is extension self.update_extend() mode = 'copyonwrite' for key, val in PYTHON_MODES.iteritems(): if val == fmode: mode = key break hdulist = fitsopen(fileobj, mode=mode) for hdu in self: hdu._prewriteto(checksum=checksum) try: hdu._writeto(hdulist.__file) finally: hdu._postwriteto() hdulist.close(output_verify=output_verify, closed=closed)
def __init__(self, fileobj=None, mode='readonly', memmap=False): if fileobj is None: self.__file = None self.closed = False self.mode = mode self.memmap = memmap self.compression = None self.readonly = False self.writeonly = False self.simulateonly = True return else: self.simulateonly = False if mode not in PYTHON_MODES: raise ValueError("Mode '%s' not recognized" % mode) if (isinstance(fileobj, basestring) and mode != 'append' and not os.path.exists(fileobj) and not os.path.splitdrive(fileobj)[0]): # # Not writing file and file does not exist on local machine and # name does not begin with a drive letter (Windows), try to # get it over the web. # self.name, _ = urllib.urlretrieve(fileobj) else: self.name = fileobj_name(fileobj) self.closed = False self.mode = mode self.memmap = memmap # Underlying fileobj is a file-like object, but an actual file object self.file_like = False # More defaults to be adjusted below as necessary self.compression = None self.readonly = False self.writeonly = False # Initialize the internal self.__file object if isfile(fileobj) or isinstance(fileobj, gzip.GzipFile): closed = fileobj_closed(fileobj) fmode = fileobj_mode(fileobj) or PYTHON_MODES[mode] if not closed: # In some cases (like on Python 3) a file opened for # appending still shows a mode of 'r+', hence the extra # check for the append case if ((mode == 'append' and fmode not in ('ab+', 'rb+')) or (mode != 'append' and PYTHON_MODES[mode] != fmode)): raise ValueError( "Input mode '%s' (%s) does not match mode of the " "input file (%s)." % (mode, PYTHON_MODES[mode], fmode)) self.__file = fileobj elif isfile(fileobj): self.__file = fileobj_open(self.name, PYTHON_MODES[mode]) # Return to the beginning of the file--in Python 3 when # opening in append mode the file pointer is at the end of # the file self.__file.seek(0) else: self.__file = gzip.open(self.name, PYTHON_MODES[mode]) elif isinstance(fileobj, basestring): if os.path.exists(self.name): with fileobj_open(self.name, 'rb') as f: magic = f.read(4) else: magic = ''.encode('raw-unicode-escape') ext = os.path.splitext(self.name)[1] if ext == '.gz' or magic.startswith(GZIP_MAGIC): # Handle gzip files if mode in ['update', 'append']: raise IOError( "Writing to gzipped fits files is not currently " "supported") self.__file = gzip.open(self.name) self.compression = 'gzip' elif ext == '.zip' or magic.startswith(PKZIP_MAGIC): # Handle zip files if mode in ['update', 'append']: raise IOError( "Writing to zipped fits files is not currently " "supported") zfile = zipfile.ZipFile(self.name) namelist = zfile.namelist() if len(namelist) != 1: raise IOError( "Zip files with multiple members are not supported.") self.__file = tempfile.NamedTemporaryFile(suffix='.fits') self.__file.write(zfile.read(namelist[0])) zfile.close() self.compression = 'zip' else: self.__file = fileobj_open(self.name, PYTHON_MODES[mode]) # Make certain we're back at the beginning of the file self.__file.seek(0) else: # We are dealing with a file like object. # Assume it is open. self.file_like = True self.__file = fileobj # If there is not seek or tell methods then set the mode to # output streaming. if (not hasattr(self.__file, 'seek') or not hasattr(self.__file, 'tell')): self.mode = mode = 'ostream' if (self.mode in ('copyonwrite', 'update', 'append') and not hasattr(self.__file, 'write')): raise IOError("File-like object does not have a 'write' " "method, required for mode '%s'." % self.mode) if (self.mode in ('readonly', 'denywrite') and not hasattr(self.__file, 'read')): raise IOError("File-like object does not have a 'read' " "method, required for mode %r." % self.mode) if isinstance(fileobj, gzip.GzipFile): self.compression = 'gzip' elif isinstance(fileobj, zipfile.ZipFile): # Reading from zip files is supported but not writing (yet) self.compression = 'zip' if (mode in ('readonly', 'copyonwrite', 'denywrite') or (self.compression and mode == 'update')): self.readonly = True elif (mode == 'ostream' or (self.compression and mode == 'append')): self.writeonly = True # For 'ab+' mode, the pointer is at the end after the open in # Linux, but is at the beginning in Solaris. if (mode == 'ostream' or self.compression or not hasattr(self.__file, 'seek')): # For output stream start with a truncated file. # For compressed files we can't really guess at the size self.size = 0 else: pos = self.__file.tell() self.__file.seek(0, 2) self.size = self.__file.tell() self.__file.seek(pos) if self.memmap and not isfile(self.__file): self.memmap = False