When we renamed all the python files to say python3 we missed the actual directory
Testing Done:
Compiled locally, built debian and fedora packages without issues.
Reviewed at https://reviews.imfreedom.org/r/106/
--- a/meson.build Sat Sep 05 20:27:32 2020 -0500
+++ b/meson.build Sat Sep 05 23:31:26 2020 -0500
@@ -91,7 +91,7 @@
--- a/python/gplugin-python3-core.c Sat Sep 05 20:27:32 2020 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
- * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
-#include <glib/gi18n-lib.h>
-#include <gplugin-native.h>
-#include "gplugin-python3-loader.h"
-#include "gplugin-python3-plugin.h"
-G_MODULE_EXPORT GPluginPluginInfo *
-gplugin_query(G_GNUC_UNUSED GError **error)
- /* clang-format-11 formats this correctly, so this can be removed then. */
- const gchar *const authors[] = {
- "Gary Kramlich <grim@reaperworld.com>",
- return gplugin_plugin_info_new(
- "gplugin/python3-loader",
- GPLUGIN_NATIVE_PLUGIN_ABI_VERSION,
- "name", "Python Plugin Loader",
- "version", GPLUGIN_VERSION,
- "license-id", "LGPL-2.0-or-later",
- "summary", "A plugin that can load python plugins",
- "description", "This plugin allows the loading of plugins written in "
- "the python programming language.",
- "website", GPLUGIN_WEBSITE,
-G_MODULE_EXPORT gboolean
-gplugin_load(GPluginNativePlugin *plugin, G_GNUC_UNUSED GError **error)
- gplugin_python3_plugin_register(plugin);
- gplugin_python3_loader_register(plugin);
- return gplugin_manager_register_loader(GPLUGIN_PYTHON3_TYPE_LOADER, error);
-G_MODULE_EXPORT gboolean
-gplugin_unload(G_GNUC_UNUSED GPluginNativePlugin *plugin, GError **error)
- _("The Python loader can not be unloaded"));
--- a/python/gplugin-python3-loader.c Sat Sep 05 20:27:32 2020 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,401 +0,0 @@
- * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
-#include "gplugin-python3-loader.h"
-#include <glib/gi18n-lib.h>
-#include "gplugin-python3-plugin.h"
-#include "gplugin-python3-utils.h"
-struct _GPluginPython3Loader {
- PyThreadState *py_thread_state;
- gplugin_python3_loader,
-/******************************************************************************
- * GPluginLoader Implementation
- *****************************************************************************/
-gplugin_python3_loader_supported_extensions(G_GNUC_UNUSED GPluginLoader *l)
- return g_slist_append(NULL, "py");
-gplugin_python3_loader_query(
- G_GNUC_UNUSED GError **error)
- GPluginPlugin *plugin = NULL;
- PyObject *pyinfo = NULL, *args = NULL;
- PyObject *module = NULL, *package_list = NULL, *module_dict = NULL;
- PyObject *query = NULL, *load = NULL, *unload = NULL;
- PyGILState_STATE state;
- gchar *module_name = NULL, *dir_name = NULL;
- state = pyg_gil_state_ensure();
- /* create package_list as a tuple to handle 'import foo.bar' */
- package_list = PyTuple_New(0);
- /* now figure out the module name from the filename */
- module_name = gplugin_python3_filename_to_module(filename);
- /* grab the dirname since we need it on sys.path to import the module */
- dir_name = g_path_get_dirname(filename);
- gplugin_python3_add_module_path(dir_name);
- /* import the module */
- module = PyImport_ImportModuleEx(module_name, NULL, NULL, package_list);
- g_warning(_("Failed to query %s"), filename);
- /* clean some stuff up */
- Py_DECREF(package_list);
- pyg_gil_state_release(state);
- /* clean some stuff up */
- Py_DECREF(package_list);
- /* at this point we have the module, lets find the query, load, and unload
- module_dict = PyModule_GetDict(module);
- query = PyDict_GetItemString(module_dict, "gplugin_query");
- _("Failed to find the gplugin_query function in %s"),
- pyg_gil_state_release(state);
- if(!PyCallable_Check(query)) {
- _("Found gplugin_query in %s but it is not a "
- pyg_gil_state_release(state);
- load = PyDict_GetItemString(module_dict, "gplugin_load");
- _("Failed to find the gplugin_load function in %s"),
- pyg_gil_state_release(state);
- if(!PyCallable_Check(load)) {
- _("Found gplugin_load in %s but it is not a "
- pyg_gil_state_release(state);
- unload = PyDict_GetItemString(module_dict, "gplugin_unload");
- _("Failed to find the gplugin_unload function in %s"),
- pyg_gil_state_release(state);
- if(!PyCallable_Check(unload)) {
- _("Found gplugin_unload in %s but it is not a "
- pyg_gil_state_release(state);
- /* now that we have everything, call the query method and get the plugin's
- pyinfo = PyObject_Call(query, args, NULL);
- info = pygobject_get(pyinfo);
- /* now that we have everything, create the plugin */
- GPLUGIN_PYTHON3_TYPE_PLUGIN,
- pyg_gil_state_release(state);
-gplugin_python3_loader_load(
- G_GNUC_UNUSED GPluginLoader *loader,
- PyObject *load = NULL, *pyplugin = NULL, *result = NULL;
- g_object_get(G_OBJECT(plugin), "load-func", &load, NULL);
- pyplugin = pygobject_new(G_OBJECT(plugin));
- result = PyObject_CallFunctionObjArgs(load, pyplugin, NULL);
- *error = gplugin_python3_exception_to_gerror();
- ret = PyObject_IsTrue(result);
- _("Failed to load plugin"));
-gplugin_python3_loader_unload(
- G_GNUC_UNUSED GPluginLoader *loader,
- PyObject *unload = NULL, *pyplugin = NULL, *result = NULL;
- g_object_get(G_OBJECT(plugin), "unload-func", &unload, NULL);
- pyplugin = pygobject_new(G_OBJECT(plugin));
- result = PyObject_CallFunctionObjArgs(unload, pyplugin, NULL);
- ret = PyObject_IsTrue(result);
- _("Failed to unload plugin"));
-/******************************************************************************
- *****************************************************************************/
-gplugin_python3_loader_init_pygobject(void)
- pygobject_init(3, 0, 0);
- PyObject *type = NULL, *value = NULL, *tb = NULL, *obj = NULL;
- PyErr_Fetch(&type, &value, &tb);
- obj = PyUnicode_AsUTF8String(value);
- g_warning("Failed to initialize PyGObject : %s", PyBytes_AsString(obj));
- /* disable g_log redirections */
- pyg_disable_warning_redirections();
-gplugin_python3_loader_init_gettext(void)
- PyObject *module_dict = NULL, *install = NULL;
- PyObject *gettext = NULL, *result = NULL;
- gettext = PyImport_ImportModule("gettext");
- g_warning("Failed to import gettext");
- module_dict = PyModule_GetDict(gettext);
- install = PyDict_GetItemString(module_dict, "install");
- result = PyObject_CallFunction(install, "ss", GETTEXT_PACKAGE, LOCALEDIR);
-gplugin_python3_loader_init_python(void)
- wchar_t *argv[] = {NULL, NULL};
- /* Initializes Python */
- if(!Py_IsInitialized())
- Py_InitializeEx(FALSE);
- argv[0] = Py_DecodeLocale(g_get_prgname(), NULL);
- g_warning("Could not convert program name to wchar_t string.");
- /* setup sys.path according to
- * https://docs.python.org/3/c-api/init.html#PySys_SetArgvEx
- PySys_SetArgvEx(1, argv, 0);
- PyMem_RawFree(argv[0]);
- /* initialize pygobject */
- if(gplugin_python3_loader_init_pygobject()) {
- if(gplugin_python3_loader_init_gettext()) {
-/******************************************************************************
- * GObject Implementation
- *****************************************************************************/
-gplugin_python3_loader_init(G_GNUC_UNUSED GPluginPython3Loader *loader)
-gplugin_python3_loader_class_finalize(
- G_GNUC_UNUSED GPluginPython3LoaderClass *klass)
-gplugin_python3_loader_class_init(GPluginPython3LoaderClass *klass)
- GPluginLoaderClass *loader_class = GPLUGIN_LOADER_CLASS(klass);
- loader_class->supported_extensions =
- gplugin_python3_loader_supported_extensions;
- loader_class->query = gplugin_python3_loader_query;
- loader_class->load = gplugin_python3_loader_load;
- loader_class->unload = gplugin_python3_loader_unload;
-/******************************************************************************
- *****************************************************************************/
-gplugin_python3_loader_register(GPluginNativePlugin *native)
- gplugin_python3_loader_register_type(G_TYPE_MODULE(native));
- gplugin_python3_loader_init_python();
--- a/python/gplugin-python3-loader.h Sat Sep 05 20:27:32 2020 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
- * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
-#ifndef GPLUGIN_PYTHON3_LOADER_H
-#define GPLUGIN_PYTHON3_LOADER_H
-#include <gplugin-native.h>
-#define GPLUGIN_PYTHON3_TYPE_LOADER (gplugin_python3_loader_get_type())
- gplugin_python3_loader,
-void gplugin_python3_loader_register(GPluginNativePlugin *native);
-#endif /* GPLUGIN_PYTHON3_LOADER_H */
--- a/python/gplugin-python3-plugin.c Sat Sep 05 20:27:32 2020 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,310 +0,0 @@
- * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
-#include "gplugin-python3-plugin.h"
-/******************************************************************************
- *****************************************************************************/
-struct _GPluginPython3Plugin {
- GPluginPluginInfo *info;
- GPluginPluginState state;
-/******************************************************************************
- *****************************************************************************/
- PROP_FILENAME = N_PROPERTIES,
-static GParamSpec *properties[N_PROPERTIES] = {
-/* I hate forward declarations... */
-static void gplugin_python3_plugin_iface_init(GPluginPluginInterface *iface);
-G_DEFINE_DYNAMIC_TYPE_EXTENDED(
- gplugin_python3_plugin,
- gplugin_python3_plugin_iface_init));
-/******************************************************************************
- * GPluginPlugin Implementation
- *****************************************************************************/
-gplugin_python3_plugin_iface_init(G_GNUC_UNUSED GPluginPluginInterface *iface)
-/******************************************************************************
- *****************************************************************************/
-gplugin_python3_plugin_set_module(
- GPluginPython3Plugin *plugin,
- g_return_if_fail(GPLUGIN_IS_PLUGIN(plugin));
- g_return_if_fail(module);
- Py_CLEAR(plugin->module);
- plugin->module = module;
-gplugin_python3_plugin_get_load_func(GPluginPython3Plugin *plugin)
- g_return_val_if_fail(GPLUGIN_PYTHON3_IS_PLUGIN(plugin), NULL);
-gplugin_python3_plugin_set_load_func(
- GPluginPython3Plugin *plugin,
- g_return_if_fail(GPLUGIN_PYTHON3_IS_PLUGIN(plugin));
- g_return_if_fail(func != NULL);
- Py_CLEAR(plugin->load);
-gplugin_python3_plugin_get_unload_func(GPluginPython3Plugin *plugin)
- g_return_val_if_fail(GPLUGIN_PYTHON3_IS_PLUGIN(plugin), NULL);
-gplugin_python3_plugin_set_unload_func(
- GPluginPython3Plugin *plugin,
- g_return_if_fail(GPLUGIN_PYTHON3_IS_PLUGIN(plugin));
- g_return_if_fail(func != NULL);
- Py_CLEAR(plugin->unload);
-/******************************************************************************
- * GObject Implementation
- *****************************************************************************/
-gplugin_python3_plugin_get_property(
- GPluginPython3Plugin *plugin = GPLUGIN_PYTHON3_PLUGIN(obj);
- g_value_set_pointer(value, plugin->module);
- gplugin_python3_plugin_get_load_func(plugin));
- gplugin_python3_plugin_get_unload_func(plugin));
- g_value_set_string(value, plugin->filename);
- g_value_set_object(value, plugin->loader);
- g_value_set_object(value, plugin->info);
- g_value_set_enum(value, plugin->state);
- g_value_set_boxed(value, plugin->error);
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-gplugin_python3_plugin_set_property(
- GPluginPython3Plugin *plugin = GPLUGIN_PYTHON3_PLUGIN(obj);
- gplugin_python3_plugin_set_module(
- g_value_get_pointer(value));
- gplugin_python3_plugin_set_load_func(
- g_value_get_pointer(value));
- gplugin_python3_plugin_set_unload_func(
- g_value_get_pointer(value));
- plugin->filename = g_value_dup_string(value);
- plugin->loader = g_value_dup_object(value);
- plugin->info = g_value_dup_object(value);
- plugin->state = g_value_get_enum(value);
- plugin->error = g_value_dup_boxed(value);
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-gplugin_python3_plugin_finalize(GObject *obj)
- GPluginPython3Plugin *plugin = GPLUGIN_PYTHON3_PLUGIN(obj);
- Py_CLEAR(plugin->module);
- Py_CLEAR(plugin->load);
- Py_CLEAR(plugin->unload);
- g_clear_pointer(&plugin->filename, g_free);
- g_clear_object(&plugin->loader);
- g_clear_object(&plugin->info);
- g_clear_error(&plugin->error);
- G_OBJECT_CLASS(gplugin_python3_plugin_parent_class)->finalize(obj);
-gplugin_python3_plugin_init(G_GNUC_UNUSED GPluginPython3Plugin *plugin)
-gplugin_python3_plugin_class_finalize(
- G_GNUC_UNUSED GPluginPython3PluginClass *klass)
-gplugin_python3_plugin_class_init(GPluginPython3PluginClass *klass)
- GObjectClass *obj_class = G_OBJECT_CLASS(klass);
- obj_class->get_property = gplugin_python3_plugin_get_property;
- obj_class->set_property = gplugin_python3_plugin_set_property;
- obj_class->finalize = gplugin_python3_plugin_finalize;
- properties[PROP_MODULE] = g_param_spec_pointer(
- "The python module object",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
- properties[PROP_LOAD_FUNC] = g_param_spec_pointer(
- "The python load function",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
- properties[PROP_UNLOAD_FUNC] = g_param_spec_pointer(
- "The python unload function",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
- g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
- /* add our overrides */
- g_object_class_override_property(obj_class, PROP_FILENAME, "filename");
- g_object_class_override_property(obj_class, PROP_LOADER, "loader");
- g_object_class_override_property(obj_class, PROP_INFO, "info");
- g_object_class_override_property(obj_class, PROP_STATE, "state");
- g_object_class_override_property(obj_class, PROP_ERROR, "error");
-/******************************************************************************
- *****************************************************************************/
-gplugin_python3_plugin_register(GPluginNativePlugin *native)
- gplugin_python3_plugin_register_type(G_TYPE_MODULE(native));
--- a/python/gplugin-python3-plugin.h Sat Sep 05 20:27:32 2020 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
- * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
-#ifndef GPLUGIN_PYTHON3_PLUGIN_H
-#define GPLUGIN_PYTHON3_PLUGIN_H
-#include <gplugin-native.h>
-#define GPLUGIN_PYTHON3_TYPE_PLUGIN (gplugin_python3_plugin_get_type())
- gplugin_python3_plugin,
-void gplugin_python3_plugin_register(GPluginNativePlugin *native);
-#endif /* GPLUGIN_PYTHON3_PLUGIN_H */
--- a/python/gplugin-python3-test-pygobject.c Sat Sep 05 20:27:32 2020 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
- * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
-main(gint argc, gchar *argv[])
- wchar_t *wargv[] = {NULL, NULL};
- /* initialize python */
- if(!Py_IsInitialized())
- Py_InitializeEx(FALSE);
- len = mbstowcs(NULL, argv[0], 0);
- if(len == (size_t)-1) {
- printf("Failed to call mbstowcs to find length of argv[0]: %s\n", argv[0]);
- wargv[0] = g_new0(wchar_t, len + 1);
- len = mbstowcs(wargv[0], argv[0], len + 1);
- if(len == (size_t)-1) {
- printf("Failed to call mbstowcs to convert argv[0]: %s\n", argv[0]);
- PySys_SetArgvEx(1, wargv, 0);
- /* initialize pygobject */
- pygobject_init(3, 0, 0);
- printf("Calling pygobject_init failed.\n");
--- a/python/gplugin-python3-utils.c Sat Sep 05 20:27:32 2020 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
- * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
-#include "gplugin-python3-utils.h"
-gplugin_python3_filename_to_module(const gchar *filename)
- gchar *e = NULL, *r = NULL;
- g_return_val_if_fail(filename != NULL, NULL);
- /* first make sure we just have a filename */
- base = g_path_get_basename(filename);
- /* now find the last . for the extension */
- e = g_utf8_strrchr(base, g_utf8_strlen(base, -1), g_utf8_get_char("."));
- /* now copy the module name into r */
- r = g_malloc(e - base + 1);
- memcpy(r, base, e - base);
- /* free the basename */
-gplugin_python3_add_module_path(const gchar *module_path)
- PyObject *sys_path = NULL, *path = NULL;
- sys_path = PySys_GetObject("path");
- path = PyUnicode_FromString(module_path);
- if(PySequence_Contains(sys_path, path) == 0) {
- PyList_Insert(sys_path, 0, path);
-gplugin_python3_exception_to_gerror(void)
- PyObject *type = NULL, *value = NULL, *trace = NULL;
- PyObject *type_name = NULL, *value_str = NULL, *obj = NULL;
- PyErr_Fetch(&type, &value, &trace);
- PyErr_NormalizeException(&type, &value, &trace);
- type_name = PyObject_GetAttrString(type, "__name__");
- value_str = PyObject_Str(value);
- /* now decode the utf8 into a string we can use */
- obj = PyUnicode_AsUTF8String(type_name);
- obj = PyUnicode_AsUTF8String(value_str);
- PyBytes_AsString(type_name),
- PyBytes_AsString(value_str));
--- a/python/gplugin-python3-utils.h Sat Sep 05 20:27:32 2020 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
- * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
-#ifndef GPLUGIN_PYTHON3_UTILS_H
-#define GPLUGIN_PYTHON3_UTILS_H
-gchar *gplugin_python3_filename_to_module(const gchar *filename);
-gboolean gplugin_python3_add_module_path(const gchar *module_path);
-GError *gplugin_python3_exception_to_gerror(void);
-#endif /* GPLUGIN_PYTHON3_UTILS_H */
--- a/python/meson.build Sat Sep 05 20:27:32 2020 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-if get_option('python3')
- if not get_option('introspection')
- error('Python plugin requires GObject Introspection.')
- GPLUGIN_PYTHON3_SOURCES = [
- 'gplugin-python3-core.c',
- 'gplugin-python3-loader.c',
- 'gplugin-python3-plugin.c',
- 'gplugin-python3-utils.c',
- GPLUGIN_PYTHON3_HEADERS = [
- 'gplugin-python3-loader.h',
- 'gplugin-python3-plugin.h',
- 'gplugin-python3-utils.h',
- PYTHON3 = dependency('python3-embed', version: '>=3.5.0', required: false)
- PYTHON3 = dependency('python3', version: '>=3.5.0')
- PYGOBJECT = dependency('pygobject-3.0', version: '>=3.0.0')
- # Compile and run our python-gi test program
- python3_gi_test = compiler.run(files('gplugin-python3-test-pygobject.c'),
- dependencies : [GLIB, PYTHON3, PYGOBJECT],
- if not python3_gi_test.compiled() or python3_gi_test.returncode() != 0
- error('pygobject does not work with Python3')
- # Now add our libraries
- gplugin_python3_inc = include_directories('.')
- gplugin_python3 = shared_library('gplugin-python3',
- GPLUGIN_PYTHON3_SOURCES,
- GPLUGIN_PYTHON3_HEADERS,
- dependencies : [PYTHON3, PYGOBJECT, gplugin_dep],
- install_dir : get_option('libdir') / 'gplugin'
- gplugin_python3_dep = declare_dependency(
- include_directories : gplugin_python3_inc,
- link_with : gplugin_python3,
- gplugin_python3_static = static_library('gplugin-python3-static',
- GPLUGIN_PYTHON3_SOURCES,
- GPLUGIN_PYTHON3_HEADERS,
- dependencies : [PYTHON3, PYGOBJECT, gplugin_dep],
- gplugin_python3_static_dep = declare_dependency(
- include_directories : gplugin_python3_inc,
- link_with : gplugin_python3_static,
--- a/python/tests/meson.build Sat Sep 05 20:27:32 2020 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-if get_option('python3')
-e = executable('test-python3-loader', 'test-python3-loader.c',
- include_directories : include_directories('.'),
- '-DPYTHON3_LOADER_DIR="@0@/.."'.format(meson.current_build_dir()),
- '-DPYTHON3_PLUGIN_DIR="@0@/plugins"'.format(meson.current_source_dir()),
- link_with : gplugin_loader_tests,
- dependencies : [GLIB, GOBJECT, PYTHON3, PYGOBJECT, gplugin_dep])
-test('Python3 loader', e)
-# we can't see the symbols in gplugin-python externally, so use the static
-e = executable('test-python3-utils', 'test-python3-utils.c',
- include_directories : include_directories('.'),
- link_with : [gplugin_loader_tests],
- dependencies : [GLIB, GOBJECT, PYTHON3, PYGOBJECT,
- gplugin_python3_static_dep])
-test('Python3 utils', e)
--- a/python/tests/plugins/basic.py Sat Sep 05 20:27:32 2020 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-# Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, see <http://www.gnu.org/licenses/>.
-gi.require_version('GPlugin', '1.0')
-from gi.repository import GPlugin # noqa
- return GPlugin.PluginInfo(
- id='gplugin/python3-basic-plugin',
- abi_version=0x01020304,
- description='description',
-def gplugin_load(plugin):
-def gplugin_unload(plugin):
--- a/python/tests/plugins/dependent.py Sat Sep 05 20:27:32 2020 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-# Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, see <http://www.gnu.org/licenses/>.
-gi.require_version('GPlugin', '1.0')
-from gi.repository import GPlugin # noqa
- return GPlugin.PluginInfo(
- id='gplugin/python3-dependent-plugin',
- dependencies=['dependency1', 'dependency2'],
-def gplugin_load(plugin):
-def gplugin_unload(plugin):
--- a/python/tests/plugins/load-exception.py Sat Sep 05 20:27:32 2020 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-# Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, see <http://www.gnu.org/licenses/>.
-gi.require_version('GPlugin', '1.0')
-from gi.repository import GPlugin # noqa
- return GPlugin.PluginInfo(
- id="gplugin/python3-load-exception",
-def gplugin_load(plugin):
- raise ValueError('explosion!')
-def gplugin_unload(plugin):
--- a/python/tests/plugins/load-failed.py Sat Sep 05 20:27:32 2020 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-# Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, see <http://www.gnu.org/licenses/>.
-gi.require_version('GPlugin', '1.0')
-from gi.repository import GPlugin # noqa
- return GPlugin.PluginInfo(
- id="gplugin/python3-load-failed",
-def gplugin_load(plugin):
-def gplugin_unload(plugin):
--- a/python/tests/plugins/unload-failed.py Sat Sep 05 20:27:32 2020 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-# Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, see <http://www.gnu.org/licenses/>.
-gi.require_version('GPlugin', '1.0')
-from gi.repository import GPlugin # noqa
- return GPlugin.PluginInfo(
- id="gplugin/python3-unload-failed",
-def gplugin_load(plugin):
-def gplugin_unload(plugin):
--- a/python/tests/test-python3-loader.c Sat Sep 05 20:27:32 2020 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
- * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
-#include <gplugin/gplugin-loader-tests.h>
-/******************************************************************************
- *****************************************************************************/
-main(gint argc, gchar **argv)
- g_test_init(&argc, &argv, NULL);
- gplugin_loader_tests_main(
--- a/python/tests/test-python3-utils.c Sat Sep 05 20:27:32 2020 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
- * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
-#include "gplugin-python3-utils.h"
-/******************************************************************************
- * filename to module tests
- *****************************************************************************/
-test_filename_to_module_NULL_subprocess(void)
- gplugin_python3_filename_to_module(NULL);
-test_filename_to_module_NULL(void)
- g_test_trap_subprocess(
- "/loaders/python/utils/filename_to_module/NULL/subprocess",
- g_test_trap_assert_failed();
-test_filename_to_module_empty(void)
- gchar *module = gplugin_python3_filename_to_module("");
- g_assert_cmpstr(module, ==, "");
-test_filename_to_module_no_extension(void)
- gchar *module = gplugin_python3_filename_to_module("foo");
- g_assert_cmpstr(module, ==, "foo");
-/******************************************************************************
- *****************************************************************************/
-main(gint argc, gchar **argv)
- g_test_init(&argc, &argv, NULL);
- "/loaders/python/utils/filename_to_module/NULL",
- test_filename_to_module_NULL);
- "/loaders/python/utils/filename_to_module/NULL/subprocess",
- test_filename_to_module_NULL_subprocess);
- "/loaders/python/utils/filename_to_module/empty",
- test_filename_to_module_empty);
- "/loaders/python/utils/filename_to_module/no-extension",
- test_filename_to_module_no_extension);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python3/gplugin-python3-core.c Sat Sep 05 23:31:26 2020 -0500
@@ -0,0 +1,74 @@
+ * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com> + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. +#include <glib/gi18n-lib.h> +#include <gplugin-native.h> +#include "gplugin-python3-loader.h" +#include "gplugin-python3-plugin.h" +G_MODULE_EXPORT GPluginPluginInfo * +gplugin_query(G_GNUC_UNUSED GError **error) + /* clang-format-11 formats this correctly, so this can be removed then. */ + const gchar *const authors[] = { + "Gary Kramlich <grim@reaperworld.com>", + return gplugin_plugin_info_new( + "gplugin/python3-loader", + GPLUGIN_NATIVE_PLUGIN_ABI_VERSION, + "name", "Python Plugin Loader", + "version", GPLUGIN_VERSION, + "license-id", "LGPL-2.0-or-later", + "summary", "A plugin that can load python plugins", + "description", "This plugin allows the loading of plugins written in " + "the python programming language.", + "website", GPLUGIN_WEBSITE, +G_MODULE_EXPORT gboolean +gplugin_load(GPluginNativePlugin *plugin, G_GNUC_UNUSED GError **error) + gplugin_python3_plugin_register(plugin); + gplugin_python3_loader_register(plugin); + return gplugin_manager_register_loader(GPLUGIN_PYTHON3_TYPE_LOADER, error); +G_MODULE_EXPORT gboolean +gplugin_unload(G_GNUC_UNUSED GPluginNativePlugin *plugin, GError **error) + _("The Python loader can not be unloaded")); --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python3/gplugin-python3-loader.c Sat Sep 05 23:31:26 2020 -0500
@@ -0,0 +1,401 @@
+ * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com> + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. +#include "gplugin-python3-loader.h" +#include <glib/gi18n-lib.h> +#include "gplugin-python3-plugin.h" +#include "gplugin-python3-utils.h" +struct _GPluginPython3Loader { + PyThreadState *py_thread_state; + gplugin_python3_loader, +/****************************************************************************** + * GPluginLoader Implementation + *****************************************************************************/ +gplugin_python3_loader_supported_extensions(G_GNUC_UNUSED GPluginLoader *l) + return g_slist_append(NULL, "py"); +gplugin_python3_loader_query( + G_GNUC_UNUSED GError **error) + GPluginPlugin *plugin = NULL; + PyObject *pyinfo = NULL, *args = NULL; + PyObject *module = NULL, *package_list = NULL, *module_dict = NULL; + PyObject *query = NULL, *load = NULL, *unload = NULL; + PyGILState_STATE state; + gchar *module_name = NULL, *dir_name = NULL; + state = pyg_gil_state_ensure(); + /* create package_list as a tuple to handle 'import foo.bar' */ + package_list = PyTuple_New(0); + /* now figure out the module name from the filename */ + module_name = gplugin_python3_filename_to_module(filename); + /* grab the dirname since we need it on sys.path to import the module */ + dir_name = g_path_get_dirname(filename); + gplugin_python3_add_module_path(dir_name); + /* import the module */ + module = PyImport_ImportModuleEx(module_name, NULL, NULL, package_list); + g_warning(_("Failed to query %s"), filename); + /* clean some stuff up */ + Py_DECREF(package_list); + pyg_gil_state_release(state); + /* clean some stuff up */ + Py_DECREF(package_list); + /* at this point we have the module, lets find the query, load, and unload + module_dict = PyModule_GetDict(module); + query = PyDict_GetItemString(module_dict, "gplugin_query"); + _("Failed to find the gplugin_query function in %s"), + pyg_gil_state_release(state); + if(!PyCallable_Check(query)) { + _("Found gplugin_query in %s but it is not a " + pyg_gil_state_release(state); + load = PyDict_GetItemString(module_dict, "gplugin_load"); + _("Failed to find the gplugin_load function in %s"), + pyg_gil_state_release(state); + if(!PyCallable_Check(load)) { + _("Found gplugin_load in %s but it is not a " + pyg_gil_state_release(state); + unload = PyDict_GetItemString(module_dict, "gplugin_unload"); + _("Failed to find the gplugin_unload function in %s"), + pyg_gil_state_release(state); + if(!PyCallable_Check(unload)) { + _("Found gplugin_unload in %s but it is not a " + pyg_gil_state_release(state); + /* now that we have everything, call the query method and get the plugin's + pyinfo = PyObject_Call(query, args, NULL); + info = pygobject_get(pyinfo); + /* now that we have everything, create the plugin */ + GPLUGIN_PYTHON3_TYPE_PLUGIN, + pyg_gil_state_release(state); +gplugin_python3_loader_load( + G_GNUC_UNUSED GPluginLoader *loader, + PyObject *load = NULL, *pyplugin = NULL, *result = NULL; + g_object_get(G_OBJECT(plugin), "load-func", &load, NULL); + pyplugin = pygobject_new(G_OBJECT(plugin)); + result = PyObject_CallFunctionObjArgs(load, pyplugin, NULL); + *error = gplugin_python3_exception_to_gerror(); + ret = PyObject_IsTrue(result); + _("Failed to load plugin")); +gplugin_python3_loader_unload( + G_GNUC_UNUSED GPluginLoader *loader, + PyObject *unload = NULL, *pyplugin = NULL, *result = NULL; + g_object_get(G_OBJECT(plugin), "unload-func", &unload, NULL); + pyplugin = pygobject_new(G_OBJECT(plugin)); + result = PyObject_CallFunctionObjArgs(unload, pyplugin, NULL); + ret = PyObject_IsTrue(result); + _("Failed to unload plugin")); +/****************************************************************************** + *****************************************************************************/ +gplugin_python3_loader_init_pygobject(void) + pygobject_init(3, 0, 0); + PyObject *type = NULL, *value = NULL, *tb = NULL, *obj = NULL; + PyErr_Fetch(&type, &value, &tb); + obj = PyUnicode_AsUTF8String(value); + g_warning("Failed to initialize PyGObject : %s", PyBytes_AsString(obj)); + /* disable g_log redirections */ + pyg_disable_warning_redirections(); +gplugin_python3_loader_init_gettext(void) + PyObject *module_dict = NULL, *install = NULL; + PyObject *gettext = NULL, *result = NULL; + gettext = PyImport_ImportModule("gettext"); + g_warning("Failed to import gettext"); + module_dict = PyModule_GetDict(gettext); + install = PyDict_GetItemString(module_dict, "install"); + result = PyObject_CallFunction(install, "ss", GETTEXT_PACKAGE, LOCALEDIR); +gplugin_python3_loader_init_python(void) + wchar_t *argv[] = {NULL, NULL}; + /* Initializes Python */ + if(!Py_IsInitialized()) + Py_InitializeEx(FALSE); + argv[0] = Py_DecodeLocale(g_get_prgname(), NULL); + g_warning("Could not convert program name to wchar_t string."); + /* setup sys.path according to + * https://docs.python.org/3/c-api/init.html#PySys_SetArgvEx + PySys_SetArgvEx(1, argv, 0); + PyMem_RawFree(argv[0]); + /* initialize pygobject */ + if(gplugin_python3_loader_init_pygobject()) { + if(gplugin_python3_loader_init_gettext()) { +/****************************************************************************** + * GObject Implementation + *****************************************************************************/ +gplugin_python3_loader_init(G_GNUC_UNUSED GPluginPython3Loader *loader) +gplugin_python3_loader_class_finalize( + G_GNUC_UNUSED GPluginPython3LoaderClass *klass) +gplugin_python3_loader_class_init(GPluginPython3LoaderClass *klass) + GPluginLoaderClass *loader_class = GPLUGIN_LOADER_CLASS(klass); + loader_class->supported_extensions = + gplugin_python3_loader_supported_extensions; + loader_class->query = gplugin_python3_loader_query; + loader_class->load = gplugin_python3_loader_load; + loader_class->unload = gplugin_python3_loader_unload; +/****************************************************************************** + *****************************************************************************/ +gplugin_python3_loader_register(GPluginNativePlugin *native) + gplugin_python3_loader_register_type(G_TYPE_MODULE(native)); + gplugin_python3_loader_init_python(); --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python3/gplugin-python3-loader.h Sat Sep 05 23:31:26 2020 -0500
@@ -0,0 +1,38 @@
+ * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com> + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. +#ifndef GPLUGIN_PYTHON3_LOADER_H +#define GPLUGIN_PYTHON3_LOADER_H +#include <gplugin-native.h> +#define GPLUGIN_PYTHON3_TYPE_LOADER (gplugin_python3_loader_get_type()) + gplugin_python3_loader, +void gplugin_python3_loader_register(GPluginNativePlugin *native); +#endif /* GPLUGIN_PYTHON3_LOADER_H */ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python3/gplugin-python3-plugin.c Sat Sep 05 23:31:26 2020 -0500
@@ -0,0 +1,310 @@
+ * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com> + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. +#include "gplugin-python3-plugin.h" +/****************************************************************************** + *****************************************************************************/ +struct _GPluginPython3Plugin { + GPluginPluginInfo *info; + GPluginPluginState state; +/****************************************************************************** + *****************************************************************************/ + PROP_FILENAME = N_PROPERTIES, +static GParamSpec *properties[N_PROPERTIES] = { +/* I hate forward declarations... */ +static void gplugin_python3_plugin_iface_init(GPluginPluginInterface *iface); +G_DEFINE_DYNAMIC_TYPE_EXTENDED( + gplugin_python3_plugin, + gplugin_python3_plugin_iface_init)); +/****************************************************************************** + * GPluginPlugin Implementation + *****************************************************************************/ +gplugin_python3_plugin_iface_init(G_GNUC_UNUSED GPluginPluginInterface *iface) +/****************************************************************************** + *****************************************************************************/ +gplugin_python3_plugin_set_module( + GPluginPython3Plugin *plugin, + g_return_if_fail(GPLUGIN_IS_PLUGIN(plugin)); + g_return_if_fail(module); + Py_CLEAR(plugin->module); + plugin->module = module; +gplugin_python3_plugin_get_load_func(GPluginPython3Plugin *plugin) + g_return_val_if_fail(GPLUGIN_PYTHON3_IS_PLUGIN(plugin), NULL); +gplugin_python3_plugin_set_load_func( + GPluginPython3Plugin *plugin, + g_return_if_fail(GPLUGIN_PYTHON3_IS_PLUGIN(plugin)); + g_return_if_fail(func != NULL); + Py_CLEAR(plugin->load); +gplugin_python3_plugin_get_unload_func(GPluginPython3Plugin *plugin) + g_return_val_if_fail(GPLUGIN_PYTHON3_IS_PLUGIN(plugin), NULL); +gplugin_python3_plugin_set_unload_func( + GPluginPython3Plugin *plugin, + g_return_if_fail(GPLUGIN_PYTHON3_IS_PLUGIN(plugin)); + g_return_if_fail(func != NULL); + Py_CLEAR(plugin->unload); +/****************************************************************************** + * GObject Implementation + *****************************************************************************/ +gplugin_python3_plugin_get_property( + GPluginPython3Plugin *plugin = GPLUGIN_PYTHON3_PLUGIN(obj); + g_value_set_pointer(value, plugin->module); + gplugin_python3_plugin_get_load_func(plugin)); + gplugin_python3_plugin_get_unload_func(plugin)); + g_value_set_string(value, plugin->filename); + g_value_set_object(value, plugin->loader); + g_value_set_object(value, plugin->info); + g_value_set_enum(value, plugin->state); + g_value_set_boxed(value, plugin->error); + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); +gplugin_python3_plugin_set_property( + GPluginPython3Plugin *plugin = GPLUGIN_PYTHON3_PLUGIN(obj); + gplugin_python3_plugin_set_module( + g_value_get_pointer(value)); + gplugin_python3_plugin_set_load_func( + g_value_get_pointer(value)); + gplugin_python3_plugin_set_unload_func( + g_value_get_pointer(value)); + plugin->filename = g_value_dup_string(value); + plugin->loader = g_value_dup_object(value); + plugin->info = g_value_dup_object(value); + plugin->state = g_value_get_enum(value); + plugin->error = g_value_dup_boxed(value); + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); +gplugin_python3_plugin_finalize(GObject *obj) + GPluginPython3Plugin *plugin = GPLUGIN_PYTHON3_PLUGIN(obj); + Py_CLEAR(plugin->module); + Py_CLEAR(plugin->load); + Py_CLEAR(plugin->unload); + g_clear_pointer(&plugin->filename, g_free); + g_clear_object(&plugin->loader); + g_clear_object(&plugin->info); + g_clear_error(&plugin->error); + G_OBJECT_CLASS(gplugin_python3_plugin_parent_class)->finalize(obj); +gplugin_python3_plugin_init(G_GNUC_UNUSED GPluginPython3Plugin *plugin) +gplugin_python3_plugin_class_finalize( + G_GNUC_UNUSED GPluginPython3PluginClass *klass) +gplugin_python3_plugin_class_init(GPluginPython3PluginClass *klass) + GObjectClass *obj_class = G_OBJECT_CLASS(klass); + obj_class->get_property = gplugin_python3_plugin_get_property; + obj_class->set_property = gplugin_python3_plugin_set_property; + obj_class->finalize = gplugin_python3_plugin_finalize; + properties[PROP_MODULE] = g_param_spec_pointer( + "The python module object", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + properties[PROP_LOAD_FUNC] = g_param_spec_pointer( + "The python load function", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + properties[PROP_UNLOAD_FUNC] = g_param_spec_pointer( + "The python unload function", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_properties(obj_class, N_PROPERTIES, properties); + /* add our overrides */ + g_object_class_override_property(obj_class, PROP_FILENAME, "filename"); + g_object_class_override_property(obj_class, PROP_LOADER, "loader"); + g_object_class_override_property(obj_class, PROP_INFO, "info"); + g_object_class_override_property(obj_class, PROP_STATE, "state"); + g_object_class_override_property(obj_class, PROP_ERROR, "error"); +/****************************************************************************** + *****************************************************************************/ +gplugin_python3_plugin_register(GPluginNativePlugin *native) + gplugin_python3_plugin_register_type(G_TYPE_MODULE(native)); --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python3/gplugin-python3-plugin.h Sat Sep 05 23:31:26 2020 -0500
@@ -0,0 +1,38 @@
+ * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com> + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. +#ifndef GPLUGIN_PYTHON3_PLUGIN_H +#define GPLUGIN_PYTHON3_PLUGIN_H +#include <gplugin-native.h> +#define GPLUGIN_PYTHON3_TYPE_PLUGIN (gplugin_python3_plugin_get_type()) + gplugin_python3_plugin, +void gplugin_python3_plugin_register(GPluginNativePlugin *native); +#endif /* GPLUGIN_PYTHON3_PLUGIN_H */ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python3/gplugin-python3-test-pygobject.c Sat Sep 05 23:31:26 2020 -0500
@@ -0,0 +1,64 @@
+ * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com> + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. +main(gint argc, gchar *argv[]) + wchar_t *wargv[] = {NULL, NULL}; + /* initialize python */ + if(!Py_IsInitialized()) + Py_InitializeEx(FALSE); + len = mbstowcs(NULL, argv[0], 0); + if(len == (size_t)-1) { + printf("Failed to call mbstowcs to find length of argv[0]: %s\n", argv[0]); + wargv[0] = g_new0(wchar_t, len + 1); + len = mbstowcs(wargv[0], argv[0], len + 1); + if(len == (size_t)-1) { + printf("Failed to call mbstowcs to convert argv[0]: %s\n", argv[0]); + PySys_SetArgvEx(1, wargv, 0); + /* initialize pygobject */ + pygobject_init(3, 0, 0); + printf("Calling pygobject_init failed.\n"); --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python3/gplugin-python3-utils.c Sat Sep 05 23:31:26 2020 -0500
@@ -0,0 +1,117 @@
+ * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com> + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. +#include "gplugin-python3-utils.h" +gplugin_python3_filename_to_module(const gchar *filename) + gchar *e = NULL, *r = NULL; + g_return_val_if_fail(filename != NULL, NULL); + /* first make sure we just have a filename */ + base = g_path_get_basename(filename); + /* now find the last . for the extension */ + e = g_utf8_strrchr(base, g_utf8_strlen(base, -1), g_utf8_get_char(".")); + /* now copy the module name into r */ + r = g_malloc(e - base + 1); + memcpy(r, base, e - base); + /* free the basename */ +gplugin_python3_add_module_path(const gchar *module_path) + PyObject *sys_path = NULL, *path = NULL; + sys_path = PySys_GetObject("path"); + path = PyUnicode_FromString(module_path); + if(PySequence_Contains(sys_path, path) == 0) { + PyList_Insert(sys_path, 0, path); +gplugin_python3_exception_to_gerror(void) + PyObject *type = NULL, *value = NULL, *trace = NULL; + PyObject *type_name = NULL, *value_str = NULL, *obj = NULL; + PyErr_Fetch(&type, &value, &trace); + PyErr_NormalizeException(&type, &value, &trace); + type_name = PyObject_GetAttrString(type, "__name__"); + value_str = PyObject_Str(value); + /* now decode the utf8 into a string we can use */ + obj = PyUnicode_AsUTF8String(type_name); + obj = PyUnicode_AsUTF8String(value_str); + PyBytes_AsString(type_name), + PyBytes_AsString(value_str)); --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python3/gplugin-python3-utils.h Sat Sep 05 23:31:26 2020 -0500
@@ -0,0 +1,33 @@
+ * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com> + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. +#ifndef GPLUGIN_PYTHON3_UTILS_H +#define GPLUGIN_PYTHON3_UTILS_H +gchar *gplugin_python3_filename_to_module(const gchar *filename); +gboolean gplugin_python3_add_module_path(const gchar *module_path); +GError *gplugin_python3_exception_to_gerror(void); +#endif /* GPLUGIN_PYTHON3_UTILS_H */ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python3/meson.build Sat Sep 05 23:31:26 2020 -0500
@@ -0,0 +1,60 @@
+if get_option('python3') + if not get_option('introspection') + error('Python plugin requires GObject Introspection.') + GPLUGIN_PYTHON3_SOURCES = [ + 'gplugin-python3-core.c', + 'gplugin-python3-loader.c', + 'gplugin-python3-plugin.c', + 'gplugin-python3-utils.c', + GPLUGIN_PYTHON3_HEADERS = [ + 'gplugin-python3-loader.h', + 'gplugin-python3-plugin.h', + 'gplugin-python3-utils.h', + PYTHON3 = dependency('python3-embed', version: '>=3.5.0', required: false) + PYTHON3 = dependency('python3', version: '>=3.5.0') + PYGOBJECT = dependency('pygobject-3.0', version: '>=3.0.0') + # Compile and run our python-gi test program + python3_gi_test = compiler.run(files('gplugin-python3-test-pygobject.c'), + dependencies : [GLIB, PYTHON3, PYGOBJECT], + if not python3_gi_test.compiled() or python3_gi_test.returncode() != 0 + error('pygobject does not work with Python3') + # Now add our libraries + gplugin_python3_inc = include_directories('.') + gplugin_python3 = shared_library('gplugin-python3', + GPLUGIN_PYTHON3_SOURCES, + GPLUGIN_PYTHON3_HEADERS, + dependencies : [PYTHON3, PYGOBJECT, gplugin_dep], + install_dir : get_option('libdir') / 'gplugin' + gplugin_python3_dep = declare_dependency( + include_directories : gplugin_python3_inc, + link_with : gplugin_python3, + gplugin_python3_static = static_library('gplugin-python3-static', + GPLUGIN_PYTHON3_SOURCES, + GPLUGIN_PYTHON3_HEADERS, + dependencies : [PYTHON3, PYGOBJECT, gplugin_dep], + gplugin_python3_static_dep = declare_dependency( + include_directories : gplugin_python3_inc, + link_with : gplugin_python3_static, --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python3/tests/meson.build Sat Sep 05 23:31:26 2020 -0500
@@ -0,0 +1,22 @@
+if get_option('python3') +e = executable('test-python3-loader', 'test-python3-loader.c', + include_directories : include_directories('.'), + '-DPYTHON3_LOADER_DIR="@0@/.."'.format(meson.current_build_dir()), + '-DPYTHON3_PLUGIN_DIR="@0@/plugins"'.format(meson.current_source_dir()), + link_with : gplugin_loader_tests, + dependencies : [GLIB, GOBJECT, PYTHON3, PYGOBJECT, gplugin_dep]) +test('Python3 loader', e) +# we can't see the symbols in gplugin-python externally, so use the static +e = executable('test-python3-utils', 'test-python3-utils.c', + include_directories : include_directories('.'), + link_with : [gplugin_loader_tests], + dependencies : [GLIB, GOBJECT, PYTHON3, PYGOBJECT, + gplugin_python3_static_dep]) +test('Python3 utils', e) --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python3/tests/plugins/basic.py Sat Sep 05 23:31:26 2020 -0500
@@ -0,0 +1,43 @@
+# Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com> +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see <http://www.gnu.org/licenses/>. +gi.require_version('GPlugin', '1.0') +from gi.repository import GPlugin # noqa + return GPlugin.PluginInfo( + id='gplugin/python3-basic-plugin', + abi_version=0x01020304, + description='description', +def gplugin_load(plugin): +def gplugin_unload(plugin): --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python3/tests/plugins/dependent.py Sat Sep 05 23:31:26 2020 -0500
@@ -0,0 +1,35 @@
+# Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com> +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see <http://www.gnu.org/licenses/>. +gi.require_version('GPlugin', '1.0') +from gi.repository import GPlugin # noqa + return GPlugin.PluginInfo( + id='gplugin/python3-dependent-plugin', + dependencies=['dependency1', 'dependency2'], +def gplugin_load(plugin): +def gplugin_unload(plugin): --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python3/tests/plugins/load-exception.py Sat Sep 05 23:31:26 2020 -0500
@@ -0,0 +1,34 @@
+# Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com> +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see <http://www.gnu.org/licenses/>. +gi.require_version('GPlugin', '1.0') +from gi.repository import GPlugin # noqa + return GPlugin.PluginInfo( + id="gplugin/python3-load-exception", +def gplugin_load(plugin): + raise ValueError('explosion!') +def gplugin_unload(plugin): --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python3/tests/plugins/load-failed.py Sat Sep 05 23:31:26 2020 -0500
@@ -0,0 +1,34 @@
+# Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com> +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see <http://www.gnu.org/licenses/>. +gi.require_version('GPlugin', '1.0') +from gi.repository import GPlugin # noqa + return GPlugin.PluginInfo( + id="gplugin/python3-load-failed", +def gplugin_load(plugin): +def gplugin_unload(plugin): --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python3/tests/plugins/unload-failed.py Sat Sep 05 23:31:26 2020 -0500
@@ -0,0 +1,34 @@
+# Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com> +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see <http://www.gnu.org/licenses/>. +gi.require_version('GPlugin', '1.0') +from gi.repository import GPlugin # noqa + return GPlugin.PluginInfo( + id="gplugin/python3-unload-failed", +def gplugin_load(plugin): +def gplugin_unload(plugin): --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python3/tests/test-python3-loader.c Sat Sep 05 23:31:26 2020 -0500
@@ -0,0 +1,37 @@
+ * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com> + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. +#include <gplugin/gplugin-loader-tests.h> +/****************************************************************************** + *****************************************************************************/ +main(gint argc, gchar **argv) + g_test_init(&argc, &argv, NULL); + gplugin_loader_tests_main( --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python3/tests/test-python3-utils.c Sat Sep 05 23:31:26 2020 -0500
@@ -0,0 +1,87 @@
+ * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com> + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. +#include "gplugin-python3-utils.h" +/****************************************************************************** + * filename to module tests + *****************************************************************************/ +test_filename_to_module_NULL_subprocess(void) + gplugin_python3_filename_to_module(NULL); +test_filename_to_module_NULL(void) + g_test_trap_subprocess( + "/loaders/python/utils/filename_to_module/NULL/subprocess", + g_test_trap_assert_failed(); +test_filename_to_module_empty(void) + gchar *module = gplugin_python3_filename_to_module(""); + g_assert_cmpstr(module, ==, ""); +test_filename_to_module_no_extension(void) + gchar *module = gplugin_python3_filename_to_module("foo"); + g_assert_cmpstr(module, ==, "foo"); +/****************************************************************************** + *****************************************************************************/ +main(gint argc, gchar **argv) + g_test_init(&argc, &argv, NULL); + "/loaders/python/utils/filename_to_module/NULL", + test_filename_to_module_NULL); + "/loaders/python/utils/filename_to_module/NULL/subprocess", + test_filename_to_module_NULL_subprocess); + "/loaders/python/utils/filename_to_module/empty", + test_filename_to_module_empty); + "/loaders/python/utils/filename_to_module/no-extension", + test_filename_to_module_no_extension);