[Buildroot] [PATCH 1/1] package/python-matplotlib: fix "Couldn't close file" runtime_error in pyplot import
Valerio De Benedetto
posta at debevv.com
Wed Mar 17 22:37:00 UTC 2021
This backports the PR from
https://github.com/matplotlib/matplotlib/pull/15104 to matplotlib 3.0.3.
Fixes the runtime_error thrown when executing "import matplotlib.pyplot"
in a python3 shell (same symptoms of
https://github.com/matplotlib/matplotlib/issues/15410)
Signed-off-by: Valerio De Benedetto <posta at debevv.com>
---
...03-Simplify-file-handling-in-ft2font.patch | 261 ++++++++++++++++++
1 file changed, 261 insertions(+)
create mode 100644
package/python-matplotlib/0003-Simplify-file-handling-in-ft2font.patch
diff --git
a/package/python-matplotlib/0003-Simplify-file-handling-in-ft2font.patch
b/package/python-matplotlib/0003-Simplify-file-handling-in-ft2font.patch
new file mode 100644
index 0000000000..392d1195f5
--- /dev/null
+++ b/package/python-matplotlib/0003-Simplify-file-handling-in-ft2font.patch
@@ -0,0 +1,261 @@
+--- a/src/ft2font_wrapper.cpp 2019-03-01 04:33:38.000000000 +0100
++++ b/src/ft2font_wrapper.cpp 2021-03-17 02:22:07.580939585 +0100
+@@ -1,6 +1,5 @@
+ #include "mplutils.h"
+ #include "ft2font.h"
+-#include "file_compat.h"
+ #include "py_converters.h"
+ #include "py_exceptions.h"
+ #include "numpy_cpp.h"
+@@ -328,12 +327,7 @@
+ FT2Font *x;
+ PyObject *fname;
+ PyObject *py_file;
+- FILE *fp;
+- int close_file;
+- mpl_off_t offset;
+ FT_StreamRec stream;
+- FT_Byte *mem;
+- size_t mem_size;
+ Py_ssize_t shape[2];
+ Py_ssize_t strides[2];
+ Py_ssize_t suboffsets[2];
+@@ -344,118 +338,43 @@
+ unsigned char *buffer,
+ unsigned long count)
+ {
+-
+- PyFT2Font *def = (PyFT2Font *)stream->descriptor.pointer;
+-
+- if (fseek(def->fp, offset, SEEK_SET) == -1) {
+- return 0;
++ PyObject *py_file = ((PyFT2Font
*)stream->descriptor.pointer)->py_file;
++ PyObject *seek_result = NULL, *read_result = NULL;
++ Py_ssize_t n_read = 0;
++ if (!(seek_result = PyObject_CallMethod(py_file, "seek", "k", offset))
++ || !(read_result = PyObject_CallMethod(py_file, "read", "k",
count))) {
++ goto exit;
++ }
++ char *tmpbuf;
++ if (PyBytes_AsStringAndSize(read_result, &tmpbuf, &n_read) == -1) {
++ goto exit;
+ }
+-
+- if (count > 0) {
+- return fread(buffer, 1, count, def->fp);
++ memcpy(buffer, tmpbuf, n_read);
++exit:
++ Py_XDECREF(seek_result);
++ Py_XDECREF(read_result);
++ if (PyErr_Occurred()) {
++ PyErr_WriteUnraisable(py_file);
++ if (!count) {
++ return 1; // Non-zero signals error, when count == 0.
++ }
+ }
+-
+- return 0;
++ return n_read;
+ }
+
+ static void close_file_callback(FT_Stream stream)
+ {
+- PyFT2Font *def = (PyFT2Font *)stream->descriptor.pointer;
+-
+- if (mpl_PyFile_DupClose(def->py_file, def->fp, def->offset)) {
+- throw std::runtime_error("Couldn't close file");
+- }
+-
+- if (def->close_file) {
+- mpl_PyFile_CloseFile(def->py_file);
+- }
+-
+- Py_DECREF(def->py_file);
+- def->py_file = NULL;
+-}
+-
+-static int convert_open_args(PyFT2Font *self, PyObject *py_file_arg,
FT_Open_Args *open_args)
+-{
+- PyObject *py_file = NULL;
+- int close_file = 0;
+- FILE *fp;
+- PyObject *data = NULL;
+- char *data_ptr;
+- Py_ssize_t data_len;
+- long file_size;
+- FT_Byte *new_memory;
+- mpl_off_t offset = 0;
+-
+- int result = 0;
+-
+- memset((void *)open_args, 0, sizeof(FT_Open_Args));
+-
+- if (PyBytes_Check(py_file_arg) || PyUnicode_Check(py_file_arg)) {
+- if ((py_file = mpl_PyFile_OpenFile(py_file_arg, (char *)"rb"))
== NULL) {
+- goto exit;
+- }
+- close_file = 1;
+- } else {
+- Py_INCREF(py_file_arg);
+- py_file = py_file_arg;
+- }
+-
+- if ((fp = mpl_PyFile_Dup(py_file, (char *)"rb", &offset))) {
+- Py_INCREF(py_file);
+- self->py_file = py_file;
+- self->close_file = close_file;
+- self->fp = fp;
+- self->offset = offset;
+- fseek(fp, 0, SEEK_END);
+- file_size = ftell(fp);
+- fseek(fp, 0, SEEK_SET);
+-
+- self->stream.base = NULL;
+- self->stream.size = (unsigned long)file_size;
+- self->stream.pos = 0;
+- self->stream.descriptor.pointer = self;
+- self->stream.read = &read_from_file_callback;
+- self->stream.close = &close_file_callback;
+-
+- open_args->flags = FT_OPEN_STREAM;
+- open_args->stream = &self->stream;
+- } else {
+- if (PyObject_HasAttrString(py_file_arg, "read") &&
+- (data = PyObject_CallMethod(py_file_arg, (char *)"read",
(char *)""))) {
+- if (PyBytes_AsStringAndSize(data, &data_ptr, &data_len)) {
+- goto exit;
+- }
+-
+- if (self->mem) {
+- free(self->mem);
+- }
+- self->mem = (FT_Byte *)malloc((self->mem_size + data_len)
* sizeof(FT_Byte));
+- if (self->mem == NULL) {
+- goto exit;
+- }
+- new_memory = self->mem + self->mem_size;
+- self->mem_size += data_len;
+-
+- memcpy(new_memory, data_ptr, data_len);
+- open_args->flags = FT_OPEN_MEMORY;
+- open_args->memory_base = new_memory;
+- open_args->memory_size = data_len;
+- open_args->stream = NULL;
+- } else {
+- PyErr_SetString(PyExc_TypeError,
+- "First argument must be a path or file
object reading bytes");
+- goto exit;
+- }
++ PyFT2Font *self = (PyFT2Font *)stream->descriptor.pointer;
++ PyObject *close_result = NULL;
++ if (!(close_result = PyObject_CallMethod(self->py_file, "close",
""))) {
++ goto exit;
+ }
+-
+- result = 1;
+-
+ exit:
+-
+- Py_XDECREF(py_file);
+- Py_XDECREF(data);
+-
+- return result;
++ Py_XDECREF(close_result);
++ Py_CLEAR(self->py_file);
++ if (PyErr_Occurred()) {
++ PyErr_WriteUnraisable((PyObject*)self);
++ }
+ }
+
+ static PyTypeObject PyFT2FontType;
+@@ -467,12 +386,7 @@
+ self->x = NULL;
+ self->fname = NULL;
+ self->py_file = NULL;
+- self->fp = NULL;
+- self->close_file = 0;
+- self->offset = 0;
+ memset(&self->stream, 0, sizeof(FT_StreamRec));
+- self->mem = 0;
+- self->mem_size = 0;
+ return (PyObject *)self;
+ }
+
+@@ -503,35 +417,54 @@
+ " underline_thickness vertical thickness of the underline\n"
+ " postscript_name PostScript name of the font\n";
+
+-static void PyFT2Font_fail(PyFT2Font *self)
+-{
+- free(self->mem);
+- self->mem = NULL;
+- Py_XDECREF(self->py_file);
+- self->py_file = NULL;
+-}
+-
+ static int PyFT2Font_init(PyFT2Font *self, PyObject *args, PyObject *kwds)
+ {
+- PyObject *fname;
++ PyObject *filename = NULL, *open = NULL, *data = NULL;
+ FT_Open_Args open_args;
+ long hinting_factor = 8;
+ const char *names[] = { "filename", "hinting_factor", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(
+- args, kwds, "O|l:FT2Font", (char **)names, &fname,
&hinting_factor)) {
++ args, kwds, "O|l:FT2Font", (char **)names, &filename,
&hinting_factor)) {
+ return -1;
+ }
+
+- if (!convert_open_args(self, fname, &open_args)) {
+- return -1;
++ self->stream.base = NULL;
++ self->stream.size = 0x7fffffff; // Unknown size.
++ self->stream.pos = 0;
++ self->stream.descriptor.pointer = self;
++ self->stream.read = &read_from_file_callback;
++ memset((void *)&open_args, 0, sizeof(FT_Open_Args));
++ open_args.flags = FT_OPEN_STREAM;
++ open_args.stream = &self->stream;
++
++ if (PyBytes_Check(filename) || PyUnicode_Check(filename)) {
++ if (!(open = PyDict_GetItemString(PyEval_GetBuiltins(),
"open")) // Borrowed reference.
++ || !(self->py_file = PyObject_CallFunction(open, "Os",
filename, "rb"))) {
++ goto exit;
++ }
++ self->stream.close = &close_file_callback;
++ } else if (!PyObject_HasAttrString(filename, "read")
++ || !(data = PyObject_CallMethod(filename, "read", "i", 0))
++ || !PyBytes_Check(data)) {
++ PyErr_SetString(PyExc_TypeError,
++ "First argument must be a path or binary-mode
file object");
++ goto exit;
++ } else {
++ self->py_file = filename;
++ self->stream.close = NULL;
++ Py_INCREF(filename);
+ }
+
+ CALL_CPP_FULL(
+- "FT2Font", (self->x = new FT2Font(open_args, hinting_factor)),
PyFT2Font_fail(self), -1);
++ "FT2Font", (self->x = new FT2Font(open_args, hinting_factor)),
++ Py_CLEAR(self->py_file), -1);
+
+- Py_INCREF(fname);
+- self->fname = fname;
++ Py_INCREF(filename);
++ self->fname = filename;
++
++exit:
++ Py_XDECREF(data);
+
+ return 0;
+ }
+@@ -539,7 +472,6 @@
+ static void PyFT2Font_dealloc(PyFT2Font *self)
+ {
+ delete self->x;
+- free(self->mem);
+ Py_XDECREF(self->py_file);
+ Py_XDECREF(self->fname);
+ Py_TYPE(self)->tp_free((PyObject *)self);
--
2.25.1
More information about the buildroot
mailing list