Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions Lib/test/test_capi/test_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import unittest
import io
import os
Comment thread
sobolevn marked this conversation as resolved.
Outdated

from test.support import import_helper, os_helper

# Skip this test if the _testcapi module isn't available.
_testcapi = import_helper.import_module('_testcapi')

NULL = None


class TestPyFileCAPI(unittest.TestCase):
def tearDown(self):
try:
os.unlink(os_helper.TESTFN)
except FileNotFoundError:
pass
Comment thread
sobolevn marked this conversation as resolved.
Outdated

def test_file_from_fd(self):
# PyFile_FromFd()
with open(os_helper.TESTFN, "w") as f:
# raise ValueError(*file_mode, 0, "utf-8", "strict", "\n", 0,)
file_obj = _testcapi.file_from_fd(
f.fileno(), os_helper.TESTFN, "w",
1, "utf-8", "strict", "\n", 0,
)
Comment thread
sobolevn marked this conversation as resolved.
Outdated

# We don't apply heavy testing here, because inside it directly calls
Comment thread
sobolevn marked this conversation as resolved.
Outdated
# `_io.open` which is fully tested in `test_io`.
self.assertIsInstance(file_obj, io.TextIOWrapper)

def test_file_get_line(self):
# PyFile_GetLine
get_line = _testcapi.file_get_line

# Create file with unicode content:
first_line = "text with юникод 统一码"
with open(os_helper.TESTFN, "w") as f:
Comment thread
sobolevn marked this conversation as resolved.
Outdated
f.writelines([first_line])
Comment thread
sobolevn marked this conversation as resolved.

with open(os_helper.TESTFN) as f:
Comment thread
sobolevn marked this conversation as resolved.
Outdated
self.assertEqual(get_line(f, 0), first_line)
with open(os_helper.TESTFN) as f:
self.assertEqual(get_line(f, 4), 'text')
Comment thread
sobolevn marked this conversation as resolved.
Outdated
with open(os_helper.TESTFN) as f:
self.assertEqual(get_line(f, -1), first_line)

# Create file with bytes content:
first_line = "text with юникод 统一码".encode("utf8")
with open(os_helper.TESTFN, mode="wb") as f:
f.writelines([first_line])
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has the same content.


with open(os_helper.TESTFN, 'rb') as f:
self.assertEqual(get_line(f, 0), first_line)
with open(os_helper.TESTFN, 'rb') as f:
self.assertEqual(get_line(f, 4), b'text')
with open(os_helper.TESTFN, 'rb') as f:
self.assertEqual(get_line(f, -1), first_line)

# Create empty file:
with open(os_helper.TESTFN, mode="w") as f:
pass

with open(os_helper.TESTFN) as f:
self.assertEqual(get_line(f, 0), '')
with open(os_helper.TESTFN) as f:
self.assertEqual(get_line(f, 4), '')
with open(os_helper.TESTFN) as f:
self.assertRaises(EOFError, get_line, f, -1)

# Not `bytes` or `str` is returned:
class _BadIO(io.IOBase):
def readline(self, size = 0):
return object()

self.assertRaises(TypeError, get_line, _BadIO(), 0)
self.assertRaises(AttributeError, get_line, object(), 0)
# CRASHES: get_line(NULL)

def test_file_write_object(self):
# PyFile_WriteObject
write = _testcapi.file_write_object

def write_and_return(obj, flags=0):
dst = io.StringIO()
write(obj, dst, flags)
return dst.getvalue()

self.assertEqual(write_and_return(1), '1')
self.assertEqual(write_and_return('1'), "'1'")
Comment thread
sobolevn marked this conversation as resolved.
Outdated
self.assertEqual(write_and_return(False), 'False')
self.assertEqual(write_and_return(b'123'), "b'123'")
Comment thread
sobolevn marked this conversation as resolved.
Outdated

class Custom:
def __str__(self):
return '<str>'
def __repr__(self):
return '<repr>'

self.assertEqual(write_and_return(Custom()), '<repr>')
self.assertEqual(
write_and_return(Custom(), flags=_testcapi.Py_PRINT_RAW),
'<str>',
)

self.assertRaises(TypeError, write, object(), None)
Comment thread
sobolevn marked this conversation as resolved.
Outdated
# CRASHES: write(NULL, io.StringIO(), flags)
# CRASHES: write(NULL, NULL, flags)

