diff --git a/news/fix_win.rst b/news/fix_win.rst new file mode 100644 index 00000000..f74cd809 --- /dev/null +++ b/news/fix_win.rst @@ -0,0 +1,23 @@ +**Added:** + +* + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* Removed `restore_stdout` function and wrapper. + +**Fixed:** + +* Fixed `SystemError` and `MemoryError` for `redirect_stdout` on Windows with Python 3.13. + +**Security:** + +* diff --git a/src/diffpy/pdffit2/output.py b/src/diffpy/pdffit2/output.py index 9fc55eea..f24c28e9 100644 --- a/src/diffpy/pdffit2/output.py +++ b/src/diffpy/pdffit2/output.py @@ -39,13 +39,4 @@ def redirect_stdout(dst): return -def restore_stdout(): - """Restore the standard output.""" - from diffpy.pdffit2.pdffit2 import restore_stdout - - restore_stdout() - global stdout - return - - # End of file diff --git a/src/extensions/pdffit2module/PyFileStreambuf.h b/src/extensions/pdffit2module/PyFileStreambuf.h index 3a2bc383..cc8588bc 100644 --- a/src/extensions/pdffit2module/PyFileStreambuf.h +++ b/src/extensions/pdffit2module/PyFileStreambuf.h @@ -67,16 +67,21 @@ class PyFileStreambuf : public std::streambuf virtual int_type overflow( int_type c) { - PyObject* rv; - rv = PyObject_CallMethod(py_file, "write", "(s#)", &c, 1); + char ch = static_cast(c); + PyObject* py_str = PyUnicode_FromStringAndSize(&ch, 1); + if (!py_str) { return traits_type::eof(); } + PyObject* rv = PyObject_CallMethod(py_file, "write", "O", py_str); + Py_DECREF(py_str); if (rv) { Py_DECREF(rv); } return c; } virtual std::streamsize xsputn(const char_type* s, std::streamsize n) { - PyObject* rv; - rv = PyObject_CallMethod(py_file, "write", "(s#)", s, n); + PyObject* py_str = PyUnicode_DecodeUTF8(s, n, "replace"); + if (!py_str) { return 0; } + PyObject* rv = PyObject_CallMethod(py_file, "write", "O", py_str); + Py_DECREF(py_str); if (rv) { Py_DECREF(rv); } return n; } diff --git a/src/extensions/pdffit2module/bindings.cc b/src/extensions/pdffit2module/bindings.cc index 3a542aed..568e1dd1 100644 --- a/src/extensions/pdffit2module/bindings.cc +++ b/src/extensions/pdffit2module/bindings.cc @@ -330,10 +330,6 @@ struct PyMethodDef pypdffit2_methods[] = { {pypdffit2_redirect_stdout__name__, pypdffit2_redirect_stdout, METH_VARARGS, pypdffit2_redirect_stdout__doc__}, - //restore_stdout - {pypdffit2_restore_stdout__name__, pypdffit2_restore_stdout, - METH_VARARGS, pypdffit2_restore_stdout__doc__}, - //is_element {pypdffit2_is_element__name__, pypdffit2_is_element, METH_VARARGS, pypdffit2_is_element__doc__}, diff --git a/src/extensions/pdffit2module/misc.cc b/src/extensions/pdffit2module/misc.cc index 20547a23..f3f22a21 100644 --- a/src/extensions/pdffit2module/misc.cc +++ b/src/extensions/pdffit2module/misc.cc @@ -2176,15 +2176,14 @@ char pypdffit2_redirect_stdout__name__[] = "redirect_stdout"; PyObject * pypdffit2_redirect_stdout(PyObject *, PyObject *args) { // instance of PyFileStreambuf which takes care of redirection - PyObject *py_file = 0; - int ok = PyArg_ParseTuple(args, "O", &py_file); - if (!ok) return 0; + PyObject *py_file = nullptr; + if (!PyArg_ParseTuple(args, "O", &py_file)) return nullptr; // check if py_file has write and flush attributes if ( !PyObject_HasAttrString(py_file, "write") || !PyObject_HasAttrString(py_file, "flush") ) { PyErr_SetString(PyExc_TypeError, "expected file-like argument"); - return 0; + return nullptr; } // create py_stdout_streambuf if necessary if (!py_stdout_streambuf) @@ -2195,38 +2194,8 @@ PyObject * pypdffit2_redirect_stdout(PyObject *, PyObject *args) // on first redirection we need to assign new ostream to NS_PDFFIT2::pout if (NS_PDFFIT2::pout == &std::cout) { - NS_PDFFIT2::pout = new ostream(py_stdout_streambuf); - } - Py_INCREF(Py_None); - return Py_None; -} - -// restore_stdout -char pypdffit2_restore_stdout__doc__[] = - "Restore engine output to the default stream (std::cout)."; -char pypdffit2_restore_stdout__name__[] = - "restore_stdout"; - -PyObject * pypdffit2_restore_stdout(PyObject *, PyObject *args) -{ - // no arguments. - if (!PyArg_ParseTuple(args, "")) - return 0; - - // If the global output stream pointer is not std::cout, then delete the custom stream. - if (NS_PDFFIT2::pout != &std::cout) - { - delete NS_PDFFIT2::pout; - NS_PDFFIT2::pout = &std::cout; + NS_PDFFIT2::pout = new std::ostream(py_stdout_streambuf); } - - // Clean up the custom stream buffer - if (py_stdout_streambuf) - { - delete py_stdout_streambuf; - py_stdout_streambuf = nullptr; - } - Py_INCREF(Py_None); return Py_None; } diff --git a/src/extensions/pdffit2module/misc.h b/src/extensions/pdffit2module/misc.h index 2ccec0fa..3374fa5f 100644 --- a/src/extensions/pdffit2module/misc.h +++ b/src/extensions/pdffit2module/misc.h @@ -477,11 +477,6 @@ extern char pypdffit2_redirect_stdout__name__[]; extern "C" PyObject * pypdffit2_redirect_stdout(PyObject *, PyObject *); -// restore_stdout -extern char pypdffit2_restore_stdout__doc__[]; -extern char pypdffit2_restore_stdout__name__[]; -extern "C" -PyObject * pypdffit2_restore_stdout(PyObject *, PyObject *); // is_element extern char pypdffit2_is_element__doc__[]; diff --git a/tests/conftest.py b/tests/conftest.py index 2192452a..6a142536 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -45,7 +45,6 @@ def _capture(f, *args, **kwargs): f(*args, **kwargs) finally: diffpy.pdffit2.redirect_stdout(savestdout) - diffpy.pdffit2.output.restore_stdout() return fp.getvalue() return _capture