From 84e55b86e6382ad6b4ffc59ddbdfe98eb73c3ff8 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Mon, 8 Sep 2014 14:53:37 +0100 Subject: [PATCH] added class methods to python we now have Vips.Image.black(w, h), woo --- TODO | 21 --------------------- libvips/include/vips/object.h | 1 + libvips/iofuncs/object.c | 23 +++++++++++++++++++++++ python/try9.py | 2 -- python/vips8/vips.py | 14 ++++++++++---- 5 files changed, 34 insertions(+), 27 deletions(-) diff --git a/TODO b/TODO index 0ac5d7a5..6a97fff1 100644 --- a/TODO +++ b/TODO @@ -1,27 +1,6 @@ - python: - - can we override __getattr__ on a type object? - - Vips.Image.black - AttributeError: type object 'Image' has no attribute 'black' - - we'd like to attack black as a class method, or override __getattr__ - to let us patch class methods in - - looks like defining a metaclass might do it, but - - Vips.Image.__metaclass__ = ImageType - setattr(Vips.Image, '__metaclass__', ImageType) - setattr(Vips.Image, '__metaclass__', classmethod(ImageType)) - - don't work, nor any other obvious variations - - we could walk all vips operators and paste in ones without an - image instance arg as class methods, but that would be very slow and - wouldn't work for loading plugins - - - how about the in-place things? draw a circle? - try getting / setting / deleting metadata such as an ICC profile or diff --git a/libvips/include/vips/object.h b/libvips/include/vips/object.h index 371beae4..7c0487d5 100644 --- a/libvips/include/vips/object.h +++ b/libvips/include/vips/object.h @@ -618,6 +618,7 @@ void *vips_type_map( GType base, VipsTypeMap2Fn fn, void *a, void *b ); void *vips_type_map_all( GType base, VipsTypeMapFn fn, void *a ); int vips_type_depth( GType type ); GType vips_type_find( const char *basename, const char *nickname ); +const char *vips_nickname_find( GType type ); void *vips_class_map_all( GType base, VipsClassMapFn fn, void *a ); VipsObjectClass *vips_class_find( const char *basename, const char *nickname ); diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index d669f442..cc8cd72f 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -2746,6 +2746,29 @@ vips_type_find( const char *basename, const char *nickname ) return( type ); } +/** + * vips_nickname_find: + * @type: #GType to search for + * + * Return the VIPS nickanme for a %GType. Handy for language bindings. + * + * Returns: (transfer none): the class nickname. + */ +const char * +vips_nickname_find( GType type ) +{ + gpointer p; + VipsObjectClass *class; + + if( type && + (p = g_type_class_ref( type )) && + VIPS_IS_OBJECT_CLASS( p ) && + (class = VIPS_OBJECT_CLASS( p )) ) + return( class->nickname ); + + return( NULL ); +} + /* The vips_object_local() macro uses this as its callback. */ void diff --git a/python/try9.py b/python/try9.py index 084115de..eaf778ff 100755 --- a/python/try9.py +++ b/python/try9.py @@ -5,8 +5,6 @@ import sys import logging logging.basicConfig(level = logging.DEBUG) -from gi.repository import GLib -from gi.repository import GObject from gi.repository import Vips from vips8 import vips diff --git a/python/vips8/vips.py b/python/vips8/vips.py index 229076c8..c770a53d 100644 --- a/python/vips8/vips.py +++ b/python/vips8/vips.py @@ -397,7 +397,7 @@ setattr(Vips.Image, 'new_from_buffer', classmethod(vips_image_new_from_buffer)) setattr(Vips.Image, 'new_from_array', classmethod(vips_image_new_from_array)) # yuk, we should run these via a metaclass somehow -setattr(Vips.Image, 'black', classmethod(vips_black)) +#setattr(Vips.Image, 'black', classmethod(vips_black)) # Search for all VipsOperation which don't have an input image object ... these # become class methods @@ -405,7 +405,10 @@ setattr(Vips.Image, 'black', classmethod(vips_black)) def vips_image_class_method(name, args, kwargs): logging.debug('vips_image_class_method %s' % name) - return _call_instance(None, name, args, kwargs) + # the first arg is the class we are called from ... drop it + args = tuple(list(args)[1::]) + + return _call_base(name, args, kwargs) def define_class_methods(cls): if len(cls.children) > 0: @@ -424,8 +427,11 @@ def define_class_methods(cls): break if not found: - print 'operation %s has no input image args' % cls.name - setattr(Vips.Image, cls.name, classmethod(lambda *args, **kwargs: vips_image_class_method(cls.name, args, kwargs))) + gtype = Vips.type_find("VipsOperation", cls.name) + nickname = Vips.nickname_find(gtype) + logging.debug('adding %s as a class method' % nickname) + method = lambda *args, **kwargs: vips_image_class_method( nickname, args, kwargs) + setattr(Vips.Image, nickname, classmethod(method)) define_class_methods(vips_type_operation)