Since version 1.11.0 Pycairo uses `Semantic Versioning
<http://semver.org/>`__ i.e. the newest version is the latest stable one.
+.. _v1.15.6:
+
+1.15.6 - 2018-01-30
+-------------------
+
+* Experimental PyPy and PyPy3 support :bug:`90`
+
+
.. _v1.15.5:
1.15.5 - 2018-01-29
Metadata-Version: 1.1
Name: pycairo
-Version: 1.15.5
+Version: 1.15.6
Summary: Python interface for cairo
Home-page: https://pycairo.readthedocs.io
Author: Christoph Reiter
PyObject *xpybVISUALTYPE_type;
#endif
-#if PY_MAJOR_VERSION < 3
-
-/* A module specific exception */
-PyObject *_CairoError = NULL;
-
-#else
-
-/* Module initialization */
-struct cairo_state {
- PyObject *ErrorObject;
-};
-
-#define GETSTATE(m) ((struct cairo_state*)PyModule_GetState(m))
-
-static struct PyModuleDef cairomoduledef;
-#endif
-
-/* Returns a borrowed reference of the error type. */
-PyObject *
-_Pycairo_Get_Error(void) {
-#if PY_MAJOR_VERSION < 3
- assert(_CairoError != NULL);
- return _CairoError;
-#else
- PyObject *cairo_module = PyState_FindModule(&cairomoduledef);
- assert(cairo_module != NULL);
- return GETSTATE(cairo_module)->ErrorObject;
-#endif
-}
-
/* C API. Clients get at this via Pycairo_IMPORT or import_cairo(), defined in pycairo.h.
*/
static Pycairo_CAPI_t CAPI = {
#if PY_MAJOR_VERSION >= 3
-static int
-cairo_traverse(PyObject *m, visitproc visit, void *arg)
-{
- Py_VISIT(GETSTATE(m)->ErrorObject);
- return 0;
-}
-
-static int
-cairo_clear(PyObject *m)
-{
- Py_CLEAR(GETSTATE(m)->ErrorObject);
- return 0;
-}
-
static struct PyModuleDef cairomoduledef = {
PyModuleDef_HEAD_INIT,
"cairo",
NULL,
- sizeof(struct cairo_state),
+ 0,
cairo_functions,
- 0, /* m_reload */
- cairo_traverse,
- cairo_clear,
- 0, /* m_free - not needed, since all is done in m_clear */
+ 0,
+ 0,
+ 0,
+ 0,
};
#endif
PYCAIRO_MOD_INIT(_cairo)
{
- PyObject *m, *capi, *error;
+ PyObject *m, *capi;
if (PyType_Ready(&PycairoContext_Type) < 0)
return PYCAIRO_MOD_ERROR_VAL;
if (m == NULL)
return PYCAIRO_MOD_ERROR_VAL;
+ if(init_error(m) < 0)
+ return PYCAIRO_MOD_ERROR_VAL;
+
if(init_buffer_proxy() < 0)
return PYCAIRO_MOD_ERROR_VAL;
(PyObject *)&PycairoTeeSurface_Type);
#endif
- /* Add 'cairo.Error' to the module */
- error = error_get_type();
- if (error == NULL)
- return PYCAIRO_MOD_ERROR_VAL;
-
-#if PY_MAJOR_VERSION >= 3
- GETSTATE(m)->ErrorObject = error;
-#else
- _CairoError = error;
-#endif
-
- Py_INCREF(error);
- if (PyModule_AddObject(m, "Error", error) < 0)
- return PYCAIRO_MOD_ERROR_VAL;
-
- /* Alias for cairocffi */
- Py_INCREF(error);
- if (PyModule_AddObject(m, "CairoError", error) < 0)
- return PYCAIRO_MOD_ERROR_VAL;
-
/* constants */
#ifdef CAIRO_HAS_ATSUI_FONT
PyModule_AddIntConstant(m, "HAS_ATSUI_FONT", 1);
int
Pycairo_Check_Status (cairo_status_t status) {
- PyObject *suberror;
+ PyObject *module, *error, *suberror;
if (PyErr_Occurred() != NULL)
return 1;
+ if (status == CAIRO_STATUS_SUCCESS)
+ return 0;
+
+ module = PyImport_ImportModule ("cairo");
+ if (module == NULL)
+ return 1;
+ error = PyObject_GetAttrString (module, "Error");
+ Py_DECREF (module);
+ if (error == NULL)
+ return 1;
+
switch (status) {
- case CAIRO_STATUS_SUCCESS:
- return 0;
case CAIRO_STATUS_NO_MEMORY:
suberror = error_get_type_combined (
- _Pycairo_Get_Error(), PyExc_MemoryError, "cairo.MemoryError");
+ error, PyExc_MemoryError, "cairo.MemoryError");
set_error (suberror, status);
Py_DECREF (suberror);
break;
case CAIRO_STATUS_READ_ERROR:
case CAIRO_STATUS_WRITE_ERROR:
suberror = error_get_type_combined (
- _Pycairo_Get_Error(), PyExc_IOError, "cairo.IOError");
+ error, PyExc_IOError, "cairo.IOError");
set_error (suberror, status);
Py_DECREF (suberror);
break;
default:
- set_error (_Pycairo_Get_Error(), status);
+ set_error (error, status);
}
+ Py_DECREF (error);
+
return 1;
}
PyBaseExceptionObject base;
} PycairoErrorObject;
+static PyObject *
+error_get_args(PycairoErrorObject *self) {
+ PyObject *args;
+
+ args = PyObject_GetAttrString((PyObject *)self, "args");
+ if (args == NULL)
+ return NULL;
+
+ if (!PyTuple_Check(args)) {
+ PyErr_SetString(PyExc_TypeError, ".args not a tuple");
+ Py_DECREF(args);
+ return NULL;
+ }
+
+ return args;
+}
+
static int
error_init(PycairoErrorObject *self, PyObject *args, PyObject *kwds)
{
- PyObject *status_obj;
+ PyObject *status_obj, *error_args;
if (PycairoError_Type.tp_base->tp_init((PyObject *)self, args, kwds) < 0)
return -1;
- if(PyTuple_GET_SIZE(self->base.args) >= 2) {
- status_obj = PyTuple_GET_ITEM(self->base.args, 1);
+ error_args = error_get_args(self);
+ if (error_args == NULL)
+ return -1;
+
+ if(PyTuple_GET_SIZE(error_args) >= 2) {
+ status_obj = PyTuple_GET_ITEM(error_args, 1);
} else {
status_obj = Py_None;
}
+ Py_DECREF(error_args);
+
if (PyObject_SetAttrString ((PyObject *)self, "__status", status_obj) < 0)
return -1;
static PyObject *
error_str(PycairoErrorObject *self)
{
+ PyObject *result, *error_args;
+
+ error_args = error_get_args(self);
+ if (error_args == NULL)
+ return NULL;
+
/* Default to printing just the message */
- if (PyTuple_GET_SIZE(self->base.args) >= 1) {
- return PyObject_Str(PyTuple_GET_ITEM(self->base.args, 0));
+ if (PyTuple_GET_SIZE(error_args) >= 1) {
+ result = PyObject_Str(PyTuple_GET_ITEM(error_args, 0));
} else {
- return PycairoError_Type.tp_base->tp_str((PyObject*)self);
+ result = PycairoError_Type.tp_base->tp_str((PyObject*)self);
}
+
+ Py_DECREF(error_args);
+ return result;
}
static PyObject *
0, /* tp_new */
};
-/* Returns a new reference of the error type or NULL on error and sets
- * an exception.
- */
-PyObject *
-error_get_type(void) {
+int
+init_error (PyObject *module) {
+ PyObject *error;
+
PycairoError_Type.tp_base = (PyTypeObject*)PyExc_Exception;
if (PyType_Ready(&PycairoError_Type) < 0)
- return NULL;
- Py_INCREF(&PycairoError_Type);
- return (PyObject*)&PycairoError_Type;
+ return -1;
+
+ error = (PyObject*)&PycairoError_Type;
+
+ Py_INCREF(error);
+ if (PyModule_AddObject(module, "Error", error) < 0) {
+ Py_DECREF (error);
+ return -1;
+ }
+
+ Py_INCREF(error);
+ if (PyModule_AddObject(module, "CairoError", error) < 0) {
+ Py_DECREF (error);
+ return -1;
+ }
+
+ return 0;
}
static PyObject *
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
- 0, /* tp_hash */
+ (hashfunc)PyObject_HashNotImplemented,/* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
#define PYCAIRO_STRINGIFY(s) PYCAIRO_STRINGIFY_ARG(s)
#define PYCAIRO_STRINGIFY_ARG(s) #s
+int init_error(PyObject *module);
+
int Pycairo_fspath_converter (PyObject *obj, char** result);
int Pycairo_fspath_none_converter (PyObject *obj, char** result);
int Pycairo_writer_converter (PyObject *obj, PyObject** file);
int _conv_pyobject_to_ulong (PyObject *pyobj, unsigned long *result);
-PyObject *_Pycairo_Get_Error(void);
-
PyObject* Pycairo_richcompare (void* a, void *b, int op);
PyObject* Pycairo_tuple_getattro (PyObject *self, char **kwds, PyObject *name);
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
- 0, /* tp_hash */
+ (hashfunc)PyObject_HashNotImplemented,/* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
- 0, /* tp_hash */
+ (hashfunc)PyObject_HashNotImplemented,/* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
from distutils.ccompiler import new_compiler
-PYCAIRO_VERSION = '1.15.5'
+PYCAIRO_VERSION = '1.15.6'
CAIRO_VERSION_REQUIRED = '1.13.1'
XPYB_VERSION_REQUIRED = '1.3'
assert cairo.SVG_VERSION_1_2 == 1
+@pytest.mark.skipif(not hasattr(sys, "getrefcount"), reason="PyPy")
def test_surface_get_set_mime_data_references():
surface = cairo.ImageSurface(cairo.FORMAT_RGB24, 1, 1)
if sys.version_info[0] == 2:
import cairo
import pytest
import ctypes
+import platform
@pytest.fixture
assert context.get_operator() == val
+@pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="PyPy")
def test_show_text_glyphs():
surface = cairo.PDFSurface(None, 300, 300)
context = cairo.Context(surface)
context.scale(object(), 0)
+@pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="PyPy")
def test_select_font_face(context):
context.select_font_face("")
with pytest.raises(TypeError):
context.text_extents()
+@pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="PyPy")
def test_text_path(context):
context.text_path("foo")
with pytest.raises(TypeError):
import pickle
import re
+import platform
import pytest
import cairo
+@pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="PyPy")
def test_type():
t = cairo.Antialias
assert int in t.__mro__
err.status = cairo.Status.DEVICE_FINISHED
assert err.status == cairo.Status.DEVICE_FINISHED
- with pytest.raises(TypeError):
+ with pytest.raises((TypeError, AttributeError)):
del err.status
str(cairo.Error())
import sys
+import platform
import cairo
import pytest
assert isinstance(scaled_font.get_scale_matrix(), cairo.Matrix)
+@pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="PyPy")
def test_scaled_font_text_extents(scaled_font):
with pytest.raises(TypeError):
scaled_font.text_extents(object())
scaled_font.glyph_extents()
+@pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="PyPy")
def test_toy_font_face():
with pytest.raises(TypeError):
cairo.ToyFontFace(object())
import sys
import tempfile
import shutil
+import platform
import pytest
import cairo
return tuple(map(int, cairo.cairo_version_string().split(".")))
+@pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="PyPy")
@given(path=fspaths())
@settings(max_examples=500)
def test_fspaths(tempdir_path, path):
import tempfile
import struct
import sysconfig
+import platform
import cairo
import pytest
tee.remove(s1)
+@pytest.mark.skipif(not hasattr(sys, "getrefcount"), reason="PyPy")
def test_image_surface_get_data_refcount():
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
assert sys.getrefcount(surface) == 2
surface.supports_mime_type(object())
+@pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="PyPy")
def test_image_surface_create_for_data_array():
width, height = 255, 255
data = array.array('B', [0] * width * height * 4)