Skip to content

Commit b8d1744

Browse files
gh-109611: Add convenient C API function _PyFile_Flush() (GH-109612)
1 parent 92af0cc commit b8d1744

File tree

11 files changed

+54
-97
lines changed

11 files changed

+54
-97
lines changed

Include/internal/pycore_fileutils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,8 @@ PyAPI_FUNC(int) _PyLong_FileDescriptor_Converter(PyObject *, void *);
318318
// Export for test_peg_generator
319319
PyAPI_FUNC(char*) _Py_UniversalNewlineFgetsWithSize(char *, int, FILE*, PyObject *, size_t*);
320320

321+
extern int _PyFile_Flush(PyObject *);
322+
321323
#ifdef __cplusplus
322324
}
323325
#endif

Modules/_io/bufferedio.c

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -553,17 +553,14 @@ _io__Buffered_close_impl(buffered *self)
553553
}
554554
/* flush() will most probably re-take the lock, so drop it first */
555555
LEAVE_BUFFERED(self)
556-
res = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(flush));
556+
r = _PyFile_Flush((PyObject *)self);
557557
if (!ENTER_BUFFERED(self)) {
558558
return NULL;
559559
}
560560
PyObject *exc = NULL;
561-
if (res == NULL) {
561+
if (r < 0) {
562562
exc = PyErr_GetRaisedException();
563563
}
564-
else {
565-
Py_DECREF(res);
566-
}
567564

568565
res = PyObject_CallMethodNoArgs(self->raw, &_Py_ID(close));
569566

@@ -593,12 +590,11 @@ static PyObject *
593590
_io__Buffered_detach_impl(buffered *self)
594591
/*[clinic end generated code: output=dd0fc057b8b779f7 input=482762a345cc9f44]*/
595592
{
596-
PyObject *raw, *res;
593+
PyObject *raw;
597594
CHECK_INITIALIZED(self)
598-
res = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(flush));
599-
if (res == NULL)
595+
if (_PyFile_Flush((PyObject *)self) < 0) {
600596
return NULL;
601-
Py_DECREF(res);
597+
}
602598
raw = self->raw;
603599
self->raw = NULL;
604600
self->detached = 1;

Modules/_io/iobase.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ static PyObject *
265265
_io__IOBase_close_impl(PyObject *self)
266266
/*[clinic end generated code: output=63c6a6f57d783d6d input=f4494d5c31dbc6b7]*/
267267
{
268-
int rc, closed = iobase_is_closed(self);
268+
int rc1, rc2, closed = iobase_is_closed(self);
269269

270270
if (closed < 0) {
271271
return NULL;
@@ -274,19 +274,14 @@ _io__IOBase_close_impl(PyObject *self)
274274
Py_RETURN_NONE;
275275
}
276276

277-
PyObject *res = PyObject_CallMethodNoArgs(self, &_Py_ID(flush));
278-
277+
rc1 = _PyFile_Flush(self);
279278
PyObject *exc = PyErr_GetRaisedException();
280-
rc = PyObject_SetAttr(self, &_Py_ID(__IOBase_closed), Py_True);
279+
rc2 = PyObject_SetAttr(self, &_Py_ID(__IOBase_closed), Py_True);
281280
_PyErr_ChainExceptions1(exc);
282-
if (rc < 0) {
283-
Py_CLEAR(res);
284-
}
285-
286-
if (res == NULL)
281+
if (rc1 < 0 || rc2 < 0) {
287282
return NULL;
283+
}
288284

289-
Py_DECREF(res);
290285
Py_RETURN_NONE;
291286
}
292287

Modules/_io/textio.c

Lines changed: 15 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,11 +1368,9 @@ _io_TextIOWrapper_reconfigure_impl(textio *self, PyObject *encoding,
13681368
return NULL;
13691369
}
13701370

1371-
PyObject *res = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(flush));
1372-
if (res == NULL) {
1371+
if (_PyFile_Flush((PyObject *)self) < 0) {
13731372
return NULL;
13741373
}
1375-
Py_DECREF(res);
13761374
self->b2cratio = 0;
13771375

13781376
if (newline_obj != NULL && set_newline(self, newline) < 0) {
@@ -1508,12 +1506,11 @@ static PyObject *
15081506
_io_TextIOWrapper_detach_impl(textio *self)
15091507
/*[clinic end generated code: output=7ba3715cd032d5f2 input=e5a71fbda9e1d9f9]*/
15101508
{
1511-
PyObject *buffer, *res;
1509+
PyObject *buffer;
15121510
CHECK_ATTACHED(self);
1513-
res = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(flush));
1514-
if (res == NULL)
1511+
if (_PyFile_Flush((PyObject *)self) < 0) {
15151512
return NULL;
1516-
Py_DECREF(res);
1513+
}
15171514
buffer = self->buffer;
15181515
self->buffer = NULL;
15191516
self->detached = 1;
@@ -1713,10 +1710,9 @@ _io_TextIOWrapper_write_impl(textio *self, PyObject *text)
17131710
}
17141711

17151712
if (needflush) {
1716-
ret = PyObject_CallMethodNoArgs(self->buffer, &_Py_ID(flush));
1717-
if (ret == NULL)
1713+
if (_PyFile_Flush(self->buffer) < 0) {
17181714
return NULL;
1719-
Py_DECREF(ret);
1715+
}
17201716
}
17211717

17221718
textiowrapper_set_decoded_chars(self, NULL);
@@ -2502,10 +2498,9 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence)
25022498
goto fail;
25032499
}
25042500

