Skip to content

Commit 7976663

Browse files
author
Victor Stinner
committed
Issue python#9599: Create PySys_FormatStdout() and PySys_FormatStderr()
Write a message formatted by PyUnicode_FromFormatV() to sys.stdout and sys.stderr.
1 parent 982c018 commit 7976663

File tree

4 files changed

+87
-18
lines changed

4 files changed

+87
-18
lines changed

Doc/c-api/sys.rst

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,19 @@ accessible to C code. They all work with the current interpreter thread's
109109

110110
.. cfunction:: void PySys_WriteStderr(const char *format, ...)
111111

112-
As above, but write to :data:`sys.stderr` or *stderr* instead.
112+
As :cfunc:`PySys_WriteStdout`, but write to :data:`sys.stderr` or *stderr*
113+
instead.
113114

115+
.. cfunction:: void PySys_FormatStdout(const char *format, ...)
116+
117+
Function similar to PySys_WriteStdout() but format the message using
118+
:cfunc:`PyUnicode_FromFormatV` and don't truncate the message to an
119+
arbitrary length.
120+
121+
.. cfunction:: void PySys_FormatStderr(const char *format, ...)
122+
123+
As :cfunc:`PySys_FormatStdout`, but write to :data:`sys.stderr` or *stderr*
124+
instead.
114125

115126
.. _processcontrol:
116127

Include/sysmodule.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ PyAPI_FUNC(void) PySys_SetArgvEx(int, wchar_t **, int);
1414
PyAPI_FUNC(void) PySys_SetPath(const wchar_t *);
1515

1616
PyAPI_FUNC(void) PySys_WriteStdout(const char *format, ...)
17-
Py_GCC_ATTRIBUTE((format(printf, 1, 2)));
17+
Py_GCC_ATTRIBUTE((format(printf, 1, 2)));
1818
PyAPI_FUNC(void) PySys_WriteStderr(const char *format, ...)
19-
Py_GCC_ATTRIBUTE((format(printf, 1, 2)));
19+
Py_GCC_ATTRIBUTE((format(printf, 1, 2)));
20+
PyAPI_FUNC(void) PySys_FormatStdout(const char *format, ...);
21+
PyAPI_FUNC(void) PySys_FormatStderr(const char *format, ...);
2022

2123
PyAPI_DATA(PyObject *) _PySys_TraceFunc, *_PySys_ProfileFunc;
2224

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ What's New in Python 3.2 Alpha 2?
1212
Core and Builtins
1313
-----------------
1414

15+
- Issue #9599: Create PySys_FormatStdout() and PySys_FormatStderr() functions
16+
to write a message formatted by PyUnicode_FromFormatV() to sys.stdout and
17+
sys.stderr.
18+
1519
- Issue #9542: Create PyUnicode_FSDecoder() function, a ParseTuple converter:
1620
decode bytes objects to unicode using PyUnicode_DecodeFSDefaultAndSize();
1721
str objects are output as-is.

Python/sysmodule.c

Lines changed: 67 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1834,18 +1834,14 @@ PySys_SetArgv(int argc, wchar_t **argv)
18341834
PyErr_CheckSignals(): avoid the call to PyObject_Str(). */
18351835

18361836
static int
1837-
sys_pyfile_write(const char *text, PyObject *file)
1837+
sys_pyfile_write_unicode(PyObject *unicode, PyObject *file)
18381838
{
1839-
PyObject *unicode = NULL, *writer = NULL, *args = NULL, *result = NULL;
1839+
PyObject *writer = NULL, *args = NULL, *result = NULL;
18401840
int err;
18411841

18421842
if (file == NULL)
18431843
return -1;
18441844

1845-
unicode = PyUnicode_FromString(text);
1846-
if (unicode == NULL)
1847-
goto error;
1848-
18491845
writer = PyObject_GetAttrString(file, "write");
18501846
if (writer == NULL)
18511847
goto error;
@@ -1865,13 +1861,29 @@ sys_pyfile_write(const char *text, PyObject *file)
18651861
error:
18661862
err = -1;
18671863
finally:
1868-
Py_XDECREF(unicode);
18691864
Py_XDECREF(writer);
18701865
Py_XDECREF(args);
18711866
Py_XDECREF(result);
18721867
return err;
18731868
}
18741869

