def dirlist(self, path, flags=0, timeout=0, callback=None): """List entries of a directory. :param path: path to the directory to list :type path: string :param flags: An `ORed` combination of :mod:`XRootD.client.flags.DirListFlags` where the default is `DirListFlags.NONE` :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and :mod:`XRootD.client.responses.DirectoryList` object .. warning:: Currently, passing `DirListFlags.STAT` with an asynchronous call to :mod:`XRootD.client.FileSystem.dirlist()` does not work, due to an xrootd client limitation. So you'll get ``None`` instead of the ``StatInfo`` instance. See `the GitHub issue <https://github.com/xrootd/xrootd/issues/2>`_ for more details. """ if callback: callback = CallbackWrapper(callback, DirectoryList) return XRootDStatus( self.__fs.dirlist(path, flags, timeout, callback)) status, response = self.__fs.dirlist(path, flags, timeout) if response: response = DirectoryList(response) return XRootDStatus(status), response
def sync(self, timeout=0, callback=None): """Commit all pending disk writes. :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and None """ if callback: callback = CallbackWrapper(callback, None) return XRootDStatus(self.__file.sync(timeout, callback)) status, response = self.__file.sync(timeout) return XRootDStatus(status), None
def visa(self, timeout=0, callback=None): """Get access token to a file. :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and a string """ if callback: callback = CallbackWrapper(callback, None) return XRootDStatus(self.__file.visa(timeout, callback)) status, response = self.__file.visa(timeout) return XRootDStatus(status), response
def list_xattr(self, timeout=0, callback=None): """List all extended file attributes. :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and :mod:`list of touples (string, string, XRootD.client.responses.XRootDStatus)` object """ if callback: callback = CallbackWrapper(callback, list) return XRootDStatus(self.__file.list_xattr(timeout, callback)) status, response = self.__file.list_xattr(timeout) return XRootDStatus(status), response
def ping(self, timeout=0, callback=None): """Check if the server is alive. :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and None """ if callback: callback = CallbackWrapper(callback, None) return XRootDStatus(self.__fs.ping(timeout, callback)) status, response = self.__fs.ping(timeout) return XRootDStatus(status), None
def protocol(self, timeout=0, callback=None): """Obtain server protocol information. :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and :mod:`XRootD.client.responses.ProtocolInfo` object """ if callback: callback = CallbackWrapper(callback, ProtocolInfo) return XRootDStatus(self.__fs.protocol(timeout, callback)) status, response = self.__fs.protocol(timeout) if response: response = ProtocolInfo(response) return XRootDStatus(status), response
def run(self, handler=None): """Run the copy jobs with an optional progress handler. :param handler: a copy progress handler. You can subclass :mod:`XRootD.client.utils.CopyProgressHandler` and implement the three methods (``begin()``, ``progress()`` and ``end()`` ) to get regular progress updates for your copy jobs. """ status, results = self.__process.run(ProgressHandlerWrapper(handler)) for x in results: if 'status' in x: x['status'] = XRootDStatus(x['status']) return XRootDStatus(status), results
def sendinfo(self, info, timeout=0, callback=None): """Send info to the server (up to 1024 characters). :param info: the info string to be sent :type info: string :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and None """ if callback: callback = CallbackWrapper(callback, None) return XRootDStatus(self.__fs.sendinfo(info, timeout, callback)) status, response = self.__fs.sendinfo(info, timeout) return XRootDStatus(status), response
def del_xattr(self, attrs, timeout=0, callback=None): """Delete extended file attributes. :param attrs: list of extended attribute names to be deleted :type attrs: list of strings :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and :mod:`list of touples (string, XRootD.client.responses.XRootDStatus)` object """ if callback: callback = CallbackWrapper(callback, list) return XRootDStatus(self.__file.del_xattr(attrs, timeout, callback)) status, response = self.__file.del_xattr(attrs, timeout) return XRootDStatus(status), response
def set_xattr(self, attrs, timeout=0, callback=None): """Set extended file attributes. :param attrs: extended attributes to be set on the file :type attrs: list of tuples of name/value pairs :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and :mod:`list of touples (string, XRootD.client.responses.XRootDStatus)` object """ if callback: callback = CallbackWrapper(callback, list) return XRootDStatus(self.__file.set_xattr(attrs, timeout, callback)) status, response = self.__file.set_xattr(attrs, timeout) return XRootDStatus(status), response
def truncate(self, size, timeout=0, callback=None): """Truncate the file to a particular size. :param size: desired size of the file :type size: integer :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and None """ if callback: callback = CallbackWrapper(callback, None) return XRootDStatus(self.__file.truncate(size, timeout, callback)) status, response = self.__file.truncate(size, timeout) return XRootDStatus(status), None
def rmdir(self, path, timeout=0, callback=None): """Remove a directory. :param path: path to the directory to remove :type path: string :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and None """ if callback: callback = CallbackWrapper(callback, None) return XRootDStatus(self.__fs.rmdir(path, timeout, callback)) status, response = self.__fs.rmdir(path, timeout) return XRootDStatus(status), None
def fcntl(self, arg, timeout=0, callback=None): """Perform a custom operation on an open file. :param arg: argument :type arg: string :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and a string """ if callback: callback = CallbackWrapper(callback, None) return XRootDStatus(self.__file.fcntl(arg, timeout, callback)) status, response = self.__file.fcntl(arg, timeout) return XRootDStatus(status), response
def chmod(self, path, mode, timeout=0, callback=None): """Change access mode on a directory or a file. :param path: path to the file/directory to change access mode :type path: string :param mode: An `OR`ed` combination of :mod:`XRootD.client.flags.AccessMode` :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and None """ if callback: callback = CallbackWrapper(callback, None) return XRootDStatus(self.__fs.chmod(path, mode, timeout, callback)) status, response = self.__fs.chmod(path, mode, timeout) return XRootDStatus(status), None
def stat(self, force=False, timeout=0, callback=None): """Obtain status information for this file. :param force: do not use the cached information, force re-stating :type force: boolean :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and :mod:`XRootD.client.responses.StatInfo` object """ if callback: callback = CallbackWrapper(callback, StatInfo) return XRootDStatus(self.__file.stat(force, timeout, callback)) status, response = self.__file.stat(force, timeout) if response: response = StatInfo(response) return XRootDStatus(status), response
def statvfs(self, path, timeout=0, callback=None): """Obtain status information for a Virtual File System. :param path: path to the file/directory to stat :type path: string :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and :mod:`XRootD.client.responses.StatInfoVFS` object """ if callback: callback = CallbackWrapper(callback, StatInfoVFS) return XRootDStatus(self.__fs.statvfs(path, timeout, callback)) status, response = self.__fs.statvfs(path, timeout) if response: response = StatInfoVFS(response) return XRootDStatus(status), response
def truncate(self, path, size, timeout=0, callback=None): """Truncate a file. :param path: path to the file to be truncated :type path: string :param size: file size :type size: integer :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and None """ if callback: callback = CallbackWrapper(callback, None) return XRootDStatus(self.__fs.truncate(path, size, timeout, callback)) status, response = self.__fs.truncate(path, size, timeout) return XRootDStatus(status), None
def mv(self, source, dest, timeout=0, callback=None): """Move a directory or a file. :param source: the file or directory to be moved :type source: string :param dest: the new name :type dest: string :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and None """ if callback: callback = CallbackWrapper(callback, None) return XRootDStatus(self.__fs.mv(source, dest, timeout, callback)) status, response = self.__fs.mv(source, dest, timeout) return XRootDStatus(status), None
def test_write(tmppath): """Test write().""" # With a new file. xfile = XRootDPyFile(mkurl(join(tmppath, 'data/nuts')), 'w+') assert xfile.size == 0 conts = xfile.read() assert not conts nconts = 'Write.' xfile.write(nconts) assert xfile.tell() == len(nconts) assert not xfile.closed xfile.seek(0) assert xfile.size == len(nconts) assert xfile.read() == nconts.encode() xfile.close() # Verify persistence after closing. xfile = XRootDPyFile(mkurl(join(tmppath, 'data/nuts')), 'r+') assert xfile.size == len(nconts) assert xfile.read() == nconts.encode() # Seek(x>0) followed by a write nc2 = 'hello' cntr = len(nconts) // 2 xfile.seek(cntr) xfile.write(nc2) assert xfile.tell() == len(nc2) + cntr xfile.seek(0) expected = nconts[:cntr] + nc2 assert xfile.read() == expected.encode() xfile.close() # Seek(x>0) followed by a write of len < size-x fd = get_tsta_file(tmppath) fp, fc = fd['full_path'], fd['contents'] xfile = XRootDPyFile(mkurl(fp), 'r+') assert xfile.read() == fc.encode() xfile.seek(2) nc = 'yo' xfile.write(nc) assert xfile.tell() == len(nc) + 2 assert xfile.read() == fc[2 + len(nc):].encode() # run w/ flushing == true xfile.write('', True) # Mock an error, yayy! fake_status = { "status": 3, "code": 0, "ok": False, "errno": errno.EREMOTE, "error": True, "message": '[FATAL] Remote I/O Error', "fatal": True, "shellcode": 51 } xfile._file.write = Mock(return_value=(XRootDStatus(fake_status), None)) pytest.raises(IOError, xfile.write, '')
def test_read_existing(tmppath): """Test read() on an existing non-empty file.""" fd = get_tsta_file(tmppath) full_path, fc = fd['full_path'], fd['contents'] xfile = XRootDPyFile(mkurl(full_path)) res = xfile.read() assert res == fc # After having read the entire file, the file pointer is at the # end of the file and consecutive reads return the empty string. assert xfile.read() == '' # reset ipp to start xfile.seek(0) assert xfile.read(1) == fc[0] assert xfile.read(2) == fc[1:3] overflow_read = xfile.read(len(fc)) assert overflow_read == fc[3:] # Mock an error, yayy! fake_status = { "status": 3, "code": 0, "ok": False, "errno": errno.EREMOTE, "error": True, "message": '[FATAL] Remote I/O Error', "fatal": True, "shellcode": 51 } xfile._file.read = Mock(return_value=(XRootDStatus(fake_status), None)) pytest.raises(IOError, xfile.read)
def test_truncate1(tmppath): """Test truncate(0).""" fd = get_tsta_file(tmppath) full_path, fc = fd['full_path'], fd['contents'] xfile = XRootDPyFile(mkurl(full_path), 'r+') # r+ opens for r/w, and won't truncate the file automatically. assert xfile.read() == fc assert xfile.tell() == len(fc) xfile.seek(0) # Reset ipp. assert xfile.tell() == 0 # Truncate it to size 0. xfile.truncate(0) assert xfile.size == 0 assert xfile.tell() == 0 assert xfile.read() == '' assert xfile.tell() == 0 xfile.close() # Re-open same file. xfile = XRootDPyFile(mkurl(full_path), 'r+') assert xfile.size == 0 assert xfile.read() == '' # Truncate it again! xfile.truncate(0) assert xfile.size == 0 assert xfile.read() == '' # Truncate it twice. xfile.truncate(0) assert xfile.size == 0 assert xfile.read() == '' # Truncate to 1. xfile.truncate(1) assert xfile.tell() == 0 assert xfile.size == 1 xfile.seek(0) assert xfile.read() == '\x00' assert xfile.tell() == 1 xfile.close() xfile = XRootDPyFile(mkurl(full_path), 'r+') assert xfile.size == 1 assert xfile.read() == '\x00' # Mock it. fake_status = { "status": 3, "code": 0, "ok": False, "errno": errno.EREMOTE, "error": True, "message": '[FATAL] Remote I/O Error', "fatal": True, "shellcode": 51 } xfile._file.truncate = Mock(return_value=(XRootDStatus(fake_status), None)) pytest.raises(IOError, xfile.truncate, 0)
def test_flush(tmppath): """Tests for flush()""" # Mostly it just ensures calling it doesn't crash the program. fd = get_tsta_file(tmppath) full_path, fc = fd['full_path'], fd['contents'] xfile = XRootDPyFile(mkurl(full_path), 'w') writestr = 'whut' xfile.flush() xfile.seek(0, SEEK_END) xfile.write(writestr) xfile.flush() xfile.close() xfile = XRootDPyFile(mkurl(full_path), 'r') assert xfile.read() == writestr # Fake/mock an error response fake_status = { "status": 3, "code": 0, "ok": False, "errno": errno.EREMOTE, "error": True, "message": '[FATAL] Remote I/O Error', "fatal": True, "shellcode": 51 } # Assign mock return value to the file's sync() function # (which is called by flush()) xfile._file.sync = Mock(return_value=(XRootDStatus(fake_status), None)) pytest.raises(IOError, xfile.flush)
def deeplocate(self, path, flags, timeout=0, callback=None): """Locate a file, recursively locate all disk servers. :param path: path to the file to be located :type path: string :param flags: An `ORed` combination of :mod:`XRootD.client.flags.OpenFlags` :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and :mod:`XRootD.client.responses.LocationInfo` object """ if callback: callback = CallbackWrapper(callback, LocationInfo) return XRootDStatus(self.__fs.deeplocate(path, flags, timeout, callback)) status, response = self.__fs.deeplocate(path, flags, timeout) if response: response = LocationInfo(response) return XRootDStatus(status), response
def test_remove_dir_mock2(tmppath): """Test removedir.""" fs = XRootDPyFS(mkurl(tmppath)) status = XRootDStatus({ "status": 3, "code": 101, "ok": False, "errno": 0, "error": True, "message": '[FATAL] Invalid address', "fatal": True, "shellcode": 51 }) def fail(f, fail_on): @wraps(f) def inner(path, **kwargs): if path == fail_on: return (status, None) return f(path, **kwargs) return inner fs.xrd_client.rmdir = fail(fs.xrd_client.rmdir, fs._p("data/bfolder/")) pytest.raises(ResourceError, fs.removedir, "data/", force=True)
def read(self, offset=0, size=0, timeout=0, callback=None): """Read a data chunk from a given offset. :param offset: offset from the beginning of the file :type offset: integer :param size: number of bytes to be read :type size: integer :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and the data that was read """ if callback: callback = CallbackWrapper(callback, None) return XRootDStatus(self.__file.read(offset, size, timeout, callback)) status, response = self.__file.read(offset, size, timeout) return XRootDStatus(status), response
def write(self, buffer, offset=0, size=0, timeout=0, callback=None): """Write a data chunk at a given offset. :param buffer: data to be written :param offset: offset from the beginning of the file :type offset: integer :param size: number of bytes to be written :type size: integer :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and None """ if callback: callback = CallbackWrapper(callback, None) return XRootDStatus(self.__file.write(buffer, offset, size, timeout, callback)) status, response = self.__file.write(buffer, offset, size, timeout) return XRootDStatus(status), None
def prepare(self, files, flags, priority=0, timeout=0, callback=None): """Prepare one or more files for access. :param files: list of files to be prepared :type files: list :param flags: An `ORed` combination of :mod:`XRootD.client.flags.PrepareFlags` :param priority: priority of the request 0 (lowest) - 3 (highest) :type priority: integer :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and None """ if callback: callback = CallbackWrapper(callback, None) return XRootDStatus( self.__fs.prepare(files, flags, priority, timeout, callback)) status, response = self.__fs.prepare(files, flags, priority, timeout) return XRootDStatus(status), response
def open(self, url, flags=0, mode=0, timeout=0, callback=None): """Open the file pointed to by the given URL. :param url: url of the file to be opened :type url: string :param flags: An `ORed` combination of :mod:`XRootD.client.flags.OpenFlags` where the default is `OpenFlags.NONE` :param mode: access mode for new files, an `ORed` combination of :mod:`XRootD.client.flags.AccessMode` where the default is `AccessMode.NONE` :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and None """ if callback: callback = CallbackWrapper(callback, None) return XRootDStatus(self.__file.open(url, flags, mode, timeout, callback)) status, response = self.__file.open(url, flags, mode, timeout) return XRootDStatus(status), None
def __call__(self, status, response, *argv): self.status = XRootDStatus(status) self.response = response if self.responsetype: self.response = self.responsetype(response) if argv: self.hostlist = HostList(argv[0]) else: self.hostlist = HostList([]) self.callback(self.status, self.response, self.hostlist)
def vector_read(self, chunks, timeout=0, callback=None): """Read scattered data chunks in one operation. :param chunks: list of the chunks to be read. The default maximum chunk size is 2097136 bytes and the default maximum number of chunks per request is 1024. The server may be queried using :func:`XRootD.client.FileSystem.query` for the actual settings. :type chunks: list of 2-tuples of the form (offset, size) :returns: tuple containing :mod:`XRootD.client.responses.XRootDStatus` object and :mod:`XRootD.client.responses.VectorReadInfo` object """ if callback: callback = CallbackWrapper(callback, VectorReadInfo) return XRootDStatus(self.__file.vector_read(chunks, timeout, callback)) status, response = self.__file.vector_read(chunks, timeout) if response: response = VectorReadInfo(response) return XRootDStatus(status), response