2505-
res = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(flush));
2506-
if (res == NULL)
2501+
if (_PyFile_Flush((PyObject *)self) < 0) {
25072502
goto fail;
2508-
Py_DECREF(res);
2503+
}
25092504

25102505
textiowrapper_set_decoded_chars(self, NULL);
25112506
Py_CLEAR(self->snapshot);
@@ -2550,10 +2545,9 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence)
25502545
goto fail;
25512546
}
25522547

2553-
res = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(flush));
2554-
if (res == NULL)
2548+
if (_PyFile_Flush((PyObject *)self) < 0) {
25552549
goto fail;
2556-
Py_DECREF(res);
2550+
}
25572551

25582552
/* The strategy of seek() is to go back to the safe start point
25592553
* and replay the effect of read(chars_to_skip) from there.
@@ -2677,10 +2671,9 @@ _io_TextIOWrapper_tell_impl(textio *self)
26772671

26782672
if (_textiowrapper_writeflush(self) < 0)
26792673
return NULL;
2680-
res = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(flush));
2681-
if (res == NULL)
2674+
if (_PyFile_Flush((PyObject *)self) < 0) {
26822675
goto fail;
2683-
Py_DECREF(res);
2676+
}
26842677

26852678
posobj = PyObject_CallMethodNoArgs(self->buffer, &_Py_ID(tell));
26862679
if (posobj == NULL)
@@ -2885,14 +2878,11 @@ static PyObject *
28852878
_io_TextIOWrapper_truncate_impl(textio *self, PyObject *pos)
28862879
/*[clinic end generated code: output=90ec2afb9bb7745f input=56ec8baa65aea377]*/
28872880
{
2888-
PyObject *res;
2889-
28902881
CHECK_ATTACHED(self)
28912882

2892-
res = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(flush));
2893-
if (res == NULL)
2883+
if (_PyFile_Flush((PyObject *)self) < 0) {
28942884
return NULL;
2895-
Py_DECREF(res);
2885+
}
28962886

