summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoruser <user@localhost.localdomain>2012-07-12 20:16:06 +0800
committeruser <user@localhost.localdomain>2012-07-12 20:16:06 +0800
commit9576b3d77034d91f456a5b199a9fc9cc2fde3c08 (patch)
tree58d75df5e3c62e4ec299135ee6e511c7c5268331
parentcbb102e3d0735028c624583264ce5243d93ef844 (diff)
downloadpycairo-9576b3d77034d91f456a5b199a9fc9cc2fde3c08.tar.gz
setup.py: add extra error messages.
SVGSurface: Change from bytes-mode to text-mode, so SVG files can be written to sys.stdout. Fixes bug #50989.
-rw-r--r--doc/reference/surfaces.rst25
-rwxr-xr-xsetup.py5
-rw-r--r--src/surface.c46
-rwxr-xr-xtest/surface_create_for_stream.py28
4 files changed, 68 insertions, 36 deletions
diff --git a/doc/reference/surfaces.rst b/doc/reference/surfaces.rst
index 0ba51c9..949b05e 100644
--- a/doc/reference/surfaces.rst
+++ b/doc/reference/surfaces.rst
@@ -227,7 +227,7 @@ class Surface()
.. method:: write_to_png(fobj)
:param fobj: the file to write to
- :type fobj: str, file or file-like object
+ :type fobj: filename (str), file or a file-like bytes-mode object
:raises: *MemoryError* if memory could not be allocated for the operation
*IOError* if an I/O error occurs while attempting to write the file
@@ -341,7 +341,7 @@ multi-page vector surface backend.
.. class:: PDFSurface(fobj, width_in_points, height_in_points)
:param fobj: a filename or writable file object. None may be used to specify no output. This will generate a *PDFSurface* that may be queried and used as a source, without generating a temporary file.
- :type fobj: None, str, file or file-like object
+ :type fobj: None, filename (str), file or a file-like bytes-mode object
:param width_in_points: width of the surface, in points
(1 point == 1/72.0 inch)
:type width_in_points: float
@@ -383,7 +383,7 @@ is a multi-page vector surface backend.
.. class:: PSSurface(fobj, width_in_points, height_in_points)
:param fobj: a filename or writable file object. None may be used to specify no output. This will generate a *PSSurface* that may be queried and used as a source, without generating a temporary file.
- :type fobj: None, str, file or file-like object
+ :type fobj: None, filename (str), file or a file-like bytes-mode object
:param width_in_points: width of the surface, in points
(1 point == 1/72.0 inch)
:type width_in_points: float
@@ -646,8 +646,10 @@ multi-page vector surface backend
.. class:: SVGSurface(fobj, width_in_points, height_in_points)
- :param fobj: a filename or writable file object. None may be used to specify no output. This will generate a *SVGSurface* that may be queried and used as a source, without generating a temporary file.
- :type fobj: None, str, file or file-like object
+ :param fobj: a filename or writable file object. None may be used to
+ specify no output. This will generate a *SVGSurface* that may be queried
+ and used as a source, without generating a temporary file.
+ :type fobj: None, filename (str), file or a file-like text-mode object
:param width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
:type width_in_points: float
:param height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
@@ -735,13 +737,14 @@ extension if it is available.
:param width: The width of the surface
:param height: The height of the surface
- Informs cairo of the new size of the X Drawable underlying the surface. For a surface created
- for a Window (rather than a Pixmap), this function must be called each time the size of the
- window changes. (For a subwindow, you are normally resizing the window yourself, but for a
- toplevel window, it is necessary to listen for ConfigureNotify events.)
+ Informs cairo of the new size of the X Drawable underlying the surface. For
+ a surface created for a Window (rather than a Pixmap), this function must
+ be called each time the size of the window changes. (For a subwindow, you
+ are normally resizing the window yourself, but for a toplevel window, it is
+ necessary to listen for ConfigureNotify events.)
- A Pixmap can never change size, so it is never necessary to call this function on a surface
- created for a Pixmap.
+ A Pixmap can never change size, so it is never necessary to call this
+ function on a surface created for a Pixmap.
class XlibSurface(:class:`Surface`)
diff --git a/setup.py b/setup.py
index 808e34a..a93a650 100755
--- a/setup.py
+++ b/setup.py
@@ -33,7 +33,12 @@ def pkg_config_version_check(pkg, version):
raise SystemExit(pipe.stderr.read().decode())
def pkg_config_parse(opt, pkg):
+ check = "pkg-config %s %s" % (opt, pkg)
pipe = call("pkg-config %s %s" % (opt, pkg))
+ if pipe.returncode != 0:
+ print(check, ' Failed')
+ raise SystemExit(pipe.stderr.read().decode())
+
output = pipe.stdout.read()
output = output.decode() # get the str
opt = opt[-2:]
diff --git a/src/surface.c b/src/surface.c
index d98c498..4701a4b 100644
--- a/src/surface.c
+++ b/src/surface.c
@@ -121,10 +121,10 @@ PycairoSurface_FromSurface (cairo_surface_t *surface, PyObject *base) {
/* for use with
* cairo_surface_write_to_png_stream()
- * cairo_pdf/ps/svg_surface_create_for_stream()
+ * cairo_pdf/ps_surface_create_for_stream()
*/
static cairo_status_t
-_write_func (void *closure, const unsigned char *data, unsigned int length) {
+_write_bytes_func (void *closure, const unsigned char *data, unsigned int length) {
PyGILState_STATE gstate = PyGILState_Ensure();
PyObject *res = PyObject_CallMethod ((PyObject *)closure, "write", "(y#)",
data, (Py_ssize_t)length);
@@ -140,6 +140,26 @@ _write_func (void *closure, const unsigned char *data, unsigned int length) {
return CAIRO_STATUS_SUCCESS;
}
+/* for use with
+ * cairo_svg_surface_create_for_stream()
+ */
+static cairo_status_t
+_write_str_func (void *closure, const unsigned char *data, unsigned int length) {
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ PyObject *res = PyObject_CallMethod ((PyObject *)closure, "write", "(s#)",
+ data, (Py_ssize_t)length);
+ if (res == NULL) {
+ /* an exception has occurred, it will be picked up later by
+ * Pycairo_Check_Status()
+ */
+ PyGILState_Release(gstate);
+ return CAIRO_STATUS_WRITE_ERROR;
+ }
+ Py_DECREF(res);
+ PyGILState_Release(gstate);
+ return CAIRO_STATUS_SUCCESS;
+}
+
static void
surface_dealloc (PycairoSurface *o) {
if (o->surface) {
@@ -307,12 +327,12 @@ surface_write_to_png (PycairoSurface *o, PyObject *args) {
Py_XDECREF(writer);
PyErr_SetString(PyExc_TypeError,
"Surface.write_to_png takes one argument which must be a filename (str), file "
-"object, or a file-like object which has a \"write\" method (like StringIO)");
+"object, or a file-like bytes-mode object which has a \"write\" method");
return NULL;
}
Py_DECREF(writer);
Py_BEGIN_ALLOW_THREADS;
- status = cairo_surface_write_to_png_stream (o->surface, _write_func,
+ status = cairo_surface_write_to_png_stream (o->surface, _write_bytes_func,
file);
Py_END_ALLOW_THREADS;
}
@@ -462,7 +482,7 @@ image_surface_create_for_data (PyTypeObject *type, PyObject *args) {
#ifdef CAIRO_HAS_PNG_FUNCTIONS
static cairo_status_t
-_read_func (void *closure, unsigned char *data, unsigned int length) {
+_read_bytes_func (void *closure, unsigned char *data, unsigned int length) {
char *buffer;
Py_ssize_t str_length;
cairo_status_t status = CAIRO_STATUS_READ_ERROR;
@@ -518,13 +538,13 @@ image_surface_create_from_png (PyTypeObject *type, PyObject *args) {
Py_XDECREF(reader);
PyErr_SetString(PyExc_TypeError,
"ImageSurface.create_from_png argument must be a filename (str), file object, "
-"or an object that has a \"read\" method (like StringIO)");
+"or a file-like bytes-mode object which has a \"read\" method");
return NULL;
}
Py_DECREF(reader);
Py_BEGIN_ALLOW_THREADS;
- is = cairo_image_surface_create_from_png_stream (_read_func, file);
+ is = cairo_image_surface_create_from_png_stream (_read_bytes_func, file);
Py_END_ALLOW_THREADS;
return PycairoSurface_FromSurface (is, NULL);
}
@@ -708,14 +728,14 @@ pdf_surface_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
" None, or\n"
" a filename (str), or\n"
" a file object, or\n"
-" an object that has a \"write\" method (like StringIO)."
+" a file-like bytes-mode object which has a \"write\" method."
);
return NULL;
}
Py_DECREF(writer);
Py_BEGIN_ALLOW_THREADS;
- sfc = cairo_pdf_surface_create_for_stream (_write_func, obj,
+ sfc = cairo_pdf_surface_create_for_stream (_write_bytes_func, obj,
width_in_points, height_in_points);
Py_END_ALLOW_THREADS;
return PycairoSurface_FromSurface (sfc, obj);
@@ -829,14 +849,14 @@ ps_surface_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
" None, or\n"
" a filename (str), or\n"
" a file object, or\n"
-" an object that has a \"write\" method (like StringIO)."
+" a file-like bytes-mode object which has a \"write\" method."
);
return NULL;
}
Py_DECREF(writer);
Py_BEGIN_ALLOW_THREADS;
- sfc = cairo_ps_surface_create_for_stream (_write_func, obj,
+ sfc = cairo_ps_surface_create_for_stream (_write_bytes_func, obj,
width_in_points, height_in_points);
Py_END_ALLOW_THREADS;
return PycairoSurface_FromSurface (sfc, obj);
@@ -1121,14 +1141,14 @@ svg_surface_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
" None, or\n"
" a filename (str), or\n"
" a file object, or\n"
-" an object that has a \"write\" method (like StringIO)."
+" a file-like text-mode object which has a \"write\" method."
);
return NULL;
}
Py_DECREF(writer);
Py_BEGIN_ALLOW_THREADS;
- sfc = cairo_svg_surface_create_for_stream (_write_func, obj,
+ sfc = cairo_svg_surface_create_for_stream (_write_str_func, obj,
width_in_points, height_in_points);
Py_END_ALLOW_THREADS;
return PycairoSurface_FromSurface (sfc, obj);
diff --git a/test/surface_create_for_stream.py b/test/surface_create_for_stream.py
index da543f2..b6ad225 100755
--- a/test/surface_create_for_stream.py
+++ b/test/surface_create_for_stream.py
@@ -3,11 +3,10 @@
Test PDF/PS/SVG constructors (using streams)
"""
-import cStringIO
import gc
import math
import sys
-import StringIO
+#import io.Bytes
import cairo
@@ -28,22 +27,27 @@ class C(object):
self.closed = True
+WIDTH, HEIGHT = 256, 256
+
# a selection of possible args to surface.write_to_png()
-#fo = '/tmp/f.ps'
-fo = file('/tmp/f.svg', 'wb')
-#fo = StringIO.StringIO()
-#fo = cStringIO.StringIO()
-#fo = sys.stdout
+fo = sys.stdout # only compatible with str/text objects - SVG
#fo = C()
-#fo.close() # this should cause: ValueError: I/O operation on closed file
-
-WIDTH, HEIGHT = 256, 256
-
+#fo = '/tmp/f.pdf'
+#fo = open('/tmp/f.pdf', 'wb')
#surface = cairo.PDFSurface(fo, WIDTH, HEIGHT)
+
+#fo = '/tmp/f.ps'
+#fo = open('/tmp/f.ps', 'wb')
#surface = cairo.PSSurface(fo, WIDTH, HEIGHT)
+
+#fo = '/tmp/f.svg'
+#fo = open('/tmp/f.svg', 'wt')
surface = cairo.SVGSurface(fo, WIDTH, HEIGHT)
+#fo.close() # this should cause: ValueError: I/O operation on closed file
+
+
#sys.stdout.write ('1\n'); sys.stdout.flush()
ctx = cairo.Context(surface)
@@ -74,7 +78,7 @@ ctx.fill()
ctx.show_page()
surface.finish()
-# for testing StringIO: get data and write to file
+# for testing io.Bytes: get data and write to file
#string = fo.getvalue()
#f2 = file('/tmp/f.ps', 'wb')
#f2.write(string)