GNOME Bugzilla – Bug 728611
Python plugin: "Function implementation not available." when I use functools.partial
Last modified: 2014-04-22 01:46:02 UTC
As explained here, https://mail.gnome.org/archives/gnumeric-list/2014-April/msg00013.html I have written a Python function that renders "Function implementation not available." without printing other error messages. It appears that the issue relates to the use of functools.partial. For example, this works, from libsheetmusic.spreadsheet import scale def diatonic_scale(scientific_note): return scale('diatonic',scientific_note) sheetmusic_functions = { 'diatonic_scale': diatonic_scale } and this doesn't. import functools from libsheetmusic.spreadsheet import scale sheetmusic_functions = { 'diatonic_scale': functools.partial(scale, 'diatonic') } libsheetmusic is part of sheetmusic. http://pypi.python.org/pypi/sheetmusic
I suspect that it's related to how functools.partial doesn't return a function. http://stackoverflow.com/questions/13483527/why-doesnt-functools-partial-return-a-real-function-and-how-to-create-one-that
If you think that it is related to functools.partial, then how is this a Gnumeric issue?
Andreas: that's a Gnumeric error: func.c: return value_new_error (ei->pos, _("Function implementation not available."));
That error means that the module was loaded, but didn't provide the function it promised to provide.
I guess some idea of what should happen would help. Here are some ways that this could work. * All callables are allowed as values in the functions dictionary. * Only functions are allowed as values in the functions dictionary, and an error message tells me when I set something other than a function as a value. * The documentation indicates that only functions are allowed in the functions dictionary. I think Gnumeric would be better if one of the above were true, so I think it's worth considering it a Gnumeric issue.
If you take away functools.partial(scale, 'diatonic') and put some trivial function in its place, do things work? My hypothesis is that some of the framework (plugin.xml.in etc.) isn't setup right. Attaching the plugin code would be nice.
Created attachment 274780 [details] The spellbook for the example plugin
Created attachment 274781 [details] A spreadsheet that uses the example plugin.
If you take away functools.partial(scale, 'diatonic') and put some trivial function in its place, things do work; see the first example in my original description. I've attached a minimal example of the issue. You can also get it at this git repository. git@github.com:tlevine/functions-must-be-functions.git
Your functions_must_be_functions variable needs to define the functions you advertise in plugin.xml: type, function, other_callable. See https://git.gnome.org/browse/gnumeric/tree/plugins/py-func
I pondered whether it would be easy to write a Python library to convert Python callables into something Gnumeric would like. Here's my progress on that. I wrapped all of the callables in functions. def to_function(name, callable): def f(*args, **kwargs): return callable(*args, **kwargs) f.__name__ = name return f callables = {'diatonic_scale': ... } sheetmusic_functions = {k:to_function(k, v) for k,v in callables.items()} Now it works within a session, but it breaks when I close the file and open it again; the following text gets rendered from the cell in Gnumeric. Python exception (<type 'exceptions.SystemError'>: Objects/tupleobject.c:125: bad argument to internal function) I that the file references the internal "f" function. I'm starting to think that it'll be easier just to write out all of these functions with "def".
(In reply to comment #10) > Your functions_must_be_functions variable needs to define the > functions you advertise in plugin.xml: type, function, other_callable. > > See https://git.gnome.org/browse/gnumeric/tree/plugins/py-func Have I done this? For easy reference, I have copied below "functions_must_be.py" from attachment 274780 [details] (https://bugzilla.gnome.org/attachment.cgi?id=274780). class c: def __call__(self): return 2 functions_must_be_functions = { 'type': int, 'function': lambda: 1, 'other_callable': c(), }
Created attachment 274789 [details] Here's a screenshot of example.gnumeric I had to change "type" to "python_type" because it clashed with another function, but this is otherwise the same as the stuff I posted above.
We subject the value to a PyFunction_Check (in function gplp_func_desc_load in python-loader.c) If you know of a better check for callability of a python object, we can change it. I note, that we use PyCallable_Check elsewhere, but I cannot test this myself.
This problem has been fixed in our software repository. The fix will go into the next software release. Thank you for your bug report.