/pypy/module/cpyext/pyfile.py

https://bitbucket.org/pypy/pypy/ · Python · 145 lines · 90 code · 12 blank · 43 comment · 21 complexity · d58e72d453771093f3d847d179043ecd MD5 · raw file

  1. from rpython.rtyper.lltypesystem import rffi, lltype
  2. from rpython.rlib.rfile import c_setvbuf, _IONBF
  3. from pypy.module.cpyext.api import (
  4. cpython_api, CANNOT_FAIL, CONST_STRING, FILEP, build_type_checkers, c_fdopen)
  5. from pypy.module.cpyext.pyobject import PyObject
  6. from pypy.module.cpyext.object import Py_PRINT_RAW
  7. from pypy.interpreter.error import (OperationError, oefmt,
  8. exception_from_saved_errno)
  9. from pypy.module._file.interp_file import W_File
  10. PyFile_Check, PyFile_CheckExact = build_type_checkers("File", W_File)
  11. @cpython_api([PyObject, rffi.INT_real], PyObject)
  12. def PyFile_GetLine(space, w_obj, n):
  13. """
  14. Equivalent to p.readline([n]), this function reads one line from the
  15. object p. p may be a file object or any object with a readline()
  16. method. If n is 0, exactly one line is read, regardless of the length of
  17. the line. If n is greater than 0, no more than n bytes will be read
  18. from the file; a partial line can be returned. In both cases, an empty string
  19. is returned if the end of the file is reached immediately. If n is less than
  20. 0, however, one line is read regardless of length, but EOFError is
  21. raised if the end of the file is reached immediately."""
  22. try:
  23. w_readline = space.getattr(w_obj, space.wrap('readline'))
  24. except OperationError:
  25. raise oefmt(space.w_TypeError,
  26. "argument must be a file, or have a readline() method.")
  27. n = rffi.cast(lltype.Signed, n)
  28. if space.is_true(space.gt(space.wrap(n), space.wrap(0))):
  29. return space.call_function(w_readline, space.wrap(n))
  30. elif space.is_true(space.lt(space.wrap(n), space.wrap(0))):
  31. return space.call_function(w_readline)
  32. else:
  33. # XXX Raise EOFError as specified
  34. return space.call_function(w_readline)
  35. @cpython_api([CONST_STRING, CONST_STRING], PyObject)
  36. def PyFile_FromString(space, filename, mode):
  37. """
  38. On success, return a new file object that is opened on the file given by
  39. filename, with a file mode given by mode, where mode has the same
  40. semantics as the standard C routine fopen(). On failure, return NULL."""
  41. w_filename = space.newbytes(rffi.charp2str(filename))
  42. w_mode = space.wrap(rffi.charp2str(mode))
  43. return space.call_method(space.builtin, 'file', w_filename, w_mode)
  44. @cpython_api([PyObject], FILEP, error=lltype.nullptr(FILEP.TO))
  45. def PyFile_AsFile(space, w_p):
  46. """Return the file object associated with p as a FILE*.
  47. If the caller will ever use the returned FILE* object while
  48. the GIL is released it must also call the PyFile_IncUseCount() and
  49. PyFile_DecUseCount() functions as appropriate."""
  50. if not PyFile_Check(space, w_p):
  51. raise oefmt(space.w_IOError, 'first argument must be an open file')
  52. assert isinstance(w_p, W_File)
  53. w_p.stream.flush_buffers()
  54. try:
  55. fd = space.int_w(space.call_method(w_p, 'fileno'))
  56. mode = w_p.mode
  57. except OperationError as e:
  58. raise oefmt(space.w_IOError, 'could not call fileno')
  59. if (fd < 0 or not mode or mode[0] not in ['r', 'w', 'a', 'U'] or
  60. ('U' in mode and ('w' in mode or 'a' in mode))):
  61. raise oefmt(space.w_IOError, 'invalid fileno or mode')
  62. ret = c_fdopen(fd, mode)
  63. if not ret:
  64. raise exception_from_saved_errno(space, space.w_IOError)
  65. # XXX fix this once use-file-star-for-file lands
  66. c_setvbuf(ret, lltype.nullptr(rffi.CCHARP.TO), _IONBF, 0)
  67. return ret
  68. @cpython_api([FILEP, CONST_STRING, CONST_STRING, rffi.VOIDP], PyObject)
  69. def PyFile_FromFile(space, fp, name, mode, close):
  70. """Create a new PyFileObject from the already-open standard C file
  71. pointer, fp. The function close will be called when the file should be
  72. closed. Return NULL on failure."""
  73. if close:
  74. raise oefmt(space.w_NotImplementedError,
  75. 'PyFromFile(..., close) with close function not implemented')
  76. w_ret = space.allocate_instance(W_File, space.gettypefor(W_File))
  77. w_ret.w_name = space.wrap(rffi.charp2str(name))
  78. w_ret.check_mode_ok(rffi.charp2str(mode))
  79. w_ret.fp = fp
  80. return w_ret
  81. @cpython_api([PyObject, rffi.INT_real], lltype.Void)
  82. def PyFile_SetBufSize(space, w_file, n):
  83. """Available on systems with setvbuf() only. This should only be called
  84. immediately after file object creation."""
  85. raise NotImplementedError
  86. @cpython_api([CONST_STRING, PyObject], rffi.INT_real, error=-1)
  87. def PyFile_WriteString(space, s, w_p):
  88. """Write string s to file object p. Return 0 on success or -1 on
  89. failure; the appropriate exception will be set."""
  90. w_str = space.wrap(rffi.charp2str(s))
  91. space.call_method(w_p, "write", w_str)
  92. return 0
  93. @cpython_api([PyObject, PyObject, rffi.INT_real], rffi.INT_real, error=-1)
  94. def PyFile_WriteObject(space, w_obj, w_p, flags):
  95. """
  96. Write object obj to file object p. The only supported flag for flags is
  97. Py_PRINT_RAW; if given, the str() of the object is written
  98. instead of the repr(). Return 0 on success or -1 on failure; the
  99. appropriate exception will be set."""
  100. if rffi.cast(lltype.Signed, flags) & Py_PRINT_RAW:
  101. w_str = space.str(w_obj)
  102. else:
  103. w_str = space.repr(w_obj)
  104. space.call_method(w_p, "write", w_str)
  105. return 0
  106. @cpython_api([PyObject], PyObject)
  107. def PyFile_Name(space, w_p):
  108. """Return the name of the file specified by p as a string object."""
  109. w_name = space.getattr(w_p, space.wrap("name"))
  110. return w_name # borrowed ref, should be a W_StringObject from the file
  111. @cpython_api([PyObject, rffi.INT_real], rffi.INT_real, error=CANNOT_FAIL)
  112. def PyFile_SoftSpace(space, w_p, newflag):
  113. """
  114. This function exists for internal use by the interpreter. Set the
  115. softspace attribute of p to newflag and return the previous value.
  116. p does not have to be a file object for this function to work
  117. properly; any object is supported (thought its only interesting if
  118. the softspace attribute can be set). This function clears any
  119. errors, and will return 0 as the previous value if the attribute
  120. either does not exist or if there were errors in retrieving it.
  121. There is no way to detect errors from this function, but doing so
  122. should not be needed."""
  123. try:
  124. if rffi.cast(lltype.Signed, newflag):
  125. w_newflag = space.w_True
  126. else:
  127. w_newflag = space.w_False
  128. oldflag = space.int_w(space.getattr(w_p, space.wrap("softspace")))
  129. space.setattr(w_p, space.wrap("softspace"), w_newflag)
  130. return oldflag
  131. except OperationError as e:
  132. return 0