28972887
return PyObject_CallMethodOneArg(self->buffer, &_Py_ID(truncate), pos);
28982888
}
@@ -3076,13 +3066,9 @@ _io_TextIOWrapper_close_impl(textio *self)
30763066
PyErr_Clear();
30773067
}
30783068
}
3079-
res = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(flush));
3080-
if (res == NULL) {
3069+
if (_PyFile_Flush((PyObject *)self) < 0) {
30813070
exc = PyErr_GetRaisedException();
30823071
}
3083-
else {
3084-
Py_DECREF(res);
3085-
}
30863072

30873073
res = PyObject_CallMethodNoArgs(self->buffer, &_Py_ID(close));
30883074
if (exc != NULL) {

Modules/_threadmodule.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,11 +1497,9 @@ thread_excepthook_file(PyObject *file, PyObject *exc_type, PyObject *exc_value,
14971497
_PyErr_Display(file, exc_type, exc_value, exc_traceback);
14981498

14991499
/* Call file.flush() */
1500-
PyObject *res = PyObject_CallMethodNoArgs(file, &_Py_ID(flush));
1501-
if (!res) {
1500+
if (_PyFile_Flush(file) < 0) {
15021501
return -1;
15031502
}
1504-
Py_DECREF(res);
15051503

15061504
return 0;
15071505
}

Modules/faulthandler.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,7 @@ faulthandler_get_fileno(PyObject **file_ptr)
146146
return -1;
147147
}
148148

149-
result = PyObject_CallMethodNoArgs(file, &_Py_ID(flush));
150-
if (result != NULL)
151-
Py_DECREF(result);
152-
else {
149+
if (_PyFile_Flush(file) < 0) {
153150
/* ignore flush() error */
154151
PyErr_Clear();
155152
}

Objects/fileobject.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,18 @@ PyFile_OpenCode(const char *utf8path)
529529
}
530530

531531

532+
int
533+
_PyFile_Flush(PyObject *file)
534+
{
535+
PyObject *tmp = PyObject_CallMethodNoArgs(file, &_Py_ID(flush));
536+
if (tmp == NULL) {
537+
return -1;
538+
}
539+
Py_DECREF(tmp);
540+
return 0;
541+
}
542+
543+
532544
#ifdef __cplusplus
533545
}
534546
#endif

Python/bltinmodule.c

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2083,11 +2083,9 @@ builtin_print_impl(PyObject *module, PyObject *args, PyObject *sep,
20832083
}
20842084

20852085
if (flush) {
2086-
PyObject *tmp = PyObject_CallMethodNoArgs(file, &_Py_ID(flush));
2087-
if (tmp == NULL) {
2086+
if (_PyFile_Flush(file) < 0) {
20882087
return NULL;
20892088
}
2090-
Py_DECREF(tmp);
20912089
}
20922090

20932091
Py_RETURN_NONE;
@@ -2146,11 +2144,9 @@ builtin_input_impl(PyObject *module, PyObject *prompt)
21462144
}
21472145

21482146
/* First of all, flush stderr */
2149-
tmp = PyObject_CallMethodNoArgs(ferr, &_Py_ID(flush));
2150-
if (tmp == NULL)
2147+
if (_PyFile_Flush(ferr) < 0) {
21512148
PyErr_Clear();
2152-
else
2153-
Py_DECREF(tmp);
2149+
}
21542150

21552151
/* We should only use (GNU) readline if Python's sys.stdin and
21562152
sys.stdout are the same as C's stdin and stdout, because we
@@ -2218,11 +2214,9 @@ builtin_input_impl(PyObject *module, PyObject *prompt)
22182214
if (stdin_errors_str == NULL) {
22192215
goto _readline_errors;
22202216
}
2221-
tmp = PyObject_CallMethodNoArgs(fout, &_Py_ID(flush));
2222-
if (tmp == NULL)
2217+
if (_PyFile_Flush(fout) < 0) {
22232218
PyErr_Clear();
2224-
else
2225-
Py_DECREF(tmp);
2219+
}
22262220
if (prompt != NULL) {
22272221
/* We have a prompt, encode it as stdout would */
22282222
const char *stdout_encoding_str, *stdout_errors_str;
@@ -2325,11 +2319,9 @@ builtin_input_impl(PyObject *module, PyObject *prompt)
23252319
if (PyFile_WriteObject(prompt, fout, Py_PRINT_RAW) != 0)
23262320
return NULL;
23272321
}
2328-
tmp = PyObject_CallMethodNoArgs(fout, &_Py_ID(flush));
2329-
if (tmp == NULL)
2322+
if (_PyFile_Flush(fout) < 0) {
23302323
PyErr_Clear();
2331-
else
2332-
Py_DECREF(tmp);
2324+
}
23332325
return PyFile_GetLine(fin, -1);
23342326
}
23352327

