_fileobjectcommon.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. try:
  2. from errno import EBADF
  3. except ImportError:
  4. EBADF = 9
  5. from io import TextIOWrapper
  6. class cancel_wait_ex(IOError):
  7. def __init__(self):
  8. super(cancel_wait_ex, self).__init__(
  9. EBADF, 'File descriptor was closed in another greenlet')
  10. class FileObjectClosed(IOError):
  11. def __init__(self):
  12. super(FileObjectClosed, self).__init__(
  13. EBADF, 'Bad file descriptor (FileObject was closed)')
  14. class FileObjectBase(object):
  15. """
  16. Internal base class to ensure a level of consistency
  17. between FileObjectPosix and FileObjectThread
  18. """
  19. # List of methods we delegate to the wrapping IO object, if they
  20. # implement them and we do not.
  21. _delegate_methods = (
  22. # General methods
  23. 'flush',
  24. 'fileno',
  25. 'writable',
  26. 'readable',
  27. 'seek',
  28. 'seekable',
  29. 'tell',
  30. # Read
  31. 'read',
  32. 'readline',
  33. 'readlines',
  34. 'read1',
  35. # Write
  36. 'write',
  37. 'writelines',
  38. 'truncate',
  39. )
  40. # Whether we are translating universal newlines or not.
  41. _translate = False
  42. def __init__(self, io, closefd):
  43. """
  44. :param io: An io.IOBase-like object.
  45. """
  46. self._io = io
  47. # We don't actually use this property ourself, but we save it (and
  48. # pass it along) for compatibility.
  49. self._close = closefd
  50. if self._translate:
  51. # This automatically handles delegation.
  52. self.translate_newlines(None)
  53. else:
  54. self._do_delegate_methods()
  55. io = property(lambda s: s._io,
  56. # Historically we either hand-wrote all the delegation methods
  57. # to use self.io, or we simply used __getattr__ to look them up at
  58. # runtime. This meant people could change the io attribute on the fly
  59. # and it would mostly work (subprocess.py used to do that). We don't recommend
  60. # that, but we still support it.
  61. lambda s, nv: setattr(s, '_io', nv) or s._do_delegate_methods())
  62. def _do_delegate_methods(self):
  63. for meth_name in self._delegate_methods:
  64. meth = getattr(self._io, meth_name, None)
  65. implemented_by_class = hasattr(type(self), meth_name)
  66. if meth and not implemented_by_class:
  67. setattr(self, meth_name, self._wrap_method(meth))
  68. elif hasattr(self, meth_name) and not implemented_by_class:
  69. delattr(self, meth_name)
  70. def _wrap_method(self, method):
  71. """
  72. Wrap a method we're copying into our dictionary from the underlying
  73. io object to do something special or different, if necessary.
  74. """
  75. return method
  76. def translate_newlines(self, mode, *text_args, **text_kwargs):
  77. wrapper = TextIOWrapper(self._io, *text_args, **text_kwargs)
  78. if mode:
  79. wrapper.mode = mode
  80. self.io = wrapper
  81. self._translate = True
  82. @property
  83. def closed(self):
  84. """True if the file is closed"""
  85. return self._io is None
  86. def close(self):
  87. if self._io is None:
  88. return
  89. io = self._io
  90. self._io = None
  91. self._do_close(io, self._close)
  92. def _do_close(self, fobj, closefd):
  93. raise NotImplementedError()
  94. def __getattr__(self, name):
  95. if self._io is None:
  96. raise FileObjectClosed()
  97. return getattr(self._io, name)
  98. def __repr__(self):
  99. return '<%s _fobj=%r%s>' % (self.__class__.__name__, self.io, self._extra_repr())
  100. def _extra_repr(self):
  101. return ''