1870+
static int
1871+
sys_pyfile_write(const char *text, PyObject *file)
1872+
{
1873+
PyObject *unicode = NULL;
1874+
int err;
1875+
1876+
if (file == NULL)
1877+
return -1;
1878+
1879+
unicode = PyUnicode_FromString(text);
1880+
if (unicode == NULL)
1881+
return -1;
1882+
1883+
err = sys_pyfile_write_unicode(unicode, file);
1884+
Py_DECREF(unicode);
1885+
return err;
1886+
}
18751887

18761888
/* APIs to write to sys.stdout or sys.stderr using a printf-like interface.
18771889
Adapted from code submitted by Just van Rossum.
@@ -1884,8 +1896,8 @@ sys_pyfile_write(const char *text, PyObject *file)
18841896
no exceptions are raised.
18851897
18861898
PyErr_CheckSignals() is not called to avoid the execution of the Python
1887-
signal handlers: they may raise a new exception whereas mywrite() ignores
1888-
all exceptions.
1899+
signal handlers: they may raise a new exception whereas sys_write()
1900+
ignores all exceptions.
18891901
18901902
Both take a printf-style format string as their first argument followed
18911903
by a variable length argument list determined by the format string.
@@ -1902,7 +1914,7 @@ sys_pyfile_write(const char *text, PyObject *file)
19021914
*/
19031915

19041916
static void
1905-
mywrite(char *name, FILE *fp, const char *format, va_list va)
1917+
sys_write(char *name, FILE *fp, const char *format, va_list va)
19061918
{
19071919
PyObject *file;
19081920
PyObject *error_type, *error_value, *error_traceback;
@@ -1918,10 +1930,8 @@ mywrite(char *name, FILE *fp, const char *format, va_list va)
19181930
}
19191931
if (written < 0 || (size_t)written >= sizeof(buffer)) {
19201932
const char *truncated = "... truncated";
1921-
if (sys_pyfile_write(truncated, file) != 0) {
1922-
PyErr_Clear();
1933+
if (sys_pyfile_write(truncated, file) != 0)
19231934
fputs(truncated, fp);
1924-
}
19251935
}
19261936
PyErr_Restore(error_type, error_value, error_traceback);
19271937
}
@@ -1932,7 +1942,7 @@ PySys_WriteStdout(const char *format, ...)
19321942
va_list va;
19331943

19341944
va_start(va, format);
1935-
mywrite("stdout", stdout, format, va);
1945+
sys_write("stdout", stdout, format, va);
19361946
va_end(va);
19371947
}
19381948

@@ -1942,6 +1952,48 @@ PySys_WriteStderr(const char *format, ...)
19421952
va_list va;
19431953

19441954
va_start(va, format);
1945-
mywrite("stderr", stderr, format, va);
1955+
sys_write("stderr", stderr, format, va);
1956+
va_end(va);
1957+
}
1958+
1959+
static void
1960+
sys_format(char *name, FILE *fp, const char *format, va_list va)
1961+
{
1962+
PyObject *file, *message;
1963+
PyObject *error_type, *error_value, *error_traceback;
1964+
char *utf8;
1965+
1966+
PyErr_Fetch(&error_type, &error_value, &error_traceback);
1967+
file = PySys_GetObject(name);
1968+
message = PyUnicode_FromFormatV(format, va);
1969+
if (message != NULL) {
1970+
if (sys_pyfile_write_unicode(message, file) != 0) {
1971+
PyErr_Clear();
1972+
utf8 = _PyUnicode_AsString(message);
1973+
if (utf8 != NULL)
1974+
fputs(utf8, fp);
1975+
}
1976+
Py_DECREF(message);
1977+
}
1978+
PyErr_Restore(error_type, error_value, error_traceback);
1979+
}
1980+
1981+
void
1982+
PySys_FormatStdout(const char *format, ...)
1983+
{
1984+
va_list va;
1985+
1986+
va_start(va, format);
1987+
sys_format("stdout", stdout, format, va);
1988+
va_end(va);
1989+
}
1990+
1991+
void
1992+
PySys_FormatStderr(const char *format, ...)
1993+
{
1994+
va_list va;
1995+
1996+
va_start(va, format);
1997+
sys_format("stderr", stderr, format, va);
19461998
va_end(va);
19471999
}

0 commit comments

Comments
 (0)