diff options
Diffstat (limited to 'gi')
-rw-r--r-- | gi/overrides/GLib.py | 56 | ||||
-rw-r--r-- | gi/overrides/GObject.py | 94 | ||||
-rw-r--r-- | gi/overrides/__init__.py | 74 | ||||
-rw-r--r-- | gi/pygi-basictype.c | 12 | ||||
-rw-r--r-- | gi/pygi-cache.c | 39 | ||||
-rw-r--r-- | gi/pygi-cache.h | 5 | ||||
-rw-r--r-- | gi/pygi-closure.c | 4 | ||||
-rw-r--r-- | gi/pygi-invoke.c | 41 |
8 files changed, 243 insertions, 82 deletions
diff --git a/gi/overrides/GLib.py b/gi/overrides/GLib.py index ce15da1..455ea84 100644 --- a/gi/overrides/GLib.py +++ b/gi/overrides/GLib.py @@ -26,7 +26,7 @@ import sys from ..module import get_introspection_module from .._gi import (variant_type_from_string, source_new, source_set_callback, io_channel_read) -from ..overrides import override, deprecated +from ..overrides import override, deprecated, deprecated_attr from gi import PyGIDeprecationWarning, version_info GLib = get_introspection_module('GLib') @@ -40,6 +40,7 @@ __all__.append('option') # Types and functions still needed from static bindings from gi._gi import _glib +from gi._gi import _gobject from gi._error import GError Error = GError @@ -481,8 +482,10 @@ __all__.append('markup_escape_text') # backwards compatible names from old static bindings for n in ['DESKTOP', 'DOCUMENTS', 'DOWNLOAD', 'MUSIC', 'PICTURES', 'PUBLIC_SHARE', 'TEMPLATES', 'VIDEOS']: - globals()['USER_DIRECTORY_' + n] = getattr(GLib.UserDirectory, 'DIRECTORY_' + n) - __all__.append('USER_DIRECTORY_' + n) + attr = 'USER_DIRECTORY_' + n + deprecated_attr("GLib", attr, "GLib.UserDirectory.DIRECTORY_" + n) + globals()[attr] = getattr(GLib.UserDirectory, 'DIRECTORY_' + n) + __all__.append(attr) for n in ['ERR', 'HUP', 'IN', 'NVAL', 'OUT', 'PRI']: globals()['IO_' + n] = getattr(GLib.IOCondition, n) @@ -490,30 +493,53 @@ for n in ['ERR', 'HUP', 'IN', 'NVAL', 'OUT', 'PRI']: for n in ['APPEND', 'GET_MASK', 'IS_READABLE', 'IS_SEEKABLE', 'MASK', 'NONBLOCK', 'SET_MASK']: - globals()['IO_FLAG_' + n] = getattr(GLib.IOFlags, n) - __all__.append('IO_FLAG_' + n) + attr = 'IO_FLAG_' + n + deprecated_attr("GLib", attr, "GLib.IOFlags." + n) + globals()[attr] = getattr(GLib.IOFlags, n) + __all__.append(attr) + # spelling for the win IO_FLAG_IS_WRITEABLE = GLib.IOFlags.IS_WRITABLE +deprecated_attr("GLib", "IO_FLAG_IS_WRITEABLE", "GLib.IOFlags.IS_WRITABLE") __all__.append('IO_FLAG_IS_WRITEABLE') for n in ['AGAIN', 'EOF', 'ERROR', 'NORMAL']: - globals()['IO_STATUS_' + n] = getattr(GLib.IOStatus, n) - __all__.append('IO_STATUS_' + n) + attr = 'IO_STATUS_' + n + globals()[attr] = getattr(GLib.IOStatus, n) + deprecated_attr("GLib", attr, "GLib.IOStatus." + n) + __all__.append(attr) for n in ['CHILD_INHERITS_STDIN', 'DO_NOT_REAP_CHILD', 'FILE_AND_ARGV_ZERO', 'LEAVE_DESCRIPTORS_OPEN', 'SEARCH_PATH', 'STDERR_TO_DEV_NULL', 'STDOUT_TO_DEV_NULL']: - globals()['SPAWN_' + n] = getattr(GLib.SpawnFlags, n) - __all__.append('SPAWN_' + n) + attr = 'SPAWN_' + n + globals()[attr] = getattr(GLib.SpawnFlags, n) + deprecated_attr("GLib", attr, "GLib.SpawnFlags." + n) + __all__.append(attr) for n in ['HIDDEN', 'IN_MAIN', 'REVERSE', 'NO_ARG', 'FILENAME', 'OPTIONAL_ARG', 'NOALIAS']: - globals()['OPTION_FLAG_' + n] = getattr(GLib.OptionFlags, n) - __all__.append('OPTION_FLAG_' + n) + attr = 'OPTION_FLAG_' + n + globals()[attr] = getattr(GLib.OptionFlags, n) + deprecated_attr("GLib", attr, "GLib.OptionFlags." + n) + __all__.append(attr) for n in ['UNKNOWN_OPTION', 'BAD_VALUE', 'FAILED']: - globals()['OPTION_ERROR_' + n] = getattr(GLib.OptionError, n) - __all__.append('OPTION_ERROR_' + n) + attr = 'OPTION_ERROR_' + n + deprecated_attr("GLib", attr, "GLib.OptionError." + n) + globals()[attr] = getattr(GLib.OptionError, n) + __all__.append(attr) + + +# these are not currently exported in GLib gir, presumably because they are +# platform dependent; so get them from our static bindings +for name in ['G_MINFLOAT', 'G_MAXFLOAT', 'G_MINDOUBLE', 'G_MAXDOUBLE', + 'G_MINSHORT', 'G_MAXSHORT', 'G_MAXUSHORT', 'G_MININT', 'G_MAXINT', + 'G_MAXUINT', 'G_MINLONG', 'G_MAXLONG', 'G_MAXULONG', 'G_MAXSIZE', + 'G_MINSSIZE', 'G_MAXSSIZE', 'G_MINOFFSET', 'G_MAXOFFSET']: + attr = name.split("_", 1)[-1] + globals()[attr] = getattr(_gobject, name) + __all__.append(attr) class MainLoop(GLib.MainLoop): @@ -901,5 +927,9 @@ if not hasattr(GLib, 'unix_signal_add_full'): # obsolete constants for backwards compatibility glib_version = (GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION) __all__.append('glib_version') +deprecated_attr("GLib", "glib_version", + "(GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION)") + pyglib_version = version_info __all__.append('pyglib_version') +deprecated_attr("GLib", "pyglib_version", "gi.version_info") diff --git a/gi/overrides/GObject.py b/gi/overrides/GObject.py index e922ac0..28408b2 100644 --- a/gi/overrides/GObject.py +++ b/gi/overrides/GObject.py @@ -27,7 +27,7 @@ from collections import namedtuple import gi.overrides import gi.module -from gi.overrides import override +from gi.overrides import override, deprecated_attr from gi.repository import GLib from gi import PyGIDeprecationWarning @@ -56,10 +56,11 @@ for name in ['markup_escape_text', 'get_application_name', 'idle_add', 'timeout_add', 'timeout_add_seconds', 'io_add_watch', 'child_watch_add', 'get_current_time', 'spawn_async']: - globals()[name] = gi.overrides.deprecated(getattr(GLib, name), 'GLib.' + name) + globals()[name] = getattr(GLib, name) + deprecated_attr("GObject", name, "GLib." + name) __all__.append(name) -# constants are also deprecated, but cannot mark them as such +# deprecated constants for name in ['PRIORITY_DEFAULT', 'PRIORITY_DEFAULT_IDLE', 'PRIORITY_HIGH', 'PRIORITY_HIGH_IDLE', 'PRIORITY_LOW', 'IO_IN', 'IO_OUT', 'IO_PRI', 'IO_ERR', 'IO_HUP', 'IO_NVAL', @@ -77,25 +78,21 @@ for name in ['PRIORITY_DEFAULT', 'PRIORITY_DEFAULT_IDLE', 'PRIORITY_HIGH', 'OPTION_FLAG_NOALIAS', 'OPTION_ERROR_UNKNOWN_OPTION', 'OPTION_ERROR_BAD_VALUE', 'OPTION_ERROR_FAILED', 'OPTION_REMAINING', 'glib_version']: - globals()[name] = getattr(GLib, name) + with warnings.catch_warnings(): + # TODO: this uses deprecated Glib attributes, silence for now + warnings.simplefilter('ignore', PyGIDeprecationWarning) + globals()[name] = getattr(GLib, name) + deprecated_attr("GObject", name, "GLib." + name) __all__.append(name) -G_MININT8 = GLib.MININT8 -G_MAXINT8 = GLib.MAXINT8 -G_MAXUINT8 = GLib.MAXUINT8 -G_MININT16 = GLib.MININT16 -G_MAXINT16 = GLib.MAXINT16 -G_MAXUINT16 = GLib.MAXUINT16 -G_MININT32 = GLib.MININT32 -G_MAXINT32 = GLib.MAXINT32 -G_MAXUINT32 = GLib.MAXUINT32 -G_MININT64 = GLib.MININT64 -G_MAXINT64 = GLib.MAXINT64 -G_MAXUINT64 = GLib.MAXUINT64 -__all__ += ['G_MININT8', 'G_MAXINT8', 'G_MAXUINT8', 'G_MININT16', - 'G_MAXINT16', 'G_MAXUINT16', 'G_MININT32', 'G_MAXINT32', - 'G_MAXUINT32', 'G_MININT64', 'G_MAXINT64', 'G_MAXUINT64'] +for name in ['G_MININT8', 'G_MAXINT8', 'G_MAXUINT8', 'G_MININT16', + 'G_MAXINT16', 'G_MAXUINT16', 'G_MININT32', 'G_MAXINT32', + 'G_MAXUINT32', 'G_MININT64', 'G_MAXINT64', 'G_MAXUINT64']: + new_name = name.split("_", 1)[-1] + globals()[name] = getattr(GLib, new_name) + deprecated_attr("GObject", name, "GLib." + new_name) + __all__.append(name) # these are not currently exported in GLib gir, presumably because they are # platform dependent; so get them from our static bindings @@ -103,7 +100,9 @@ for name in ['G_MINFLOAT', 'G_MAXFLOAT', 'G_MINDOUBLE', 'G_MAXDOUBLE', 'G_MINSHORT', 'G_MAXSHORT', 'G_MAXUSHORT', 'G_MININT', 'G_MAXINT', 'G_MAXUINT', 'G_MINLONG', 'G_MAXLONG', 'G_MAXULONG', 'G_MAXSIZE', 'G_MINSSIZE', 'G_MAXSSIZE', 'G_MINOFFSET', 'G_MAXOFFSET']: - globals()[name] = getattr(_gobject, name) + new_name = name.split("_", 1)[-1] + globals()[name] = getattr(GLib, new_name) + deprecated_attr("GObject", name, "GLib." + new_name) __all__.append(name) @@ -145,38 +144,44 @@ __all__ += ['TYPE_INVALID', 'TYPE_NONE', 'TYPE_INTERFACE', 'TYPE_CHAR', # Deprecated, use GLib directly -Pid = GLib.Pid -GError = GLib.GError -OptionGroup = GLib.OptionGroup -OptionContext = GLib.OptionContext -__all__ += ['Pid', 'GError', 'OptionGroup', 'OptionContext'] +for name in ['Pid', 'GError', 'OptionGroup', 'OptionContext']: + globals()[name] = getattr(GLib, name) + deprecated_attr("GObject", name, "GLib." + name) + __all__.append(name) # Deprecated, use: GObject.ParamFlags.* directly -PARAM_CONSTRUCT = GObjectModule.ParamFlags.CONSTRUCT -PARAM_CONSTRUCT_ONLY = GObjectModule.ParamFlags.CONSTRUCT_ONLY -PARAM_LAX_VALIDATION = GObjectModule.ParamFlags.LAX_VALIDATION -PARAM_READABLE = GObjectModule.ParamFlags.READABLE -PARAM_WRITABLE = GObjectModule.ParamFlags.WRITABLE +for name in ['PARAM_CONSTRUCT', 'PARAM_CONSTRUCT_ONLY', 'PARAM_LAX_VALIDATION', + 'PARAM_READABLE', 'PARAM_WRITABLE']: + new_name = name.split("_", 1)[-1] + globals()[name] = getattr(GObjectModule.ParamFlags, new_name) + deprecated_attr("GObject", name, "GObject.ParamFlags." + new_name) + __all__.append(name) + # PARAM_READWRITE should come from the gi module but cannot due to: # https://bugzilla.gnome.org/show_bug.cgi?id=687615 -PARAM_READWRITE = PARAM_READABLE | PARAM_WRITABLE -__all__ += ['PARAM_CONSTRUCT', 'PARAM_CONSTRUCT_ONLY', 'PARAM_LAX_VALIDATION', - 'PARAM_READABLE', 'PARAM_WRITABLE', 'PARAM_READWRITE'] +PARAM_READWRITE = GObjectModule.ParamFlags.READABLE | \ + GObjectModule.ParamFlags.WRITABLE +__all__.append("PARAM_READWRITE") +# READWRITE is part of ParamFlags since glib 2.42. Only mark PARAM_READWRITE as +# deprecated in case ParamFlags.READWRITE is available. Also include the glib +# version in the warning so it's clear that this needs a newer glib, unlike +# the other ParamFlags related deprecations. +# https://bugzilla.gnome.org/show_bug.cgi?id=726037 +if hasattr(GObjectModule.ParamFlags, "READWRITE"): + deprecated_attr("GObject", "PARAM_READWRITE", + "GObject.ParamFlags.READWRITE (glib 2.42+)") -# Deprecated, use: GObject.SignalFlags.* directly -SIGNAL_ACTION = GObjectModule.SignalFlags.ACTION -SIGNAL_DETAILED = GObjectModule.SignalFlags.DETAILED -SIGNAL_NO_HOOKS = GObjectModule.SignalFlags.NO_HOOKS -SIGNAL_NO_RECURSE = GObjectModule.SignalFlags.NO_RECURSE -SIGNAL_RUN_CLEANUP = GObjectModule.SignalFlags.RUN_CLEANUP -SIGNAL_RUN_FIRST = GObjectModule.SignalFlags.RUN_FIRST -SIGNAL_RUN_LAST = GObjectModule.SignalFlags.RUN_LAST -__all__ += ['SIGNAL_ACTION', 'SIGNAL_DETAILED', 'SIGNAL_NO_HOOKS', - 'SIGNAL_NO_RECURSE', 'SIGNAL_RUN_CLEANUP', 'SIGNAL_RUN_FIRST', - 'SIGNAL_RUN_LAST'] +# Deprecated, use: GObject.SignalFlags.* directly +for name in ['SIGNAL_ACTION', 'SIGNAL_DETAILED', 'SIGNAL_NO_HOOKS', + 'SIGNAL_NO_RECURSE', 'SIGNAL_RUN_CLEANUP', 'SIGNAL_RUN_FIRST', + 'SIGNAL_RUN_LAST']: + new_name = name.split("_", 1)[-1] + globals()[name] = getattr(GObjectModule.SignalFlags, new_name) + deprecated_attr("GObject", name, "GObject.SignalFlags." + new_name) + __all__.append(name) # Static types GBoxed = _gobject.GBoxed @@ -705,4 +710,5 @@ SignalOverride = signalhelper.SignalOverride # Deprecated naming "property" available for backwards compatibility. # Keep this at the end of the file to avoid clobbering the builtin. property = Property +deprecated_attr("GObject", "property", "GObject.Property") __all__ += ['Property', 'Signal', 'SignalOverride', 'property'] diff --git a/gi/overrides/__init__.py b/gi/overrides/__init__.py index b337b35..62cfd30 100644 --- a/gi/overrides/__init__.py +++ b/gi/overrides/__init__.py @@ -14,6 +14,10 @@ from pkgutil import extend_path __path__ = extend_path(__path__, __name__) +# namespace -> (attr, replacement) +_deprecated_attrs = {} + + def wraps(wrapped): def assign(wrapper): wrapper.__name__ = wrapped.__name__ @@ -43,6 +47,37 @@ class OverridesProxyModule(types.ModuleType): return "<%s %r>" % (type(self).__name__, self._introspection_module) +class _DeprecatedAttribute(object): + """A deprecation descriptor for OverridesProxyModule subclasses. + + Emits a PyGIDeprecationWarning on every access and tries to act as a + normal instance attribute (can be replaced and deleted). + """ + + def __init__(self, namespace, attr, value, replacement): + self._attr = attr + self._value = value + self._warning = PyGIDeprecationWarning( + '%s.%s is deprecated; use %s instead' % ( + namespace, attr, replacement)) + + def __get__(self, instance, owner): + if instance is None: + raise AttributeError(self._attr) + warnings.warn(self._warning, stacklevel=2) + return self._value + + def __set__(self, instance, value): + attr = self._attr + # delete the descriptor, then set the instance value + delattr(type(instance), attr) + setattr(instance, attr, value) + + def __delete__(self, instance): + # delete the descriptor + delattr(type(instance), self._attr) + + def load_overrides(introspection_module): """Loads overrides for an introspection module. @@ -58,7 +93,11 @@ def load_overrides(introspection_module): has_old = module_key in sys.modules old_module = sys.modules.get(module_key) - proxy = OverridesProxyModule(introspection_module) + # Create a new sub type, so we can separate descriptors like + # _DeprecatedAttribute for each namespace. + proxy_type = type(namespace + "ProxyModule", (OverridesProxyModule, ), {}) + + proxy = proxy_type(introspection_module) sys.modules[module_key] = proxy # backwards compat: @@ -90,6 +129,19 @@ def load_overrides(introspection_module): continue setattr(proxy, var, item) + # Replace deprecated module level attributes with a descriptor + # which emits a warning when accessed. + for attr, replacement in _deprecated_attrs.pop(namespace, []): + try: + value = getattr(proxy, attr) + except AttributeError: + raise AssertionError( + "%s was set deprecated but wasn't added to __all__" % attr) + delattr(proxy, attr) + deprecated_attr = _DeprecatedAttribute( + namespace, attr, value, replacement) + setattr(proxy_type, attr, deprecated_attr) + return proxy @@ -152,6 +204,26 @@ def deprecated(fn, replacement): return wrapped +def deprecated_attr(namespace, attr, replacement): + """Marks a module level attribute as deprecated. Accessing it will emit + a PyGIDeprecationWarning warning. + + e.g. for ``deprecated_attr("GObject", "STATUS_FOO", "GLib.Status.FOO")`` + accessing GObject.STATUS_FOO will emit: + + "GObject.STATUS_FOO is deprecated; use GLib.Status.FOO instead" + + :param str namespace: + The namespace of the override this is called in. + :param str namespace: + The attribute name (which gets added to __all__). + :param str replacement: + The replacement text which will be included in the warning. + """ + + _deprecated_attrs.setdefault(namespace, []).append((attr, replacement)) + + def deprecated_init(super_init_func, arg_names, ignore=tuple(), deprecated_aliases={}, deprecated_defaults={}, category=PyGIDeprecationWarning, diff --git a/gi/pygi-basictype.c b/gi/pygi-basictype.c index e199741..432559d 100644 --- a/gi/pygi-basictype.c +++ b/gi/pygi-basictype.c @@ -253,18 +253,18 @@ _pygi_marshal_from_py_filename (PyObject *py_arg, { gchar *string_; GError *error = NULL; + PyObject *tmp = NULL; if (PyUnicode_Check (py_arg)) { - PyObject *pystr_obj = PyUnicode_AsUTF8String (py_arg); - if (!pystr_obj) + tmp = PyUnicode_AsUTF8String (py_arg); + if (!tmp) return FALSE; - string_ = g_strdup (PYGLIB_PyBytes_AsString (pystr_obj)); - Py_DECREF (pystr_obj); + string_ = PYGLIB_PyBytes_AsString (tmp); } #if PY_VERSION_HEX < 0x03000000 else if (PyString_Check (py_arg)) { - string_ = g_strdup (PyString_AsString (py_arg)); + string_ = PyString_AsString (py_arg); } #endif else { @@ -274,7 +274,7 @@ _pygi_marshal_from_py_filename (PyObject *py_arg, } arg->v_string = g_filename_from_utf8 (string_, -1, NULL, NULL, &error); - g_free (string_); + Py_XDECREF (tmp); if (arg->v_string == NULL) { PyErr_SetString (PyExc_Exception, error->message); diff --git a/gi/pygi-cache.c b/gi/pygi-cache.c index a572929..ca24517 100644 --- a/gi/pygi-cache.c +++ b/gi/pygi-cache.c @@ -657,6 +657,7 @@ _callable_cache_init (PyGICallableCache *cache, GICallableInfo *callable_info) { gint n_args; + GIBaseInfo *container; if (cache->deinit == NULL) cache->deinit = _callable_cache_deinit_real; @@ -665,18 +666,27 @@ _callable_cache_init (PyGICallableCache *cache, cache->generate_args_cache = _callable_cache_generate_args_cache_real; cache->name = g_base_info_get_name ((GIBaseInfo *) callable_info); + cache->namespace = g_base_info_get_namespace ((GIBaseInfo *) callable_info); + container = g_base_info_get_container ((GIBaseInfo *) callable_info); + cache->container_name = NULL; + /* https://bugzilla.gnome.org/show_bug.cgi?id=709456 */ + if (container != NULL && g_base_info_get_type (container) != GI_INFO_TYPE_TYPE) { + cache->container_name = g_base_info_get_name (container); + } cache->throws = g_callable_info_can_throw_gerror ((GIBaseInfo *) callable_info); if (g_base_info_is_deprecated (callable_info)) { const gchar *deprecated = g_base_info_get_attribute (callable_info, "deprecated"); gchar *warning; + gchar *full_name = pygi_callable_cache_get_full_name (cache); if (deprecated != NULL) - warning = g_strdup_printf ("%s.%s is deprecated: %s", - g_base_info_get_namespace (callable_info), cache->name, + warning = g_strdup_printf ("%s is deprecated: %s", + full_name, deprecated); else - warning = g_strdup_printf ("%s.%s is deprecated", - g_base_info_get_namespace (callable_info), cache->name); + warning = g_strdup_printf ("%s is deprecated", + full_name); + g_free (full_name); PyErr_WarnEx (PyExc_DeprecationWarning, warning, 0); g_free (warning); } @@ -696,6 +706,23 @@ _callable_cache_init (PyGICallableCache *cache, return TRUE; } +gchar * +pygi_callable_cache_get_full_name (PyGICallableCache *cache) +{ + if (cache->container_name != NULL) { + return g_strjoin (".", + cache->namespace, + cache->container_name, + cache->name, + NULL); + } else { + return g_strjoin (".", + cache->namespace, + cache->name, + NULL); + } +} + void pygi_callable_cache_free (PyGICallableCache *cache) { @@ -845,11 +872,13 @@ _constructor_cache_invoke_real (PyGIFunctionCache *function_cache, constructor_class = PyTuple_GetItem (py_args, 0); if (constructor_class == NULL) { + gchar *full_name = pygi_callable_cache_get_full_name (cache); PyErr_Clear (); PyErr_Format (PyExc_TypeError, "Constructors require the class to be passed in as an argument, " "No arguments passed to the %s constructor.", - ((PyGICallableCache *) function_cache)->name); + full_name); + g_free (full_name); return FALSE; } diff --git a/gi/pygi-cache.h b/gi/pygi-cache.h index 0361f00..098f3f1 100644 --- a/gi/pygi-cache.h +++ b/gi/pygi-cache.h @@ -158,6 +158,8 @@ typedef struct _PyGIInterfaceCache struct _PyGICallableCache { const gchar *name; + const gchar *container_name; + const gchar *namespace; PyGICallingContext calling_context; @@ -265,6 +267,9 @@ pygi_arg_cache_free (PyGIArgCache *cache); void pygi_callable_cache_free (PyGICallableCache *cache); +gchar * +pygi_callable_cache_get_full_name (PyGICallableCache *cache); + PyGIFunctionCache * pygi_function_cache_new (GICallableInfo *info); diff --git a/gi/pygi-closure.c b/gi/pygi-closure.c index 2a5a120..65f7e55 100644 --- a/gi/pygi-closure.c +++ b/gi/pygi-closure.c @@ -777,10 +777,12 @@ _pygi_marshal_from_py_interface_callback (PyGIInvokeState *state, if (user_data_cache != NULL) { state->arg_values[destroy_cache->c_arg_index].v_pointer = _pygi_invoke_closure_free; } else { + char *full_name = pygi_callable_cache_get_full_name (callable_cache); gchar *msg = g_strdup_printf("Callables passed to %s will leak references because " "the method does not support a user_data argument. " "See: https://bugzilla.gnome.org/show_bug.cgi?id=685598", - callable_cache->name); + full_name); + g_free (full_name); if (PyErr_WarnEx(PyExc_RuntimeWarning, msg, 2)) { g_free(msg); _pygi_invoke_closure_free(closure); diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c index a65274a..0151650 100644 --- a/gi/pygi-invoke.c +++ b/gi/pygi-invoke.c @@ -26,7 +26,7 @@ #include "pygi-error.h" static gboolean -_check_for_unexpected_kwargs (const gchar *function_name, +_check_for_unexpected_kwargs (PyGICallableCache *cache, GHashTable *arg_name_hash, PyObject *py_kwargs) { @@ -54,11 +54,13 @@ _check_for_unexpected_kwargs (const gchar *function_name, * found which maps to index 0 for our hash lookup. */ if (!g_hash_table_lookup_extended (arg_name_hash, PyBytes_AsString(key), NULL, NULL)) { + char *full_name = pygi_callable_cache_get_full_name (cache); PyErr_Format (PyExc_TypeError, "%.200s() got an unexpected keyword argument '%.400s'", - function_name, + full_name, PyBytes_AsString (key)); Py_DECREF (key); + g_free (full_name); return FALSE; } @@ -84,7 +86,6 @@ _py_args_combine_and_check_length (PyGICallableCache *cache, Py_ssize_t n_py_args, n_py_kwargs, i; guint n_expected_args; GSList *l; - const gchar *function_name = cache->name; n_py_args = PyTuple_GET_SIZE (py_args); if (py_kwargs == NULL) @@ -100,24 +101,28 @@ _py_args_combine_and_check_length (PyGICallableCache *cache, } if (cache->user_data_varargs_index < 0 && n_expected_args < n_py_args) { + char *full_name = pygi_callable_cache_get_full_name (cache); PyErr_Format (PyExc_TypeError, "%.200s() takes exactly %d %sargument%s (%zd given)", - function_name, + full_name, n_expected_args, n_py_kwargs > 0 ? "non-keyword " : "", n_expected_args == 1 ? "" : "s", n_py_args); + g_free (full_name); return NULL; } if (cache->user_data_varargs_index >= 0 && n_py_kwargs > 0 && n_expected_args < n_py_args) { + char *full_name = pygi_callable_cache_get_full_name (cache); PyErr_Format (PyExc_TypeError, "%.200s() cannot use variable user data arguments with keyword arguments", - function_name); + full_name); + g_free (full_name); return NULL; } - if (n_py_kwargs > 0 && !_check_for_unexpected_kwargs (function_name, + if (n_py_kwargs > 0 && !_check_for_unexpected_kwargs (cache, cache->arg_name_hash, py_kwargs)) { return NULL; @@ -183,24 +188,28 @@ _py_args_combine_and_check_length (PyGICallableCache *cache, Py_INCREF (_PyGIDefaultArgPlaceholder); PyTuple_SET_ITEM (combined_py_args, i, _PyGIDefaultArgPlaceholder); } else { + char *full_name = pygi_callable_cache_get_full_name (cache); PyErr_Format (PyExc_TypeError, "%.200s() takes exactly %d %sargument%s (%zd given)", - function_name, + full_name, n_expected_args, n_py_kwargs > 0 ? "non-keyword " : "", n_expected_args == 1 ? "" : "s", n_py_args); + g_free (full_name); Py_DECREF (combined_py_args); return NULL; } } else if (kw_arg_item != NULL && py_arg_item != NULL) { + char *full_name = pygi_callable_cache_get_full_name (cache); PyErr_Format (PyExc_TypeError, "%.200s() got multiple values for keyword argument '%.200s'", - function_name, + full_name, arg_name); Py_DECREF (combined_py_args); + g_free (full_name); return NULL; } } @@ -362,11 +371,13 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGIFunctionCache *function_cac gssize i; if (state->n_py_in_args > cache->n_py_args) { + char *full_name = pygi_callable_cache_get_full_name (cache); PyErr_Format (PyExc_TypeError, "%s() takes exactly %zd argument(s) (%zd given)", - cache->name, + full_name, cache->n_py_args, state->n_py_in_args); + g_free (full_name); return FALSE; } @@ -387,11 +398,13 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGIFunctionCache *function_cac continue; if (arg_cache->py_arg_index >= state->n_py_in_args) { + char *full_name = pygi_callable_cache_get_full_name (cache); PyErr_Format (PyExc_TypeError, "%s() takes exactly %zd argument(s) (%zd given)", - cache->name, + full_name, cache->n_py_args, state->n_py_in_args); + g_free (full_name); /* clean up all of the args we have already marshalled, * since invoke will not be called @@ -410,11 +423,13 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGIFunctionCache *function_cac case PYGI_DIRECTION_BIDIRECTIONAL: if (arg_cache->meta_type != PYGI_META_ARG_TYPE_CHILD) { if (arg_cache->py_arg_index >= state->n_py_in_args) { + char *full_name = pygi_callable_cache_get_full_name (cache); PyErr_Format (PyExc_TypeError, "%s() takes exactly %zd argument(s) (%zd given)", - cache->name, + full_name, cache->n_py_args, state->n_py_in_args); + g_free (full_name); pygi_marshal_cleanup_args_from_py_parameter_fail (state, cache, i); @@ -446,9 +461,11 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGIFunctionCache *function_cac state->args[i] = c_arg; if (!_caller_alloc (arg_cache, c_arg)) { + char *full_name = pygi_callable_cache_get_full_name (cache); PyErr_Format (PyExc_TypeError, "Could not caller allocate argument %zd of callable %s", - i, cache->name); + i, full_name); + g_free (full_name); pygi_marshal_cleanup_args_from_py_parameter_fail (state, cache, i); |