PageRenderTime 55ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/pypy/module/_io/interp_bufferedio.py

https://bitbucket.org/dac_io/pypy
Python | 987 lines | 900 code | 65 blank | 22 comment | 57 complexity | e193bfc364bcf2a98a15638636fc384c MD5 | raw file
  1. from __future__ import with_statement
  2. from pypy.interpreter.typedef import (
  3. TypeDef, GetSetProperty, generic_new_descr, interp_attrproperty_w)
  4. from pypy.interpreter.gateway import interp2app, unwrap_spec
  5. from pypy.interpreter.error import OperationError, operationerrfmt
  6. from pypy.interpreter.buffer import RWBuffer
  7. from pypy.rlib.rstring import StringBuilder
  8. from pypy.rlib.rarithmetic import r_longlong, intmask
  9. from pypy.tool.sourcetools import func_renamer
  10. from pypy.module._io.interp_iobase import (
  11. W_IOBase, DEFAULT_BUFFER_SIZE, convert_size,
  12. check_readable_w, check_writable_w, check_seekable_w)
  13. from pypy.module._io.interp_io import W_BlockingIOError
  14. from pypy.module.thread import ll_thread
  15. import errno
  16. STATE_ZERO, STATE_OK, STATE_DETACHED = range(3)
  17. def trap_eintr(space, error):
  18. # Return True if an EnvironmentError with errno == EINTR is set
  19. if not error.match(space, space.w_EnvironmentError):
  20. return False
  21. try:
  22. w_value = error.get_w_value(space)
  23. w_errno = space.getattr(w_value, space.wrap("errno"))
  24. return space.is_true(
  25. space.eq(w_errno, space.wrap(errno.EINTR)))
  26. except OperationError:
  27. return False
  28. class TryLock(object):
  29. "A Lock that raises RuntimeError when acquired twice by the same thread"
  30. def __init__(self, space):
  31. ## XXX cannot free a Lock?
  32. ## if self.lock:
  33. ## self.lock.free()
  34. self.lock = space.allocate_lock()
  35. self.owner = 0
  36. self.operr = OperationError(space.w_RuntimeError,
  37. space.wrap("reentrant call"))
  38. def __enter__(self):
  39. if not self.lock.acquire(False):
  40. if self.owner == ll_thread.get_ident():
  41. raise self.operr
  42. self.lock.acquire(True)
  43. self.owner = ll_thread.get_ident()
  44. def __exit__(self,*args):
  45. self.owner = 0
  46. self.lock.release()
  47. class BlockingIOError(Exception):
  48. pass
  49. class W_BufferedIOBase(W_IOBase):
  50. def _unsupportedoperation(self, space, message):
  51. w_exc = space.getattr(space.getbuiltinmodule('_io'),
  52. space.wrap('UnsupportedOperation'))
  53. raise OperationError(w_exc, space.wrap(message))
  54. def _check_init(self, space):
  55. raise NotImplementedError
  56. def _deprecated_max_buffer_size(self, space):
  57. space.warn("max_buffer_size is deprecated",
  58. space.w_DeprecationWarning)
  59. def read_w(self, space, w_size=None):
  60. self._unsupportedoperation(space, "read")
  61. def read1_w(self, space, w_size):
  62. self._unsupportedoperation(space, "read1")
  63. def write_w(self, space, w_data):
  64. self._unsupportedoperation(space, "write")
  65. def detach_w(self, space):
  66. self._unsupportedoperation(space, "detach")
  67. def readinto_w(self, space, w_buffer):
  68. rwbuffer = space.rwbuffer_w(w_buffer)
  69. length = rwbuffer.getlength()
  70. w_data = space.call_method(self, "read", space.wrap(length))
  71. if not space.isinstance_w(w_data, space.w_str):
  72. raise OperationError(space.w_TypeError, space.wrap(
  73. "read() should return bytes"))
  74. data = space.str_w(w_data)
  75. rwbuffer.setslice(0, data)
  76. return space.wrap(len(data))
  77. W_BufferedIOBase.typedef = TypeDef(
  78. '_io._BufferedIOBase', W_IOBase.typedef,
  79. __new__ = generic_new_descr(W_BufferedIOBase),
  80. read = interp2app(W_BufferedIOBase.read_w),
  81. read1 = interp2app(W_BufferedIOBase.read1_w),
  82. write = interp2app(W_BufferedIOBase.write_w),
  83. detach = interp2app(W_BufferedIOBase.detach_w),
  84. readinto = interp2app(W_BufferedIOBase.readinto_w),
  85. )
  86. class RawBuffer(RWBuffer):
  87. def __init__(self, buf, start, length):
  88. self.buf = buf
  89. self.start = start
  90. self.length = length
  91. def getlength(self):
  92. return self.length
  93. def setitem(self, index, char):
  94. self.buf[self.start + index] = char
  95. class BufferedMixin:
  96. _mixin_ = True
  97. def __init__(self, space):
  98. W_IOBase.__init__(self, space)
  99. self.state = STATE_ZERO
  100. self.buffer = None
  101. self.abs_pos = 0 # Absolute position inside the raw stream (-1 if
  102. # unknown).
  103. self.pos = 0 # Current logical position in the buffer
  104. self.raw_pos = 0 # Position of the raw stream in the buffer.
  105. self.read_end = -1 # Just after the last buffered byte in the buffer,
  106. # or -1 if the buffer isn't ready for reading
  107. self.write_pos = 0 # Just after the last byte actually written
  108. self.write_end = -1 # Just after the last byte waiting to be written,
  109. # or -1 if the buffer isn't ready for writing.
  110. self.lock = None
  111. self.readable = False
  112. self.writable = False
  113. def _reader_reset_buf(self):
  114. self.read_end = -1
  115. def _writer_reset_buf(self):
  116. self.write_pos = 0
  117. self.write_end = -1
  118. def _init(self, space):
  119. if self.buffer_size <= 0:
  120. raise OperationError(space.w_ValueError, space.wrap(
  121. "buffer size must be strictly positive"))
  122. self.buffer = ['\0'] * self.buffer_size
  123. self.lock = TryLock(space)
  124. try:
  125. self._raw_tell(space)
  126. except OperationError:
  127. pass
  128. def _check_init(self, space):
  129. if self.state == STATE_ZERO:
  130. raise OperationError(space.w_ValueError, space.wrap(
  131. "I/O operation on uninitialized object"))
  132. elif self.state == STATE_DETACHED:
  133. raise OperationError(space.w_ValueError, space.wrap(
  134. "raw stream has been detached"))
  135. def _check_closed(self, space, message=None):
  136. self._check_init(space)
  137. W_IOBase._check_closed(self, space, message)
  138. def _raw_tell(self, space):
  139. w_pos = space.call_method(self.w_raw, "tell")
  140. pos = space.r_longlong_w(w_pos)
  141. if pos < 0:
  142. raise OperationError(space.w_IOError, space.wrap(
  143. "raw stream returned invalid position"))
  144. self.abs_pos = pos
  145. return pos
  146. def closed_get_w(self, space):
  147. self._check_init(space)
  148. return space.getattr(self.w_raw, space.wrap("closed"))
  149. def name_get_w(self, space):
  150. return space.getattr(self.w_raw, space.wrap("name"))
  151. def mode_get_w(self, space):
  152. return space.getattr(self.w_raw, space.wrap("mode"))
  153. def readable_w(self, space):
  154. self._check_init(space)
  155. return space.call_method(self.w_raw, "readable")
  156. def writable_w(self, space):
  157. self._check_init(space)
  158. return space.call_method(self.w_raw, "writable")
  159. def seekable_w(self, space):
  160. self._check_init(space)
  161. return space.call_method(self.w_raw, "seekable")
  162. def isatty_w(self, space):
  163. return space.call_method(self.w_raw, "isatty")
  164. def repr_w(self, space):
  165. typename = space.type(self).getname(space)
  166. module = space.str_w(space.type(self).get_module())
  167. try:
  168. w_name = space.getattr(self, space.wrap("name"))
  169. except OperationError, e:
  170. if not e.match(space, space.w_AttributeError):
  171. raise
  172. return space.wrap("<%s.%s>" % (module, typename,))
  173. else:
  174. name_repr = space.str_w(space.repr(w_name))
  175. return space.wrap("<%s.%s name=%s>" % (module, typename, name_repr))
  176. # ______________________________________________
  177. def _readahead(self):
  178. if self.readable and self.read_end != -1:
  179. available = self.read_end - self.pos
  180. assert available >= 0
  181. return available
  182. return 0
  183. def _raw_offset(self):
  184. if self.raw_pos >= 0 and (
  185. (self.readable and self.read_end != -1) or
  186. (self.writable and self.write_end != -1)):
  187. return self.raw_pos - self.pos
  188. return 0
  189. def tell_w(self, space):
  190. self._check_init(space)
  191. pos = self._raw_tell(space) - self._raw_offset()
  192. return space.wrap(pos)
  193. @unwrap_spec(pos=r_longlong, whence=int)
  194. def seek_w(self, space, pos, whence=0):
  195. self._check_init(space)
  196. if whence not in (0, 1, 2):
  197. raise operationerrfmt(space.w_ValueError,
  198. "whence must be between 0 and 2, not %d", whence)
  199. self._check_closed(space, "seek of closed file")
  200. if whence != 2 and self.readable:
  201. # Check if seeking leaves us inside the current buffer, so as to
  202. # return quickly if possible. Also, we needn't take the lock in
  203. # this fast path.
  204. if self.abs_pos == -1:
  205. self._raw_tell(space)
  206. current = self.abs_pos
  207. available = self._readahead()
  208. if available > 0:
  209. if whence == 0:
  210. offset = pos - (current - self._raw_offset())
  211. else:
  212. offset = pos
  213. if -self.pos <= offset <= available:
  214. newpos = self.pos + offset
  215. assert newpos >= 0
  216. self.pos = newpos
  217. return space.wrap(current - available + offset)
  218. # Fallback: invoke raw seek() method and clear buffer
  219. with self.lock:
  220. if self.writable:
  221. self._writer_flush_unlocked(space)
  222. self._writer_reset_buf()
  223. if whence == 1:
  224. pos -= self._raw_offset()
  225. n = self._raw_seek(space, pos, whence)
  226. self.raw_pos = -1
  227. if self.readable:
  228. self._reader_reset_buf()
  229. return space.wrap(n)
  230. def _raw_seek(self, space, pos, whence):
  231. w_pos = space.call_method(self.w_raw, "seek",
  232. space.wrap(pos), space.wrap(whence))
  233. pos = space.r_longlong_w(w_pos)
  234. if pos < 0:
  235. raise OperationError(space.w_IOError, space.wrap(
  236. "Raw stream returned invalid position"))
  237. self.abs_pos = pos
  238. return pos
  239. def _closed(self, space):
  240. return space.is_true(space.getattr(self.w_raw, space.wrap("closed")))
  241. def close_w(self, space):
  242. self._check_init(space)
  243. with self.lock:
  244. if self._closed(space):
  245. return
  246. space.call_method(self, "flush")
  247. with self.lock:
  248. space.call_method(self.w_raw, "close")
  249. def simple_flush_w(self, space):
  250. self._check_init(space)
  251. return space.call_method(self.w_raw, "flush")
  252. def _writer_flush_unlocked(self, space, restore_pos=False):
  253. if self.write_end == -1 or self.write_pos == self.write_end:
  254. return
  255. # First, rewind
  256. rewind = self._raw_offset() + (self.pos - self.write_pos)
  257. if rewind != 0:
  258. self._raw_seek(space, -rewind, 1)
  259. self.raw_pos -= rewind
  260. written = 0
  261. while self.write_pos < self.write_end:
  262. try:
  263. n = self._raw_write(space, self.write_pos, self.write_end)
  264. except OperationError, e:
  265. if not e.match(space, space.gettypeobject(
  266. W_BlockingIOError.typedef)):
  267. raise
  268. w_exc = e.get_w_value(space)
  269. assert isinstance(w_exc, W_BlockingIOError)
  270. self.write_pos += w_exc.written
  271. self.raw_pos = self.write_pos
  272. written += w_exc.written
  273. # re-raise the error
  274. w_exc.written = written
  275. raise
  276. self.write_pos += n
  277. self.raw_pos = self.write_pos
  278. written += n
  279. # Partial writes can return successfully when interrupted by a
  280. # signal (see write(2)). We must run signal handlers before
  281. # blocking another time, possibly indefinitely.
  282. space.getexecutioncontext().checksignals()
  283. if restore_pos:
  284. forward = rewind - written
  285. if forward:
  286. self._raw_seek(space, forward, 1)
  287. self.raw_pos += forward
  288. self._writer_reset_buf()
  289. def _write(self, space, data):
  290. w_data = space.wrap(data)
  291. while True:
  292. try:
  293. w_written = space.call_method(self.w_raw, "write", w_data)
  294. except OperationError, e:
  295. if trap_eintr(space, e):
  296. continue # try again
  297. raise
  298. else:
  299. break
  300. written = space.getindex_w(w_written, space.w_IOError)
  301. if not 0 <= written <= len(data):
  302. raise OperationError(space.w_IOError, space.wrap(
  303. "raw write() returned invalid length"))
  304. if self.abs_pos != -1:
  305. self.abs_pos += written
  306. return written
  307. def _raw_write(self, space, start, end):
  308. # XXX inefficient
  309. l = []
  310. for i in range(start, end):
  311. l.append(self.buffer[i])
  312. return self._write(space, ''.join(l))
  313. def detach_w(self, space):
  314. self._check_init(space)
  315. space.call_method(self, "flush")
  316. w_raw = self.w_raw
  317. self.w_raw = None
  318. self.state = STATE_DETACHED
  319. return w_raw
  320. def fileno_w(self, space):
  321. self._check_init(space)
  322. return space.call_method(self.w_raw, "fileno")
  323. def truncate_w(self, space, w_size=None):
  324. self._check_init(space)
  325. with self.lock:
  326. if self.writable:
  327. self._writer_flush_unlocked(space)
  328. if self.readable:
  329. if space.is_w(w_size, space.w_None):
  330. # Rewind the raw stream so that its position corresponds
  331. # to the current logical position
  332. self._raw_seek(space, -self._raw_offset(), 1)
  333. self._reader_reset_buf()
  334. # invalidate cached position
  335. self.abs_pos = -1
  336. return space.call_method(self.w_raw, "truncate", w_size)
  337. # ________________________________________________________________
  338. # Read methods
  339. def read_w(self, space, w_size=None):
  340. self._check_init(space)
  341. self._check_closed(space, "read of closed file")
  342. size = convert_size(space, w_size)
  343. if size == -1:
  344. # read until the end of stream
  345. with self.lock:
  346. return self._read_all(space)
  347. elif size >= 0:
  348. res = self._read_fast(size)
  349. if res is None:
  350. with self.lock:
  351. res = self._read_generic(space, size)
  352. else:
  353. raise OperationError(space.w_ValueError, space.wrap(
  354. "read length must be positive or -1"))
  355. return space.wrap(res)
  356. @unwrap_spec(size=int)
  357. def peek_w(self, space, size=0):
  358. self._check_init(space)
  359. with self.lock:
  360. if self.writable:
  361. self._writer_flush_unlocked(space, restore_pos=True)
  362. # Constraints:
  363. # 1. we don't want to advance the file position.
  364. # 2. we don't want to lose block alignment, so we can't shift the
  365. # buffer to make some place.
  366. # Therefore, we either return `have` bytes (if > 0), or a full
  367. # buffer.
  368. have = self._readahead()
  369. if have > 0:
  370. data = ''.join(self.buffer[self.pos:self.pos+have])
  371. return space.wrap(data)
  372. # Fill the buffer from the raw stream, and copy it to the result
  373. self._reader_reset_buf()
  374. try:
  375. size = self._fill_buffer(space)
  376. except BlockingIOError:
  377. size = 0
  378. self.pos = 0
  379. data = ''.join(self.buffer[:size])
  380. return space.wrap(data)
  381. @unwrap_spec(size=int)
  382. def read1_w(self, space, size):
  383. self._check_init(space)
  384. self._check_closed(space, "read of closed file")
  385. if size < 0:
  386. raise OperationError(space.w_ValueError, space.wrap(
  387. "read length must be positive"))
  388. if size == 0:
  389. return space.wrap("")
  390. with self.lock:
  391. if self.writable:
  392. self._writer_flush_unlocked(space, restore_pos=True)
  393. # Return up to n bytes. If at least one byte is buffered, we only
  394. # return buffered bytes. Otherwise, we do one raw read.
  395. # XXX: this mimicks the io.py implementation but is probably
  396. # wrong. If we need to read from the raw stream, then we could
  397. # actually read all `n` bytes asked by the caller (and possibly
  398. # more, so as to fill our buffer for the next reads).
  399. have = self._readahead()
  400. if have == 0:
  401. # Fill the buffer from the raw stream
  402. self._reader_reset_buf()
  403. self.pos = 0
  404. try:
  405. have = self._fill_buffer(space)
  406. except BlockingIOError:
  407. have = 0
  408. if size > have:
  409. size = have
  410. endpos = self.pos + size
  411. data = ''.join(self.buffer[self.pos:endpos])
  412. self.pos = endpos
  413. return space.wrap(data)
  414. def _read_all(self, space):
  415. "Read all the file, don't update the cache"
  416. builder = StringBuilder()
  417. # First copy what we have in the current buffer
  418. current_size = self._readahead()
  419. data = None
  420. if current_size:
  421. data = ''.join(self.buffer[self.pos:self.pos + current_size])
  422. builder.append(data)
  423. self._reader_reset_buf()
  424. # We're going past the buffer's bounds, flush it
  425. if self.writable:
  426. self._writer_flush_unlocked(space, restore_pos=True)
  427. while True:
  428. # Read until EOF or until read() would block
  429. w_data = space.call_method(self.w_raw, "read")
  430. if space.is_w(w_data, space.w_None):
  431. if current_size == 0:
  432. return w_data
  433. break
  434. data = space.str_w(w_data)
  435. size = len(data)
  436. if size == 0:
  437. break
  438. builder.append(data)
  439. current_size += size
  440. if self.abs_pos != -1:
  441. self.abs_pos += size
  442. return space.wrap(builder.build())
  443. def _raw_read(self, space, buffer, start, length):
  444. length = intmask(length)
  445. w_buf = space.wrap(RawBuffer(buffer, start, length))
  446. while True:
  447. try:
  448. w_size = space.call_method(self.w_raw, "readinto", w_buf)
  449. except OperationError, e:
  450. if trap_eintr(space, e):
  451. continue # try again
  452. raise
  453. else:
  454. break
  455. if space.is_w(w_size, space.w_None):
  456. raise BlockingIOError()
  457. size = space.int_w(w_size)
  458. if size < 0 or size > length:
  459. raise OperationError(space.w_IOError, space.wrap(
  460. "raw readinto() returned invalid length %d "
  461. "(should have been between 0 and %d)" % (size, length)))
  462. if self.abs_pos != -1:
  463. self.abs_pos += size
  464. return size
  465. def _fill_buffer(self, space):
  466. start = self.read_end
  467. if start == -1:
  468. start = 0
  469. length = self.buffer_size - start
  470. size = self._raw_read(space, self.buffer, start, length)
  471. if size > 0:
  472. self.read_end = self.raw_pos = start + size
  473. return size
  474. def _read_generic(self, space, n):
  475. """Generic read function: read from the stream until enough bytes are
  476. read, or until an EOF occurs or until read() would block."""
  477. current_size = self._readahead()
  478. if n <= current_size:
  479. return self._read_fast(n)
  480. result_buffer = ['\0'] * n
  481. remaining = n
  482. written = 0
  483. data = None
  484. if current_size:
  485. for i in range(current_size):
  486. result_buffer[written + i] = self.buffer[self.pos + i]
  487. remaining -= current_size
  488. written += current_size
  489. self._reader_reset_buf()
  490. # XXX potential bug in CPython? The following is not enabled.
  491. # We're going past the buffer's bounds, flush it
  492. ## if self.writable:
  493. ## self._writer_flush_unlocked(space, restore_pos=True)
  494. # Read whole blocks, and don't buffer them
  495. while remaining > 0:
  496. r = self.buffer_size * (remaining // self.buffer_size)
  497. if r == 0:
  498. break
  499. try:
  500. size = self._raw_read(space, result_buffer, written, r)
  501. except BlockingIOError:
  502. if written == 0:
  503. return None
  504. size = 0
  505. if size == 0:
  506. return ''.join(result_buffer[:written])
  507. remaining -= size
  508. written += size
  509. self.pos = 0
  510. self.raw_pos = 0
  511. self.read_end = 0
  512. while remaining > 0 and self.read_end < self.buffer_size:
  513. try:
  514. size = self._fill_buffer(space)
  515. except BlockingIOError:
  516. # EOF or read() would block
  517. if written == 0:
  518. return None
  519. size = 0
  520. if size == 0:
  521. break
  522. if remaining > 0:
  523. if size > remaining:
  524. size = remaining
  525. for i in range(size):
  526. result_buffer[written + i] = self.buffer[self.pos + i]
  527. self.pos += size
  528. written += size
  529. remaining -= size
  530. return ''.join(result_buffer[:written])
  531. def _read_fast(self, n):
  532. """Read n bytes from the buffer if it can, otherwise return None.
  533. This function is simple enough that it can run unlocked."""
  534. current_size = self._readahead()
  535. if n <= current_size:
  536. endpos = self.pos + n
  537. res = ''.join(self.buffer[self.pos:endpos])
  538. self.pos = endpos
  539. return res
  540. return None
  541. # ____________________________________________________
  542. # Write methods
  543. def _adjust_position(self, new_pos):
  544. assert new_pos >= 0
  545. self.pos = new_pos
  546. if self.readable and self.read_end != -1 and self.read_end < new_pos:
  547. self.read_end = self.pos
  548. def write_w(self, space, w_data):
  549. self._check_init(space)
  550. self._check_closed(space, "write to closed file")
  551. data = space.bufferstr_w(w_data)
  552. size = len(data)
  553. with self.lock:
  554. if (not (self.readable and self.read_end != -1) and
  555. not (self.writable and self.write_end != -1)):
  556. self.pos = 0
  557. self.raw_pos = 0
  558. available = self.buffer_size - self.pos
  559. # Fast path: the data to write can be fully buffered
  560. if size <= available:
  561. for i in range(size):
  562. self.buffer[self.pos + i] = data[i]
  563. if self.write_end == -1 or self.write_pos > self.pos:
  564. self.write_pos = self.pos
  565. self._adjust_position(self.pos + size)
  566. if self.pos > self.write_end:
  567. self.write_end = self.pos
  568. return space.wrap(size)
  569. # First write the current buffer
  570. try:
  571. self._writer_flush_unlocked(space)
  572. except OperationError, e:
  573. if not e.match(space, space.gettypeobject(
  574. W_BlockingIOError.typedef)):
  575. raise
  576. w_exc = e.get_w_value(space)
  577. assert isinstance(w_exc, W_BlockingIOError)
  578. if self.readable:
  579. self._reader_reset_buf()
  580. # Make some place by shifting the buffer
  581. for i in range(self.write_pos, self.write_end):
  582. self.buffer[i - self.write_pos] = self.buffer[i]
  583. self.write_end -= self.write_pos
  584. self.raw_pos -= self.write_pos
  585. newpos = self.pos - self.write_pos
  586. assert newpos >= 0
  587. self.pos = newpos
  588. self.write_pos = 0
  589. available = self.buffer_size - self.write_end
  590. if size <= available:
  591. # Everything can be buffered
  592. for i in range(size):
  593. self.buffer[self.write_end + i] = data[i]
  594. self.write_end += size
  595. return space.wrap(size)
  596. # Buffer as much as possible
  597. for i in range(available):
  598. self.buffer[self.write_end + i] = data[i]
  599. self.write_end += available
  600. # Raise previous exception
  601. w_exc.written = available
  602. raise
  603. # Adjust the raw stream position if it is away from the logical
  604. # stream position. This happens if the read buffer has been filled
  605. # but not modified (and therefore _bufferedwriter_flush_unlocked()
  606. # didn't rewind the raw stream by itself).
  607. offset = self._raw_offset()
  608. if offset:
  609. self._raw_seek(space, -offset, 1)
  610. self.raw_pos -= offset
  611. # Then write buf itself. At this point the buffer has been emptied
  612. remaining = size
  613. written = 0
  614. while remaining > self.buffer_size:
  615. try:
  616. n = self._write(space, data[written:])
  617. except OperationError, e:
  618. if not e.match(space, space.gettypeobject(
  619. W_BlockingIOError.typedef)):
  620. raise
  621. w_exc = e.get_w_value(space)
  622. assert isinstance(w_exc, W_BlockingIOError)
  623. written += w_exc.written
  624. remaining -= w_exc.written
  625. if remaining > self.buffer_size:
  626. # Can't buffer everything, still buffer as much as
  627. # possible
  628. for i in range(self.buffer_size):
  629. self.buffer[i] = data[written + i]
  630. self.raw_pos = 0
  631. self._adjust_position(self.buffer_size)
  632. self.write_end = self.buffer_size
  633. w_exc.written = written + self.buffer_size
  634. raise
  635. break
  636. written += n
  637. remaining -= n
  638. # Partial writes can return successfully when interrupted by a
  639. # signal (see write(2)). We must run signal handlers before
  640. # blocking another time, possibly indefinitely.
  641. space.getexecutioncontext().checksignals()
  642. if self.readable:
  643. self._reader_reset_buf()
  644. if remaining > 0:
  645. for i in range(remaining):
  646. self.buffer[i] = data[written + i]
  647. written += remaining
  648. self.write_pos = 0
  649. self.write_end = remaining
  650. self._adjust_position(remaining)
  651. self.raw_pos = 0
  652. return space.wrap(written)
  653. def flush_w(self, space):
  654. self._check_init(space)
  655. self._check_closed(space, "flush of closed file")
  656. with self.lock:
  657. self._writer_flush_unlocked(space)
  658. if self.readable:
  659. # Rewind the raw stream so that its position corresponds to
  660. # the current logical position.
  661. self._raw_seek(space, -self._raw_offset(), 1)
  662. self._reader_reset_buf()
  663. class W_BufferedReader(BufferedMixin, W_BufferedIOBase):
  664. @unwrap_spec(buffer_size=int)
  665. def descr_init(self, space, w_raw, buffer_size=DEFAULT_BUFFER_SIZE):
  666. self.state = STATE_ZERO
  667. check_readable_w(space, w_raw)
  668. self.w_raw = w_raw
  669. self.buffer_size = buffer_size
  670. self.readable = True
  671. self._init(space)
  672. self._reader_reset_buf()
  673. self.state = STATE_OK
  674. W_BufferedReader.typedef = TypeDef(
  675. 'BufferedReader', W_BufferedIOBase.typedef,
  676. __new__ = generic_new_descr(W_BufferedReader),
  677. __init__ = interp2app(W_BufferedReader.descr_init),
  678. __module__ = "_io",
  679. read = interp2app(W_BufferedReader.read_w),
  680. peek = interp2app(W_BufferedReader.peek_w),
  681. read1 = interp2app(W_BufferedReader.read1_w),
  682. raw = interp_attrproperty_w("w_raw", cls=W_BufferedReader),
  683. # from the mixin class
  684. __repr__ = interp2app(W_BufferedReader.repr_w),
  685. readable = interp2app(W_BufferedReader.readable_w),
  686. writable = interp2app(W_BufferedReader.writable_w),
  687. seekable = interp2app(W_BufferedReader.seekable_w),
  688. seek = interp2app(W_BufferedReader.seek_w),
  689. tell = interp2app(W_BufferedReader.tell_w),
  690. close = interp2app(W_BufferedReader.close_w),
  691. flush = interp2app(W_BufferedReader.simple_flush_w), # Not flush_w!
  692. detach = interp2app(W_BufferedReader.detach_w),
  693. truncate = interp2app(W_BufferedReader.truncate_w),
  694. fileno = interp2app(W_BufferedReader.fileno_w),
  695. isatty = interp2app(W_BufferedReader.isatty_w),
  696. closed = GetSetProperty(W_BufferedReader.closed_get_w),
  697. name = GetSetProperty(W_BufferedReader.name_get_w),
  698. mode = GetSetProperty(W_BufferedReader.mode_get_w),
  699. )
  700. class W_BufferedWriter(BufferedMixin, W_BufferedIOBase):
  701. @unwrap_spec(buffer_size=int, max_buffer_size=int)
  702. def descr_init(self, space, w_raw, buffer_size=DEFAULT_BUFFER_SIZE,
  703. max_buffer_size=-234):
  704. if max_buffer_size != -234:
  705. self._deprecated_max_buffer_size(space)
  706. self.state = STATE_ZERO
  707. check_writable_w(space, w_raw)
  708. self.w_raw = w_raw
  709. self.buffer_size = buffer_size
  710. self.writable = True
  711. self._init(space)
  712. self._writer_reset_buf()
  713. self.state = STATE_OK
  714. W_BufferedWriter.typedef = TypeDef(
  715. 'BufferedWriter', W_BufferedIOBase.typedef,
  716. __new__ = generic_new_descr(W_BufferedWriter),
  717. __init__ = interp2app(W_BufferedWriter.descr_init),
  718. __module__ = "_io",
  719. write = interp2app(W_BufferedWriter.write_w),
  720. flush = interp2app(W_BufferedWriter.flush_w),
  721. raw = interp_attrproperty_w("w_raw", cls=W_BufferedWriter),
  722. # from the mixin class
  723. __repr__ = interp2app(W_BufferedWriter.repr_w),
  724. readable = interp2app(W_BufferedWriter.readable_w),
  725. writable = interp2app(W_BufferedWriter.writable_w),
  726. seekable = interp2app(W_BufferedWriter.seekable_w),
  727. seek = interp2app(W_BufferedWriter.seek_w),
  728. tell = interp2app(W_BufferedWriter.tell_w),
  729. close = interp2app(W_BufferedWriter.close_w),
  730. fileno = interp2app(W_BufferedWriter.fileno_w),
  731. isatty = interp2app(W_BufferedWriter.isatty_w),
  732. detach = interp2app(W_BufferedWriter.detach_w),
  733. truncate = interp2app(W_BufferedWriter.truncate_w),
  734. closed = GetSetProperty(W_BufferedWriter.closed_get_w),
  735. name = GetSetProperty(W_BufferedWriter.name_get_w),
  736. mode = GetSetProperty(W_BufferedWriter.mode_get_w),
  737. )
  738. def _forward_call(space, w_obj, method, __args__):
  739. w_meth = self.getattr(w_obj, self.wrap(method))
  740. return self.call_args(w_meth, __args__)
  741. def make_forwarding_method(method, writer=False, reader=False):
  742. @func_renamer(method + '_w')
  743. def method_w(self, space, __args__):
  744. if writer:
  745. w_meth = space.getattr(self.w_writer, space.wrap(method))
  746. w_result = space.call_args(w_meth, __args__)
  747. if reader:
  748. w_meth = space.getattr(self.w_reader, space.wrap(method))
  749. w_result = space.call_args(w_meth, __args__)
  750. return w_result
  751. return method_w
  752. class W_BufferedRWPair(W_BufferedIOBase):
  753. w_reader = None
  754. w_writer = None
  755. @unwrap_spec(buffer_size=int, max_buffer_size=int)
  756. def descr_init(self, space, w_reader, w_writer,
  757. buffer_size=DEFAULT_BUFFER_SIZE, max_buffer_size=-234):
  758. if max_buffer_size != -234:
  759. self._deprecated_max_buffer_size(space)
  760. try:
  761. self.w_reader = W_BufferedReader(space)
  762. self.w_reader.descr_init(space, w_reader, buffer_size)
  763. self.w_writer = W_BufferedWriter(space)
  764. self.w_writer.descr_init(space, w_writer, buffer_size)
  765. except Exception:
  766. self.w_reader = None
  767. self.w_writer = None
  768. raise
  769. def __del__(self):
  770. self.clear_all_weakrefs()
  771. # Don't call the base __del__: do not close the files!
  772. # forward to reader
  773. for method in ['read', 'peek', 'read1', 'readinto', 'readable']:
  774. locals()[method + '_w'] = make_forwarding_method(
  775. method, reader=True)
  776. # forward to writer
  777. for method in ['write', 'flush', 'writable']:
  778. locals()[method + '_w'] = make_forwarding_method(
  779. method, writer=True)
  780. # forward to both
  781. for method in ['close']:
  782. locals()[method + '_w'] = make_forwarding_method(
  783. method, writer=True, reader=True)
  784. def isatty_w(self, space):
  785. if space.is_true(space.call_method(self.w_writer, "isatty")):
  786. return space.w_True
  787. return space.call_method(self.w_reader, "isatty")
  788. def closed_get_w(self, space):
  789. return space.getattr(self.w_writer, space.wrap("closed"))
  790. methods = dict((method, interp2app(getattr(W_BufferedRWPair, method + '_w')))
  791. for method in ['read', 'peek', 'read1', 'readinto', 'readable',
  792. 'write', 'flush', 'writable',
  793. 'close',
  794. 'isatty'])
  795. W_BufferedRWPair.typedef = TypeDef(
  796. '_io.BufferedRWPair', W_BufferedIOBase.typedef,
  797. __new__ = generic_new_descr(W_BufferedRWPair),
  798. __init__ = interp2app(W_BufferedRWPair.descr_init),
  799. closed = GetSetProperty(W_BufferedRWPair.closed_get_w),
  800. **methods
  801. )
  802. class W_BufferedRandom(BufferedMixin, W_BufferedIOBase):
  803. @unwrap_spec(buffer_size=int, max_buffer_size=int)
  804. def descr_init(self, space, w_raw, buffer_size=DEFAULT_BUFFER_SIZE,
  805. max_buffer_size = -234):
  806. if max_buffer_size != -234:
  807. self._deprecated_max_buffer_size(space)
  808. self.state = STATE_ZERO
  809. check_readable_w(space, w_raw)
  810. check_writable_w(space, w_raw)
  811. check_seekable_w(space, w_raw)
  812. self.w_raw = w_raw
  813. self.buffer_size = buffer_size
  814. self.readable = self.writable = True
  815. self._init(space)
  816. self._reader_reset_buf()
  817. self._writer_reset_buf()
  818. self.pos = 0
  819. self.state = STATE_OK
  820. W_BufferedRandom.typedef = TypeDef(
  821. 'BufferedRandom', W_BufferedIOBase.typedef,
  822. __new__ = generic_new_descr(W_BufferedRandom),
  823. __init__ = interp2app(W_BufferedRandom.descr_init),
  824. __module__ = "_io",
  825. read = interp2app(W_BufferedRandom.read_w),
  826. peek = interp2app(W_BufferedRandom.peek_w),
  827. read1 = interp2app(W_BufferedRandom.read1_w),
  828. write = interp2app(W_BufferedRandom.write_w),
  829. flush = interp2app(W_BufferedRandom.flush_w),
  830. raw = interp_attrproperty_w("w_raw", cls=W_BufferedRandom),
  831. # from the mixin class
  832. __repr__ = interp2app(W_BufferedRandom.repr_w),
  833. readable = interp2app(W_BufferedRandom.readable_w),
  834. writable = interp2app(W_BufferedRandom.writable_w),
  835. seekable = interp2app(W_BufferedRandom.seekable_w),
  836. seek = interp2app(W_BufferedRandom.seek_w),
  837. tell = interp2app(W_BufferedRandom.tell_w),
  838. close = interp2app(W_BufferedRandom.close_w),
  839. detach = interp2app(W_BufferedRandom.detach_w),
  840. truncate = interp2app(W_BufferedRandom.truncate_w),
  841. fileno = interp2app(W_BufferedRandom.fileno_w),
  842. isatty = interp2app(W_BufferedRandom.isatty_w),
  843. closed = GetSetProperty(W_BufferedRandom.closed_get_w),
  844. name = GetSetProperty(W_BufferedRandom.name_get_w),
  845. mode = GetSetProperty(W_BufferedRandom.mode_get_w),
  846. )