|
from io import BytesIO |
|
|
|
|
|
class CallbackFileWrapper(object): |
|
""" |
|
Small wrapper around a fp object which will tee everything read into a |
|
buffer, and when that file is closed it will execute a callback with the |
|
contents of that buffer. |
|
|
|
All attributes are proxied to the underlying file object. |
|
|
|
This class uses members with a double underscore (__) leading prefix so as |
|
not to accidentally shadow an attribute. |
|
""" |
|
|
|
def __init__(self, fp, callback): |
|
self.__buf = BytesIO() |
|
self.__fp = fp |
|
self.__callback = callback |
|
|
|
def __getattr__(self, name): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fp = self.__getattribute__("_CallbackFileWrapper__fp") |
|
return getattr(fp, name) |
|
|
|
def __is_fp_closed(self): |
|
try: |
|
return self.__fp.fp is None |
|
|
|
except AttributeError: |
|
pass |
|
|
|
try: |
|
return self.__fp.closed |
|
|
|
except AttributeError: |
|
pass |
|
|
|
|
|
|
|
return False |
|
|
|
def _close(self): |
|
if self.__callback: |
|
self.__callback(self.__buf.getvalue()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
self.__callback = None |
|
|
|
def read(self, amt=None): |
|
data = self.__fp.read(amt) |
|
self.__buf.write(data) |
|
if self.__is_fp_closed(): |
|
self._close() |
|
|
|
return data |
|
|
|
def _safe_read(self, amt): |
|
data = self.__fp._safe_read(amt) |
|
if amt == 2 and data == b"\r\n": |
|
|
|
|
|
return data |
|
|
|
self.__buf.write(data) |
|
if self.__is_fp_closed(): |
|
self._close() |
|
|
|
return data |
|
|