Python/errors.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1513,11 +1513,9 @@ write_unraisable_exc_file(PyThreadState *tstate, PyObject *exc_type,
15131513
}
15141514

15151515
/* Explicitly call file.flush() */
1516-
PyObject *res = PyObject_CallMethodNoArgs(file, &_Py_ID(flush));
1517-
if (!res) {
1516+
if (_PyFile_Flush(file) < 0) {
15181517
return -1;
15191518
}
1520-
Py_DECREF(res);
15211519

15221520
return 0;
15231521
}

Python/pylifecycle.c

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,27 +1639,20 @@ flush_std_files(void)
16391639
PyThreadState *tstate = _PyThreadState_GET();
16401640
PyObject *fout = _PySys_GetAttr(tstate, &_Py_ID(stdout));
16411641
PyObject *ferr = _PySys_GetAttr(tstate, &_Py_ID(stderr));
1642-
PyObject *tmp;
16431642
int status = 0;
16441643

16451644
if (fout != NULL && fout != Py_None && !file_is_closed(fout)) {
1646-
tmp = PyObject_CallMethodNoArgs(fout, &_Py_ID(flush));
1647-
if (tmp == NULL) {
1645+
if (_PyFile_Flush(fout) < 0) {
16481646
PyErr_WriteUnraisable(fout);
16491647
status = -1;
16501648
}
1651-
else
1652-
Py_DECREF(tmp);
16531649
}
16541650

16551651
if (ferr != NULL && ferr != Py_None && !file_is_closed(ferr)) {
1656-
tmp = PyObject_CallMethodNoArgs(ferr, &_Py_ID(flush));
1657-
if (tmp == NULL) {
1652+
if (_PyFile_Flush(ferr) < 0) {
16581653
PyErr_Clear();
16591654
status = -1;
16601655
}
1661-
else
1662-
Py_DECREF(tmp);
16631656
}
16641657

16651658
return status;
@@ -2632,13 +2625,9 @@ _Py_FatalError_PrintExc(PyThreadState *tstate)
26322625
Py_DECREF(exc);
26332626

26342627
/* sys.stderr may be buffered: call sys.stderr.flush() */
2635-
PyObject *res = PyObject_CallMethodNoArgs(ferr, &_Py_ID(flush));
2636-
if (res == NULL) {
2628+
if (_PyFile_Flush(ferr) < 0) {
26372629
_PyErr_Clear(tstate);
26382630
}
2639-
else {
2640-
Py_DECREF(res);
2641-
}
26422631

26432632
return has_tb;
26442633
}

Python/pythonrun.c

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1562,14 +1562,10 @@ _PyErr_Display(PyObject *file, PyObject *unused, PyObject *value, PyObject *tb)
15621562
Py_XDECREF(ctx.seen);
15631563

15641564
/* Call file.flush() */
1565-
PyObject *res = PyObject_CallMethodNoArgs(file, &_Py_ID(flush));
1566-
if (!res) {
1565+
if (_PyFile_Flush(file) < 0) {
15671566
/* Silently ignore file.flush() error */
15681567
PyErr_Clear();
15691568
}
1570-
else {
1571-
Py_DECREF(res);
1572-
}
15731569
}
15741570

15751571
void
@@ -1674,11 +1670,7 @@ flush_io_stream(PyThreadState *tstate, PyObject *name)
16741670
{
16751671
PyObject *f = _PySys_GetAttr(tstate, name);
16761672
if (f != NULL) {
1677-
PyObject *r = PyObject_CallMethodNoArgs(f, &_Py_ID(flush));
1678-
if (r) {
1679-
Py_DECREF(r);
1680-
}
1681-
else {
1673+
if (_PyFile_Flush(f) < 0) {
16821674
PyErr_Clear();
16831675
}
16841676
}

0 commit comments

Comments
 (0)