def test_file_write_string(self):
# PyFile_WriteString
write = _testcapi.file_write_string

def write_and_return(string):
dst = io.StringIO()
write(string, dst)
return dst.getvalue()

self.assertEqual(write_and_return("abc"), "abc")
self.assertEqual(
Comment thread
sobolevn marked this conversation as resolved.
write_and_return("text with юникод 统一码"),
"text with юникод 统一码",
)
self.assertRaises(TypeError, write, object(), io.StringIO())
Comment thread
sobolevn marked this conversation as resolved.
Outdated
self.assertRaises(AttributeError, write, 'abc', object())
# CRASHES: write('', NULL)
Comment thread
sobolevn marked this conversation as resolved.
Outdated

def test_object_as_file_descriptor(self):
# PyObject_AsFileDescriptor()
as_fd = _testcapi.object_as_file_descriptor
with open(os_helper.TESTFN, mode="w") as f:
self.assertEqual(as_fd(f), f.fileno())
with open(os_helper.TESTFN, mode="w") as f:
Comment thread
sobolevn marked this conversation as resolved.
Outdated
self.assertEqual(as_fd(f.fileno()), f.fileno())

class _BadIO(io.IOBase):
def fileno(self):
return object() # not int
self.assertRaises(TypeError, as_fd, _BadIO())
self.assertRaises(TypeError, as_fd, object())
Comment thread
sobolevn marked this conversation as resolved.
Outdated
# CRASHES as_fd(NULL)
Comment thread
sobolevn marked this conversation as resolved.
Outdated
84 changes: 83 additions & 1 deletion Modules/_testcapi/file.c
Original file line number Diff line number Diff line change
@@ -1,15 +1,97 @@
#include "parts.h"
#include "util.h"

static PyObject *
file_from_fd(PyObject *self, PyObject *args)
{
int fd;
const char *name;
const char *mode;
int buffering;
const char *encoding;
const char *errors;
const char *newline;
int closefd;
if (!PyArg_ParseTuple(args, "ississsi",
Comment thread
sobolevn marked this conversation as resolved.
Outdated
&fd,
&name, &mode,
&buffering,
&encoding, &errors, &newline,
&closefd)) {
return NULL;
}

return PyFile_FromFd(fd,
name, mode,
buffering,
encoding, errors, newline,
closefd);
}

static PyObject *
file_get_line(PyObject *self, PyObject *args)
{
PyObject *obj;
int n;
if (!PyArg_ParseTuple(args, "Oi", &obj, &n)) {
return NULL;
}

NULLABLE(obj);
return PyFile_GetLine(obj, n);
}

static PyObject *
file_write_object(PyObject *self, PyObject *args)
{
PyObject *obj, *p;
int flags;
if (!PyArg_ParseTuple(args, "OOi", &obj, &p, &flags)) {
return NULL;
}

NULLABLE(obj);
NULLABLE(p);
RETURN_INT(PyFile_WriteObject(obj, p, flags));
}

static PyObject *
file_write_string(PyObject *self, PyObject *args)
{
const char *string;
PyObject *f;
if (!PyArg_ParseTuple(args, "sO", &string, &f)) {
return NULL;
}

NULLABLE(f);
RETURN_INT(PyFile_WriteString(string, f));
}

static PyObject *
object_as_file_descriptor(PyObject *self, PyObject *obj)
{
NULLABLE(obj);
RETURN_INT(PyObject_AsFileDescriptor(obj));
}

static PyMethodDef test_methods[] = {
{"file_from_fd", file_from_fd, METH_VARARGS},
{"file_get_line", file_get_line, METH_VARARGS},
{"file_write_object", file_write_object, METH_VARARGS},
{"file_write_string", file_write_string, METH_VARARGS},
{"object_as_file_descriptor", object_as_file_descriptor, METH_O},
{NULL},
};

int
_PyTestCapi_Init_File(PyObject *m)
{
if (PyModule_AddFunctions(m, test_methods) < 0){
if (PyModule_AddFunctions(m, test_methods) < 0) {
return -1;
}

if (PyModule_AddIntMacro(m, Py_PRINT_RAW) < 0) {
return -1;
}

Expand Down