include setup.cfg
recursive-include docs *.py Makefile *.rst *.css *.svg
prune docs/_build
-recursive-include tests *.py README
+recursive-include tests *.py README *.c *.h
recursive-include examples *.py README
include cairo/*.h
Since version 1.11.0 Pycairo uses `Semantic Versioning
<http://semver.org/>`__ i.e. the newest version is the latest stable one.
+.. _v1.17.0:
+
+1.17.0 - 2018-04-15
+-------------------
+
+* :class:`cairo.Surface` and :class:`cairo.Device` can now be used as context
+ managers. :bug:`103`
+* Fix a leak when a cairo error was raised.
+* Fix a leak when a mapped surface was GCed instead of unmapped.
+* Make it possible to use the C API with Python 3 outside of the compilation
+ unit doing the import by defining ``PYCAIRO_NO_IMPORT``. :bug:`110`
+* Implement PEP 561 (added a py.typed marker)
+
+
.. _v1.16.3:
1.16.3 - 2018-02-27
-Metadata-Version: 1.1
+Metadata-Version: 1.2
Name: pycairo
-Version: 1.16.3
+Version: 1.17.0
Summary: Python interface for cairo
Home-page: https://pycairo.readthedocs.io
-Author: Christoph Reiter
-Author-email: reiter.christoph@gmail.com
+Maintainer: Christoph Reiter
+Maintainer-email: reiter.christoph@gmail.com
License: UNKNOWN
Description: .. image:: https://cdn.rawgit.com/pygobject/pycairo/master/docs/images/pycairo.svg
:align: center
import cairo
- surface = cairo.SVGSurface("example.svg", 200, 200)
- context = cairo.Context(surface)
- x, y, x1, y1 = 0.1, 0.5, 0.4, 0.9
- x2, y2, x3, y3 = 0.6, 0.1, 0.9, 0.5
- context.scale(200, 200)
- context.set_line_width(0.04)
- context.move_to(x, y)
- context.curve_to(x1, y1, x2, y2, x3, y3)
- context.stroke()
- context.set_source_rgba(1, 0.2, 0.2, 0.6)
- context.set_line_width(0.02)
- context.move_to(x, y)
- context.line_to(x1, y1)
- context.move_to(x2, y2)
- context.line_to(x3, y3)
- context.stroke()
- surface.finish()
+ with cairo.SVGSurface("example.svg", 200, 200) as surface:
+ context = cairo.Context(surface)
+ x, y, x1, y1 = 0.1, 0.5, 0.4, 0.9
+ x2, y2, x3, y3 = 0.6, 0.1, 0.9, 0.5
+ context.scale(200, 200)
+ context.set_line_width(0.04)
+ context.move_to(x, y)
+ context.curve_to(x1, y1, x2, y2, x3, y3)
+ context.stroke()
+ context.set_source_rgba(1, 0.2, 0.2, 0.6)
+ context.set_line_width(0.02)
+ context.move_to(x, y)
+ context.line_to(x1, y1)
+ context.move_to(x2, y2)
+ context.line_to(x3, y3)
+ context.stroke()
----
import cairo
- surface = cairo.SVGSurface("example.svg", 200, 200)
- context = cairo.Context(surface)
- x, y, x1, y1 = 0.1, 0.5, 0.4, 0.9
- x2, y2, x3, y3 = 0.6, 0.1, 0.9, 0.5
- context.scale(200, 200)
- context.set_line_width(0.04)
- context.move_to(x, y)
- context.curve_to(x1, y1, x2, y2, x3, y3)
- context.stroke()
- context.set_source_rgba(1, 0.2, 0.2, 0.6)
- context.set_line_width(0.02)
- context.move_to(x, y)
- context.line_to(x1, y1)
- context.move_to(x2, y2)
- context.line_to(x3, y3)
- context.stroke()
- surface.finish()
+ with cairo.SVGSurface("example.svg", 200, 200) as surface:
+ context = cairo.Context(surface)
+ x, y, x1, y1 = 0.1, 0.5, 0.4, 0.9
+ x2, y2, x3, y3 = 0.6, 0.1, 0.9, 0.5
+ context.scale(200, 200)
+ context.set_line_width(0.04)
+ context.move_to(x, y)
+ context.curve_to(x1, y1, x2, y2, x3, y3)
+ context.stroke()
+ context.set_source_rgba(1, 0.2, 0.2, 0.6)
+ context.set_line_width(0.02)
+ context.move_to(x, y)
+ context.line_to(x1, y1)
+ context.move_to(x2, y2)
+ context.line_to(x3, y3)
+ context.stroke()
----
@classmethod
def create_for_target(cls, script: ScriptDevice, target: Surface) -> "ScriptSurface": ...
+class Win32Surface(Surface):
+ def __init__(self, hdc: int) -> None: ...
+
+class Win32PrintingSurface(Surface):
+ def __init__(self, hdc: int) -> None: ...
+
class SolidPattern(Pattern):
def __init__(self, red: float, green: float, blue: float, alpha: float=1.0) -> None: ...
def get_rgba(self) -> Tuple[float, float, float, float]: ...
PyObject_HEAD_INIT(type) size,
#endif
+#ifdef __GNUC__
+#define PYCAIRO_MODINIT_FUNC __attribute__((visibility("default"))) PyMODINIT_FUNC
+#else
+#define PYCAIRO_MODINIT_FUNC PyMODINIT_FUNC
+#endif
+
#if PY_MAJOR_VERSION < 3
#define PYCAIRO_MOD_ERROR_VAL
#define PYCAIRO_MOD_SUCCESS_VAL(val)
-#define PYCAIRO_MOD_INIT(name) void init##name(void)
+#define PYCAIRO_MOD_INIT(name) PYCAIRO_MODINIT_FUNC init##name(void)
#define PYCAIRO_PyUnicode_FromString PyString_FromString
#define PYCAIRO_PyUnicode_Format PyString_Format
#define PYCAIRO_MOD_ERROR_VAL NULL
#define PYCAIRO_MOD_SUCCESS_VAL(val) val
-#define PYCAIRO_MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
+#define PYCAIRO_MOD_INIT(name) PYCAIRO_MODINIT_FUNC PyInit_##name(void)
#define PYCAIRO_PyUnicode_FromString PyUnicode_FromString
#define PYCAIRO_PyUnicode_Format PyUnicode_Format
Py_RETURN_NONE;
}
+static PyObject *
+device_ctx_enter (PyObject *obj) {
+ Py_INCREF (obj);
+ return obj;
+}
+
+static PyObject *
+device_ctx_exit (PycairoDevice *obj, PyObject *args) {
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_device_finish (obj->device);
+ Py_END_ALLOW_THREADS;
+ Py_RETURN_NONE;
+}
+
static PyMethodDef device_methods[] = {
+ {"__enter__", (PyCFunction)device_ctx_enter, METH_NOARGS},
+ {"__exit__", (PyCFunction)device_ctx_exit, METH_VARARGS},
{"finish", (PyCFunction)device_finish, METH_NOARGS},
{"flush", (PyCFunction)device_flush, METH_NOARGS},
{"acquire", (PyCFunction)device_acquire, METH_NOARGS},
static void
set_error (PyObject *error_type, cairo_status_t status)
{
- PyObject *args, *v;
+ PyObject *args, *v, *int_enum;
- args = Py_BuildValue("(sO)", status_to_string(status),
- CREATE_INT_ENUM(Status, status));
+ int_enum = CREATE_INT_ENUM(Status, status);
+ if (int_enum == NULL)
+ return;
+ args = Py_BuildValue("(sO)", status_to_string(status), int_enum);
+ Py_DECREF (int_enum);
v = PyObject_Call(error_type, args, NULL);
Py_DECREF(args);
if (v != NULL) {
#else
+#ifdef PYCAIRO_NO_IMPORT
+
+extern Pycairo_CAPI_t *Pycairo_CAPI;
+
+#else
+
/* To access the Pycairo C API, the client module should call 'import_cairo()'
* from the init<module> function, and check the return value, < 0 means the
* import failed.
*/
-static Pycairo_CAPI_t *Pycairo_CAPI;
+Pycairo_CAPI_t *Pycairo_CAPI;
/* Return -1 on error, 0 on success.
* PyCapsule_Import will set an exception if there's an error.
#endif
+#endif
+
#endif /* ifndef _INSIDE_PYCAIRO_ */
#endif /* ifndef _PYCAIRO_H_ */
/* Replace the mapped image surface with a fake one and finish it so
* that any operation on it fails.
*/
- fake_surface = cairo_image_surface_create (CAIRO_FORMAT_INVALID, 0, 0);
+ fake_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
cairo_surface_finish (fake_surface);
pymapped->surface = fake_surface;
/* We no longer need the base surface */
#endif /* CAIRO_HAS_IMAGE_SURFACE */
+static PyObject *
+surface_ctx_enter (PyObject *obj) {
+ Py_INCREF (obj);
+ return obj;
+}
+
+static PyObject *
+surface_ctx_exit (PycairoSurface *obj, PyObject *args) {
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_surface_finish (obj->surface);
+ Py_END_ALLOW_THREADS;
+ Py_RETURN_NONE;
+}
+
static PyMethodDef surface_methods[] = {
/* methods never exposed in a language binding:
* cairo_surface_destroy()
* cairo_surface_reference()
* cairo_surface_set_user_data()
*/
+ {"__enter__", (PyCFunction)surface_ctx_enter, METH_NOARGS},
+ {"__exit__", (PyCFunction)surface_ctx_exit, METH_VARARGS},
{"copy_page", (PyCFunction)surface_copy_page, METH_NOARGS},
{"create_similar", (PyCFunction)surface_create_similar, METH_VARARGS},
{"create_similar_image", (PyCFunction)surface_create_similar_image,
if (cairo_surface_get_user_data (
self->surface, &surface_is_mapped_image) != NULL) {
cairo_surface_unmap_image (pybasesurface->surface, self->surface);
+ self->surface = NULL;
+ } else {
+ cairo_surface_destroy(self->surface);
+ self->surface = NULL;
}
+ Py_CLEAR (self->base);
Py_TYPE (self)->tp_free (self);
}
return NULL;
}
+static PyObject *
+mapped_image_surface_ctx_exit (PycairoImageSurface *self, PyObject *args) {
+ PycairoSurface *pybasesurface = (PycairoSurface *)(self->base);
+ PyObject *subargs, *result;
+
+ subargs = Py_BuildValue("(O)", self);
+ if (subargs == NULL)
+ return NULL;
+ result = surface_unmap_image (pybasesurface, subargs);
+ Py_DECREF (subargs);
+ return result;
+}
+
static PyMethodDef mapped_image_surface_methods[] = {
+ {"__exit__", (PyCFunction)mapped_image_surface_ctx_exit, METH_VARARGS},
{"finish", (PyCFunction)mapped_image_surface_finish, METH_NOARGS},
{NULL, NULL, 0, NULL},
};
#include "pycairo.h"
/* define a variable for the C API */
- static Pycairo_CAPI_t *Pycairo_CAPI;
+ Pycairo_CAPI_t *Pycairo_CAPI;
/* import pycairo - add to the init<module> function */
Pycairo_IMPORT;
+In case you want to use the API from another compilation unit::
+
+ #include <pycairo.h>
+
+ extern Pycairo_CAPI_t *Pycairo_CAPI;
+
+ ...
To access the Pycairo C API under Python 3
==========================================
return m;
}
+In case you want to use the API from another compilation unit::
+
+ #define PYCAIRO_NO_IMPORT
+ #include <py3cairo.h>
+
+ ...
+
+.. versionadded:: 1.17.0
+
+ The ``PYCAIRO_NO_IMPORT`` macro is used since 1.17.0
+
Misc Functions
==============
.. versionadded:: 1.14
+ .. note::
+
+ .. versionadded:: 1.17.0
+
+ :class:`cairo.Device` can be used as a context manager:
+
+ .. code:: python
+
+ # device.finish() will be called on __exit__
+ with cairo.ScriptDevice(f) as device:
+ pass
+
.. method:: finish()
This function finishes the device and drops all references to external
*Surface* is the abstract base class from which all the other surface
classes derive. It cannot be instantiated directly.
+ .. note::
+
+ .. versionadded:: 1.17.0
+
+ :class:`cairo.Surface` can be used as a context manager:
+
+ .. code:: python
+
+ # surface.finish() will be called on __exit__
+ with cairo.SVGSurface("example.svg", 200, 200) as surface:
+ pass
+
+ # surface.unmap_image(image_surface) will be called on __exit__
+ with surface.map_to_image(None) as image_surface:
+ pass
+
.. method:: copy_page()
Emits the current page for backends that support multiple pages, but
--- /dev/null
+Metadata-Version: 1.2
+Name: pycairo
+Version: 1.17.0
+Summary: Python interface for cairo
+Home-page: https://pycairo.readthedocs.io
+Maintainer: Christoph Reiter
+Maintainer-email: reiter.christoph@gmail.com
+License: UNKNOWN
+Description: .. image:: https://cdn.rawgit.com/pygobject/pycairo/master/docs/images/pycairo.svg
+ :align: center
+ :width: 370px
+
+ |
+
+ Pycairo is a Python module providing bindings for the `cairo graphics library
+ <https://cairographics.org/>`__. It depends on **cairo >= 1.13.1** and
+ works with **Python 2.7+** as well as **Python 3.3+**. Pycairo, including this
+ documentation, is licensed under the **LGPLv2.1** as well as the **MPLv1.1**.
+
+ The Pycairo bindings are designed to match the cairo C API as closely as
+ possible, and to deviate only in cases which are clearly better implemented in
+ a more ‘Pythonic’ way.
+
+ Features of the Pycairo bindings:
+
+ * Provides an object oriented interface to cairo.
+ * Queries the error status of objects and translates them to exceptions.
+ * Provides a C API that can be used by other Python extensions.
+
+ ----
+
+ .. image:: https://cdn.rawgit.com/pygobject/pycairo/master/docs/images/example.svg
+ :align: right
+ :width: 200px
+
+ .. code:: python
+
+ import cairo
+
+ with cairo.SVGSurface("example.svg", 200, 200) as surface:
+ context = cairo.Context(surface)
+ x, y, x1, y1 = 0.1, 0.5, 0.4, 0.9
+ x2, y2, x3, y3 = 0.6, 0.1, 0.9, 0.5
+ context.scale(200, 200)
+ context.set_line_width(0.04)
+ context.move_to(x, y)
+ context.curve_to(x1, y1, x2, y2, x3, y3)
+ context.stroke()
+ context.set_source_rgba(1, 0.2, 0.2, 0.6)
+ context.set_line_width(0.02)
+ context.move_to(x, y)
+ context.line_to(x1, y1)
+ context.move_to(x2, y2)
+ context.line_to(x3, y3)
+ context.stroke()
+
+ ----
+
+ If Pycairo is not what you need, have a look at `cairocffi
+ <https://cairocffi.readthedocs.io>`__, which is an API compatible package
+ using `cffi <https://cffi.readthedocs.io/>`__ or `Qahirah
+ <https://github.com/ldo/qahirah>`__, which is using `ctypes
+ <https://docs.python.org/3/library/ctypes.html>`__ and provides a more
+ "pythonic" API with less focus on matching the cairo C API.
+
+ For more information visit https://pycairo.readthedocs.io
+
+ .. image:: https://travis-ci.org/pygobject/pycairo.svg?branch=master
+ :target: https://travis-ci.org/pygobject/pycairo
+
+ .. image:: https://ci.appveyor.com/api/projects/status/9hurdbb19lg2i9xm/branch/master?svg=true
+ :target: https://ci.appveyor.com/project/lazka/pycairo/branch/master
+
+ .. image:: https://codecov.io/gh/pygobject/pycairo/branch/master/graph/badge.svg
+ :target: https://codecov.io/gh/pygobject/pycairo
+
+Platform: UNKNOWN
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: License :: OSI Approved :: GNU Lesser General Public License v2 (LGPLv2)
+Classifier: License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1)
--- /dev/null
+COPYING
+COPYING-LGPL-2.1
+COPYING-MPL-1.1
+MANIFEST.in
+NEWS
+README.rst
+setup.cfg
+setup.py
+cairo/__init__.py
+cairo/__init__.pyi
+cairo/bufferproxy.c
+cairo/cairomodule.c
+cairo/compat.h
+cairo/context.c
+cairo/device.c
+cairo/enums.c
+cairo/error.c
+cairo/font.c
+cairo/glyph.c
+cairo/matrix.c
+cairo/misc.c
+cairo/path.c
+cairo/pattern.c
+cairo/private.h
+cairo/py.typed
+cairo/pycairo.h
+cairo/rectangle.c
+cairo/region.c
+cairo/surface.c
+cairo/textcluster.c
+cairo/textextents.c
+docs/Makefile
+docs/changelog.rst
+docs/conf.py
+docs/examples.rst
+docs/extra.css
+docs/faq.rst
+docs/index.rst
+docs/integration.rst
+docs/pycairo_c_api.rst
+docs/resources.rst
+docs/tutorial.rst
+docs/images/example.svg
+docs/images/pycairo.svg
+docs/reference/constants.rst
+docs/reference/context.rst
+docs/reference/devices.rst
+docs/reference/enums.rst
+docs/reference/exceptions.rst
+docs/reference/glyph.rst
+docs/reference/index.rst
+docs/reference/legacy_constants.rst
+docs/reference/matrix.rst
+docs/reference/paths.rst
+docs/reference/patterns.rst
+docs/reference/rectangle.rst
+docs/reference/region.rst
+docs/reference/surfaces.rst
+docs/reference/text.rst
+docs/reference/textcluster.rst
+docs/reference/textextents.rst
+examples/pygame-demo.py
+examples/cairo_snippets/snippets_gtk.py
+examples/cairo_snippets/snippets_pdf.py
+examples/cairo_snippets/snippets_png.py
+examples/cairo_snippets/snippets_ps.py
+examples/cairo_snippets/snippets_svg.py
+examples/cairo_snippets/snippets/__init__.py
+examples/cairo_snippets/snippets/arc.py
+examples/cairo_snippets/snippets/arc_negative.py
+examples/cairo_snippets/snippets/clip.py
+examples/cairo_snippets/snippets/curve_rectangle.py
+examples/cairo_snippets/snippets/curve_to.py
+examples/cairo_snippets/snippets/ellipse.py
+examples/cairo_snippets/snippets/fill_and_stroke.py
+examples/cairo_snippets/snippets/fill_and_stroke2.py
+examples/cairo_snippets/snippets/glyph_path.py
+examples/cairo_snippets/snippets/gradient.py
+examples/cairo_snippets/snippets/gradient_mask.py
+examples/cairo_snippets/snippets/group.py
+examples/cairo_snippets/snippets/hering.py
+examples/cairo_snippets/snippets/path.py
+examples/cairo_snippets/snippets/set_line_cap.py
+examples/cairo_snippets/snippets/set_line_join.py
+examples/cairo_snippets/snippets/show_glyphs.py
+examples/cairo_snippets/snippets/spiral.py
+examples/cairo_snippets/snippets/text.py
+examples/cairo_snippets/snippets/text_align_center.py
+examples/cairo_snippets/snippets/text_extents.py
+examples/cairo_snippets/snippets/warpedtext.py
+examples/gtk/cairo-demo.py
+examples/gtk/cairo-knockout.py
+examples/gtk/png_view.py
+examples/gtk/text.py
+pycairo.egg-info/PKG-INFO
+pycairo.egg-info/SOURCES.txt
+pycairo.egg-info/dependency_links.txt
+pycairo.egg-info/top_level.txt
+tests/__init__.py
+tests/hypothesis_fspaths.py
+tests/test_api.py
+tests/test_cmod.py
+tests/test_context.py
+tests/test_device.py
+tests/test_enums.py
+tests/test_error.py
+tests/test_font.py
+tests/test_glyph.py
+tests/test_hypothesis.py
+tests/test_matrix.py
+tests/test_path.py
+tests/test_pattern.py
+tests/test_rectangle.py
+tests/test_region.py
+tests/test_surface.py
+tests/test_surface_numpy.py
+tests/test_surface_pygame.py
+tests/test_textcluster.py
+tests/test_textextents.py
+tests/test_typing.py
+tests/cmodule/cmodule.c
+tests/cmodule/cmodulelib.c
+tests/cmodule/cmodulelib.h
\ No newline at end of file
[flake8]
-ignore=E402,E741
-builtins=buffer,unichr
+ignore = E402,E741
+builtins = buffer,unichr
[coverage:run]
-include=
- cairo/*
- tests/*
+include =
+ cairo/*
+ tests/*
[mypy-setup]
ignore_errors = True
no_implicit_optional = True
disallow_any_decorated = True
disallow_any_explicit = False
+strict_optional = True
+
+[egg_info]
+tag_build =
+tag_date = 0
+
import os
import errno
-if os.environ.get("PYCAIRO_SETUPTOOLS"):
- # for testing
- import setuptools
- setuptools
+try:
+ from setuptools import setup
+except ImportError:
+ from distutils.core import setup
-from distutils.core import Extension, setup, Command, Distribution
+from distutils.core import Extension, Command, Distribution
from distutils.ccompiler import new_compiler
+from distutils.sysconfig import customize_compiler
from distutils import log
from distutils import sysconfig
-PYCAIRO_VERSION = '1.16.3'
+PYCAIRO_VERSION = '1.17.0'
CAIRO_VERSION_REQUIRED = '1.13.1'
XPYB_VERSION_REQUIRED = '1.3'
return [x.lstrip(opt) for x in output.split()]
+def filter_compiler_arguments(compiler, args):
+ """Given a compiler instance and a list of compiler warning flags
+ returns the list of supported flags.
+ """
+
+ if compiler.compiler_type == "msvc":
+ # TODO
+ return []
+
+ extra = []
+
+ def check_arguments(compiler, args):
+ p = subprocess.Popen(
+ [compiler.compiler[0]] + args + extra + ["-x", "c", "-E", "-"],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ stdout, stderr = p.communicate(b"int i;\n")
+ if p.returncode != 0:
+ text = stderr.decode("ascii", "replace")
+ return False, [a for a in args if a in text]
+ else:
+ return True, []
+
+ def check_argument(compiler, arg):
+ return check_arguments(compiler, [arg])[0]
+
+ # clang doesn't error out for unknown options, force it to
+ if check_argument(compiler, '-Werror=unknown-warning-option'):
+ extra += ['-Werror=unknown-warning-option']
+ if check_argument(compiler, '-Werror=unused-command-line-argument'):
+ extra += ['-Werror=unused-command-line-argument']
+
+ # first try to remove all arguments contained in the error message
+ supported = list(args)
+ while 1:
+ ok, maybe_unknown = check_arguments(compiler, supported)
+ if ok:
+ return supported
+ elif not maybe_unknown:
+ break
+ for unknown in maybe_unknown:
+ if not check_argument(compiler, unknown):
+ supported.remove(unknown)
+
+ # hm, didn't work, try each argument one by one
+ supported = []
+ for arg in args:
+ if check_argument(compiler, arg):
+ supported.append(arg)
+ return supported
+
+
+def add_ext_cflags(ext, compiler):
+ args = [
+ "-Wall",
+ "-Warray-bounds",
+ "-Wcast-align",
+ "-Wconversion",
+ "-Wdeclaration-after-statement",
+ "-Wextra",
+ "-Wformat=2",
+ "-Wformat-nonliteral",
+ "-Wformat-security",
+ "-Wimplicit-function-declaration",
+ "-Winit-self",
+ "-Winline",
+ "-Wmissing-format-attribute",
+ "-Wmissing-noreturn",
+ "-Wnested-externs",
+ "-Wold-style-definition",
+ "-Wpacked",
+ "-Wpointer-arith",
+ "-Wreturn-type",
+ "-Wshadow",
+ "-Wsign-compare",
+ "-Wstrict-aliasing",
+ "-Wundef",
+ "-Wunused-but-set-variable",
+ ]
+
+ if sys.version_info[:2] not in [(3, 3), (3, 4)]:
+ args += [
+ "-Wswitch-default",
+ ]
+
+ args += [
+ "-Wno-missing-field-initializers",
+ "-Wno-unused-parameter",
+ ]
+
+ # silence clang for unused gcc CFLAGS added by Debian
+ args += [
+ "-Wno-unused-command-line-argument",
+ ]
+
+ args += [
+ "-fno-strict-aliasing",
+ "-fvisibility=hidden",
+ ]
+
+ ext.extra_compile_args += filter_compiler_arguments(compiler, args)
+
+
+class build_tests(Command):
+ description = "build test libraries and extensions"
+ user_options = [
+ ("force", "f", "force a rebuild"),
+ ("enable-xpyb", None, "Build with xpyb support (default=disabled)"),
+ ]
+
+ def initialize_options(self):
+ self.force = False
+ self.build_base = None
+ self.enable_xpyb = False
+
+ def finalize_options(self):
+ self.set_undefined_options(
+ 'build',
+ ('build_base', 'build_base'))
+ self.enable_xpyb = bool(self.enable_xpyb)
+ self.force = bool(self.force)
+
+ def run(self):
+ cmd = self.reinitialize_command("build_ext")
+ cmd.inplace = True
+ cmd.enable_xpyb = self.enable_xpyb
+ cmd.force = self.force
+ cmd.ensure_finalized()
+ cmd.run()
+
+ import cairo
+
+ tests_dir = os.path.join("tests", "cmodule")
+
+ ext = Extension(
+ name='tests.cmod',
+ sources=[
+ os.path.join(tests_dir, "cmodule.c"),
+ os.path.join(tests_dir, "cmodulelib.c"),
+ ],
+ include_dirs=[
+ tests_dir,
+ cairo.get_include(),
+ ],
+ depends=[
+ os.path.join(tests_dir, "cmodulelib.h"),
+ os.path.join(cairo.get_include(), "pycairo.h"),
+ ],
+ define_macros=[("PY_SSIZE_T_CLEAN", None)],
+ )
+
+ compiler = new_compiler()
+ customize_compiler(compiler)
+
+ add_ext_cflags(ext, compiler)
+
+ if compiler.compiler_type == "msvc":
+ ext.libraries += ['cairo']
+ else:
+ pkg_config_version_check('cairo', CAIRO_VERSION_REQUIRED)
+ ext.include_dirs += pkg_config_parse('--cflags-only-I', 'cairo')
+ ext.library_dirs += pkg_config_parse('--libs-only-L', 'cairo')
+ ext.libraries += pkg_config_parse('--libs-only-l', 'cairo')
+
+ dist = Distribution({"ext_modules": [ext]})
+
+ build_cmd = dist.get_command_obj("build")
+ build_cmd.build_base = os.path.join(self.build_base, "pycairo_tests")
+ build_cmd.ensure_finalized()
+
+ cmd = dist.get_command_obj("build_ext")
+ cmd.inplace = True
+ cmd.force = self.force
+ cmd.ensure_finalized()
+ cmd.run()
+
+
class test_cmd(Command):
description = "run tests"
user_options = [
self.enable_xpyb = None
def finalize_options(self):
- pass
+ self.enable_xpyb = bool(self.enable_xpyb)
def run(self):
import pytest
# ensure the C extension is build inplace
- cmd = self.reinitialize_command("build_ext")
- if self.enable_xpyb is not None:
- cmd.enable_xpyb = self.enable_xpyb
- cmd.inplace = True
+ cmd = self.reinitialize_command("build_tests")
+ cmd.enable_xpyb = self.enable_xpyb
cmd.ensure_finalized()
cmd.run()
ext.include_dirs += pkg_config_parse('--cflags-only-I', 'cairo')
ext.library_dirs += pkg_config_parse('--libs-only-L', 'cairo')
ext.libraries += pkg_config_parse('--libs-only-l', 'cairo')
- if sys.version_info[0] == 2:
- # Some python setups don't pass -fno-strict-aliasing,
- # while MACROS like Py_RETURN_TRUE require it.
- ext.extra_compile_args += ["-fno-strict-aliasing"]
-
- if os.environ.get("PYCAIRO_WARN"):
- ext.extra_compile_args += [
- "-Wall",
- "-Wundef",
- "-Wextra",
- "-Wno-missing-field-initializers",
- "-Wno-unused-parameter",
- "-Wnested-externs",
- "-Wpointer-arith",
- "-Wno-missing-field-initializers",
- "-Wdeclaration-after-statement",
- "-Wformat=2",
- "-Wold-style-definition",
- "-Wcast-align",
- "-Wformat-nonliteral",
- "-Wformat-security",
- "-Wsign-compare",
- "-Wstrict-aliasing",
- "-Wshadow",
- "-Winline",
- "-Wpacked",
- "-Wmissing-format-attribute",
- "-Wmissing-noreturn",
- "-Winit-self",
- "-Wunused-but-set-variable",
- "-Warray-bounds",
- "-Wimplicit-function-declaration",
- "-Wreturn-type",
- "-Wconversion",
- "-Wno-unknown-warning-option",
- ]
-
- if sys.version_info[:2] not in [(3, 3), (3, 4)]:
- ext.extra_compile_args += [
- "-Wswitch-default",
- ]
+
+ compiler = new_compiler(compiler=self.compiler)
+ customize_compiler(compiler)
+ add_ext_cflags(ext, compiler)
if self.enable_xpyb:
if sys.version_info[0] != 2:
"install_pkgconfig": install_pkgconfig,
"install_pycairo_header": install_pycairo_header,
"test": test_cmd,
+ "build_tests": build_tests,
}
setup(
maintainer_email="reiter.christoph@gmail.com",
ext_modules=[cairo_ext],
packages=["cairo"],
- package_data={"cairo": ["__init__.pyi"]},
+ package_data={
+ "cairo": [
+ "__init__.pyi",
+ "py.typed",
+ ],
+ },
classifiers=[
'Operating System :: OS Independent',
'Programming Language :: Python :: 2',
--- /dev/null
+#include <Python.h>
+/* not pycairo3.h because we use the one from the source directory */
+#include <pycairo.h>
+#include "cmodulelib.h"
+
+static PyMethodDef CModMethods[] = {
+ {"create_image_surface", create_image_surface, METH_NOARGS, NULL},
+ {NULL, NULL, 0, NULL}
+};
+
+#ifdef __GNUC__
+#define PYCAIRO_MODINIT_FUNC __attribute__((visibility("default"))) PyMODINIT_FUNC
+#else
+#define PYCAIRO_MODINIT_FUNC PyMODINIT_FUNC
+#endif
+
+#if PY_MAJOR_VERSION < 3
+
+Pycairo_CAPI_t *Pycairo_CAPI;
+
+PYCAIRO_MODINIT_FUNC
+initcmod (void)
+{
+ Py_InitModule ("cmod", CModMethods);
+
+ Pycairo_IMPORT;
+}
+#else
+
+static struct PyModuleDef cmod_module = {
+ PyModuleDef_HEAD_INIT,
+ "cmod",
+ NULL,
+ -1,
+ CModMethods,
+};
+
+PYCAIRO_MODINIT_FUNC
+PyInit_cmod (void)
+{
+ PyObject *m;
+
+ if (import_cairo () < 0)
+ return NULL;
+
+ m = PyModule_Create (&cmod_module);
+ if (m == NULL)
+ return NULL;
+
+ return m;
+}
+
+#endif
--- /dev/null
+#include <Python.h>
+#define PYCAIRO_NO_IMPORT
+#include <pycairo.h>
+#include "cmodulelib.h"
+
+#if PY_MAJOR_VERSION < 3
+extern Pycairo_CAPI_t *Pycairo_CAPI;
+#endif
+
+PyObject *
+create_image_surface (PyObject *self, PyObject *args)
+{
+ cairo_surface_t *surface;
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 10, 10);
+
+ return PycairoSurface_FromSurface (surface, NULL);
+}
--- /dev/null
+#ifndef _PYCAIRO_CMODULELIB_H_
+#define _PYCAIRO_CMODULELIB_H_
+
+PyObject *create_image_surface (PyObject *self, PyObject *args);
+
+#endif
--- /dev/null
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import
+
+import cairo
+
+from . import cmod
+
+
+def test_foo():
+ surface = cmod.create_image_surface()
+ assert isinstance(surface, cairo.ImageSurface)
import pytest
+def test_context_manager():
+ f = io.BytesIO()
+ with cairo.ScriptDevice(f) as dev:
+ dev.acquire()
+ dev.release()
+
+ with pytest.raises(cairo.Error) as excinfo:
+ dev.acquire()
+ assert excinfo.value.status == cairo.Status.DEVICE_FINISHED
+
+
def test_cmp_hash():
f = io.BytesIO()
dev = cairo.ScriptDevice(f)
import pytest
+def test_context_manager():
+ with cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) as surface:
+ surface.show_page()
+ with pytest.raises(cairo.Error) as excinfo:
+ surface.show_page()
+ assert excinfo.value.status == cairo.Status.SURFACE_FINISHED
+
+
def test_surface_cmp_hash():
main = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
ctx = cairo.Context(main)
del gced
+def test_surface_map_to_image_context_manager():
+ main = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
+ with main.map_to_image(None) as image:
+ pass
+
+ with pytest.raises(RuntimeError):
+ main.unmap_image(image)
+
+ with pytest.raises(cairo.Error) as excinfo:
+ image.show_page()
+ assert excinfo.value.status == cairo.Status.SURFACE_FINISHED
+
+ with pytest.raises(RuntimeError):
+ with image:
+ pass
+
+
def test_surface_map_to_image_data():
main = cairo.ImageSurface(cairo.Format.RGB24, 2, 1)
def collect_names(t):
names = set()
for key, value in vars(t).items():
- if key in ["XlibSurface", "XCBSurface"]:
+ if key in ["XlibSurface", "XCBSurface", "Win32PrintingSurface",
+ "Win32Surface"]:
continue
if key.startswith("_"):
continue