gplugin/gplugin

rename all of the python3 source files to have python3 in their name
feature/python3-naming
2020-02-22, Gary Kramlich
ce494367e404
Parents 0ccb96436622
Children 26051396614c
rename all of the python3 source files to have python3 in their name
--- a/python/gplugin-python-core.c Sat Feb 22 03:33:17 2020 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +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.h>
-#include <gplugin-native.h>
-
-#include <glib/gi18n-lib.h>
-
-#include "gplugin-python-loader.h"
-#include "gplugin-python-plugin.h"
-
-G_MODULE_EXPORT GPluginPluginInfo *
-gplugin_query(G_GNUC_UNUSED GError **error) {
- const gchar * const authors[] = {
- "Gary Kramlich <grim@reaperworld.com>",
- NULL
- };
-
- return gplugin_plugin_info_new(
- "gplugin/python3-loader",
- GPLUGIN_NATIVE_PLUGIN_ABI_VERSION,
- "internal", TRUE,
- "load-on-query", TRUE,
- "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.",
- "authors", authors,
- "website", GPLUGIN_WEBSITE,
- "category", "loaders",
- NULL
- );
-}
-
-G_MODULE_EXPORT gboolean
-gplugin_load(GPluginNativePlugin *plugin,
- G_GNUC_UNUSED GError **error)
-{
- gplugin_python_plugin_register(plugin);
- gplugin_python_loader_register(plugin);
-
- gplugin_manager_register_loader(GPLUGIN_PYTHON_TYPE_LOADER);
-
- return TRUE;
-}
-
-G_MODULE_EXPORT gboolean
-gplugin_unload(G_GNUC_UNUSED GPluginNativePlugin *plugin,
- GError **error)
-{
- g_set_error_literal(
- error,
- GPLUGIN_DOMAIN,
- 0,
- _("The Python loader can not be unloaded")
- );
-
- return FALSE;
-}
--- a/python/gplugin-python-loader.c Sat Feb 22 03:33:17 2020 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,373 +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 <Python.h>
-
-#include <stdlib.h>
-
-#include "gplugin-python-loader.h"
-
-#include "gplugin-python-plugin.h"
-#include "gplugin-python-utils.h"
-
-#include <glib/gi18n-lib.h>
-
-#include <pygobject.h>
-
-struct _GPluginPythonLoader {
- GPluginLoader parent;
-
- PyThreadState *py_thread_state;
- guint gc_id;
-};
-
-G_DEFINE_DYNAMIC_TYPE(GPluginPythonLoader, gplugin_python_loader, GPLUGIN_TYPE_LOADER);
-
-/******************************************************************************
- * GPluginLoader Implementation
- *****************************************************************************/
-static GSList *
-gplugin_python_loader_class_supported_extensions(G_GNUC_UNUSED GPluginLoaderClass *klass) {
- return g_slist_append(NULL, "py");
-}
-
-static GPluginPlugin *
-gplugin_python_loader_query(GPluginLoader *loader,
- const gchar *filename,
- G_GNUC_UNUSED GError **error)
-{
- GPluginPlugin *plugin = NULL;
- GObject *info = 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;
-
- /* lock the gil */
- 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_python_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_python_add_module_path(dir_name);
- g_free(dir_name);
-
- /* import the module */
- module = PyImport_ImportModuleEx(module_name, NULL, NULL, package_list);
- if(PyErr_Occurred()) {
- g_warning(_("Failed to query %s"), filename);
- PyErr_Print();
-
- /* clean some stuff up */
- g_free(module_name);
- Py_DECREF(package_list);
-
- pyg_gil_state_release(state);
-
- return NULL;
- }
-
- /* clean some stuff up */
- g_free(module_name);
- Py_DECREF(package_list);
-
- /* at this point we have the module, lets find the query, load, and unload
- * functions.
- */
- module_dict = PyModule_GetDict(module);
-
- query = PyDict_GetItemString(module_dict, "gplugin_query");
- if(query == NULL) {
- g_warning(_("Failed to find the gplugin_query function in %s"),
- filename);
-
- Py_DECREF(module);
- pyg_gil_state_release(state);
-
- return NULL;
- }
- if(!PyCallable_Check(query)) {
- g_warning(_("Found gplugin_query in %s but it is not a "
- "function"),
- filename);
-
- Py_DECREF(module);
- pyg_gil_state_release(state);
-
- return NULL;
- }
-
- load = PyDict_GetItemString(module_dict, "gplugin_load");
- if(load == NULL) {
- g_warning(_("Failed to find the gplugin_load function in %s"),
- filename);
-
- Py_DECREF(module);
- pyg_gil_state_release(state);
-
- return NULL;
- }
- if(!PyCallable_Check(load)) {
- g_warning(_("Found gplugin_load in %s but it is not a "
- "function"),
- filename);
-
- Py_DECREF(module);
- pyg_gil_state_release(state);
-
- return NULL;
- }
-
- unload = PyDict_GetItemString(module_dict, "gplugin_unload");
- if(unload == NULL) {
- g_warning(_("Failed to find the gplugin_unload function in %s"),
- filename);
-
- Py_DECREF(module);
- pyg_gil_state_release(state);
-
- return NULL;
- }
- if(!PyCallable_Check(unload)) {
- g_warning(_("Found gplugin_unload in %s but it is not a "
- "function"),
- filename);
-
- Py_DECREF(module);
- pyg_gil_state_release(state);
-
- return NULL;
- }
-
- /* now that we have everything, call the query method and get the plugin's
- * info.
- */
- args = PyTuple_New(0);
- pyinfo = PyObject_Call(query, args, NULL);
- Py_DECREF(args);
-
- info = pygobject_get(pyinfo);
-
- /* now that we have everything, create the plugin */
- plugin = g_object_new(GPLUGIN_PYTHON_TYPE_PLUGIN,
- "filename", filename,
- "loader", loader,
- "module", module,
- "info", info,
- "load-func", load,
- "unload-func", unload,
- NULL);
-
- Py_DECREF(pyinfo);
- Py_DECREF(module);
-
- /* unlock the gil */
- pyg_gil_state_release(state);
-
- return plugin;
-}
-
-static gboolean
-gplugin_python_loader_load(G_GNUC_UNUSED GPluginLoader *loader,
- GPluginPlugin *plugin,
- GError **error)
-{
- PyObject *load = NULL, *pyplugin = NULL, *result = NULL;
- gboolean ret = FALSE;
-
- g_object_get(G_OBJECT(plugin), "load-func", &load, NULL);
-
- pyplugin = pygobject_new(G_OBJECT(plugin));
-
- result = PyObject_CallFunctionObjArgs(load, pyplugin, NULL);
- Py_DECREF(pyplugin);
-
- if (PyErr_Occurred()) {
- Py_XDECREF(result);
-
- if (error) {
- *error = gplugin_python_exception_to_gerror();
- }
-
- return FALSE;
- }
-
- ret = PyObject_IsTrue(result);
- Py_DECREF(result);
-
- if(!ret) {
- g_set_error_literal(error, GPLUGIN_DOMAIN, 0,
- _("Failed to load plugin"));
- }
-
- return ret;
-}
-
-static gboolean
-gplugin_python_loader_unload(G_GNUC_UNUSED GPluginLoader *loader,
- GPluginPlugin *plugin,
- GError **error)
-{
- PyObject *unload = NULL, *pyplugin = NULL, *result = NULL;
- gboolean ret = FALSE;
-
- g_object_get(G_OBJECT(plugin), "unload-func", &unload, NULL);
-
- pyplugin = pygobject_new(G_OBJECT(plugin));
-
- result = PyObject_CallFunctionObjArgs(unload, pyplugin, NULL);
- Py_DECREF(pyplugin);
-
- if(PyErr_Occurred()) {
- PyErr_Print();
-
- Py_XDECREF(result);
-
- return FALSE;
- }
-
- ret = PyObject_IsTrue(result);
- Py_DECREF(result);
-
- if(!ret) {
- g_set_error_literal(error, GPLUGIN_DOMAIN, 0,
- _("Failed to unload plugin"));
- }
-
- return ret;
-}
-
-/******************************************************************************
- * Python Stuff
- *****************************************************************************/
-static gboolean
-gplugin_python_loader_init_pygobject(void) {
- pygobject_init(3, 0, 0);
- if(PyErr_Occurred()) {
- PyObject *type = NULL, *value = NULL, *tb = NULL, *obj = NULL;
-
- PyErr_Fetch(&type, &value, &tb);
- Py_DECREF(type);
- Py_XDECREF(tb);
-
- obj = PyUnicode_AsUTF8String(value);
- Py_DECREF(value);
-
- g_warning("Failed to initialize PyGObject : %s", PyBytes_AsString(obj));
- Py_DECREF(obj);
-
- return FALSE;
- }
-
- /* enable threads */
- pyg_enable_threads();
-
- /* disable g_log redirections */
- pyg_disable_warning_redirections();
-
- return TRUE;
-}
-
-static gboolean
-gplugin_python_loader_init_gettext(void) {
- PyObject *module_dict = NULL, *install = NULL;
- PyObject *gettext = NULL, *result = NULL;
-
- gettext = PyImport_ImportModule("gettext");
- if(gettext == NULL) {
- g_warning("Failed to import gettext");
-
- return FALSE;
- }
-
- module_dict = PyModule_GetDict(gettext);
- install = PyDict_GetItemString(module_dict, "install");
- result = PyObject_CallFunction(install, "ss", GETTEXT_PACKAGE, LOCALEDIR);
- Py_XDECREF(result);
- Py_DECREF(gettext);
-
- return TRUE;
-}
-
-static gboolean
-gplugin_python_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);
- if(argv[0] == NULL) {
- g_warning("Could not convert program name to wchar_t string.");
- return FALSE;
- }
-
- /* 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_python_loader_init_pygobject()) {
- if(gplugin_python_loader_init_gettext()) {
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-/******************************************************************************
- * Object Stuff
- *****************************************************************************/
-static void
-gplugin_python_loader_init(G_GNUC_UNUSED GPluginPythonLoader *loader) {
-}
-
-static void
-gplugin_python_loader_class_finalize(G_GNUC_UNUSED GPluginPythonLoaderClass *klass)
-{
-}
-
-static void
-gplugin_python_loader_class_init(GPluginPythonLoaderClass *klass) {
- GPluginLoaderClass *loader_class = GPLUGIN_LOADER_CLASS(klass);
-
- loader_class->supported_extensions =
- gplugin_python_loader_class_supported_extensions;
- loader_class->query = gplugin_python_loader_query;
- loader_class->load = gplugin_python_loader_load;
- loader_class->unload = gplugin_python_loader_unload;
-}
-
-/******************************************************************************
- * API
- *****************************************************************************/
-void
-gplugin_python_loader_register(GPluginNativePlugin *native) {
- gplugin_python_loader_register_type(G_TYPE_MODULE(native));
-
- gplugin_python_loader_init_python();
-}
--- a/python/gplugin-python-loader.h Sat Feb 22 03:33:17 2020 -0600
+++ /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_PYTHON_LOADER_H
-#define GPLUGIN_PYTHON_LOADER_H
-
-#include <gplugin.h>
-#include <gplugin-native.h>
-
-G_BEGIN_DECLS
-
-#define GPLUGIN_PYTHON_TYPE_LOADER (gplugin_python_loader_get_type())
-G_DECLARE_FINAL_TYPE(GPluginPythonLoader, gplugin_python_loader, GPLUGIN_PYTHON, LOADER, GPluginLoader)
-
-void gplugin_python_loader_register(GPluginNativePlugin *native);
-
-G_END_DECLS
-
-#endif /* GPLUGIN_PYTHON_LOADER_H */
--- a/python/gplugin-python-plugin.c Sat Feb 22 03:33:17 2020 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,277 +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 <Python.h>
-
-#include "gplugin-python-plugin.h"
-
-#include <pygobject.h>
-
-/******************************************************************************
- * Typedefs
- *****************************************************************************/
-struct _GPluginPythonPlugin {
- GObject parent;
-
- PyObject *module;
- PyObject *query;
- PyObject *load;
- PyObject *unload;
-
- /* overrides */
- gchar *filename;
- GPluginLoader *loader;
- GPluginPluginInfo *info;
- GPluginPluginState state;
-};
-
-/******************************************************************************
- * Enums
- *****************************************************************************/
-enum {
- PROP_ZERO,
- PROP_MODULE,
- PROP_LOAD_FUNC,
- PROP_UNLOAD_FUNC,
- N_PROPERTIES,
- /* overrides */
- PROP_FILENAME = N_PROPERTIES,
- PROP_LOADER,
- PROP_INFO,
- PROP_STATE
-};
-static GParamSpec *properties[N_PROPERTIES] = {NULL,};
-
-/* I hate forward declarations... */
-static void gplugin_python_plugin_iface_init(GPluginPluginInterface *iface);
-
-G_DEFINE_DYNAMIC_TYPE_EXTENDED(
- GPluginPythonPlugin,
- gplugin_python_plugin,
- G_TYPE_OBJECT,
- 0,
- G_IMPLEMENT_INTERFACE(GPLUGIN_TYPE_PLUGIN, gplugin_python_plugin_iface_init)
-);
-
-/******************************************************************************
- * GPluginPlugin Implementation
- *****************************************************************************/
-static void
-gplugin_python_plugin_iface_init(G_GNUC_UNUSED GPluginPluginInterface *iface) {
-}
-
-/******************************************************************************
- * Private Stuff
- *****************************************************************************/
-static void
-gplugin_python_plugin_set_module(GPluginPythonPlugin *plugin,
- PyObject *module)
-{
- g_return_if_fail(GPLUGIN_IS_PLUGIN(plugin));
- g_return_if_fail(module);
-
- Py_XINCREF(module);
- Py_CLEAR(plugin->module);
- plugin->module = module;
-}
-
-static gpointer
-gplugin_python_plugin_get_load_func(GPluginPythonPlugin *plugin) {
- g_return_val_if_fail(GPLUGIN_PYTHON_IS_PLUGIN(plugin), NULL);
-
- return plugin->load;
-}
-
-static void
-gplugin_python_plugin_set_load_func(GPluginPythonPlugin *plugin,
- PyObject *func)
-{
- g_return_if_fail(GPLUGIN_PYTHON_IS_PLUGIN(plugin));
- g_return_if_fail(func != NULL);
-
- Py_XINCREF(func);
- Py_CLEAR(plugin->load);
- plugin->load = func;
-}
-
-static gpointer
-gplugin_python_plugin_get_unload_func(GPluginPythonPlugin *plugin) {
- g_return_val_if_fail(GPLUGIN_PYTHON_IS_PLUGIN(plugin), NULL);
-
- return plugin->unload;
-}
-
-static void
-gplugin_python_plugin_set_unload_func(GPluginPythonPlugin *plugin,
- PyObject *func)
-{
- g_return_if_fail(GPLUGIN_PYTHON_IS_PLUGIN(plugin));
- g_return_if_fail(func != NULL);
-
- Py_XINCREF(func);
- Py_CLEAR(plugin->unload);
- plugin->unload = func;
-}
-
-/******************************************************************************
- * Object Stuff
- *****************************************************************************/
-static void
-gplugin_python_plugin_get_property(GObject *obj, guint param_id, GValue *value,
- GParamSpec *pspec)
-{
- GPluginPythonPlugin *plugin = GPLUGIN_PYTHON_PLUGIN(obj);
-
- switch(param_id) {
- case PROP_MODULE:
- g_value_set_pointer(value, plugin->module);
- break;
- case PROP_LOAD_FUNC:
- g_value_set_pointer(value,
- gplugin_python_plugin_get_load_func(plugin));
- break;
- case PROP_UNLOAD_FUNC:
- g_value_set_pointer(value,
- gplugin_python_plugin_get_unload_func(plugin));
- break;
-
- /* overrides */
- case PROP_FILENAME:
- g_value_set_string(value, plugin->filename);
- break;
- case PROP_LOADER:
- g_value_set_object(value, plugin->loader);
- break;
- case PROP_INFO:
- g_value_set_object(value, plugin->info);
- break;
- case PROP_STATE:
- g_value_set_enum(value, plugin->state);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
- break;
- }
-}
-
-static void
-gplugin_python_plugin_set_property(GObject *obj, guint param_id,
- const GValue *value, GParamSpec *pspec)
-{
- GPluginPythonPlugin *plugin = GPLUGIN_PYTHON_PLUGIN(obj);
-
- switch(param_id) {
- case PROP_MODULE:
- gplugin_python_plugin_set_module(plugin,
- g_value_get_pointer(value));
- break;
- case PROP_LOAD_FUNC:
- gplugin_python_plugin_set_load_func(plugin,
- g_value_get_pointer(value));
- break;
- case PROP_UNLOAD_FUNC:
- gplugin_python_plugin_set_unload_func(plugin,
- g_value_get_pointer(value));
- break;
-
- /* overrides */
- case PROP_FILENAME:
- plugin->filename = g_value_dup_string(value);
- break;
- case PROP_LOADER:
- plugin->loader = g_value_dup_object(value);
- break;
- case PROP_INFO:
- plugin->info = g_value_dup_object(value);
- break;
- case PROP_STATE:
- plugin->state = g_value_get_enum(value);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
- break;
- }
-}
-
-static void
-gplugin_python_plugin_finalize(GObject *obj) {
- GPluginPythonPlugin *plugin = GPLUGIN_PYTHON_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_OBJECT_CLASS(gplugin_python_plugin_parent_class)->finalize(obj);
-}
-
-static void
-gplugin_python_plugin_init(G_GNUC_UNUSED GPluginPythonPlugin *plugin) {
-}
-
-static void
-gplugin_python_plugin_class_finalize(G_GNUC_UNUSED GPluginPythonPluginClass *klass)
-{
-}
-
-static void
-gplugin_python_plugin_class_init(GPluginPythonPluginClass *klass) {
- GObjectClass *obj_class = G_OBJECT_CLASS(klass);
-
- obj_class->get_property = gplugin_python_plugin_get_property;
- obj_class->set_property = gplugin_python_plugin_set_property;
- obj_class->finalize = gplugin_python_plugin_finalize;
-
- properties[PROP_MODULE] = g_param_spec_pointer(
- "module", "module",
- "The python module object",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY
- );
-
- properties[PROP_LOAD_FUNC] = g_param_spec_pointer(
- "load-func", "load-func",
- "The python load function",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY
- );
-
- properties[PROP_UNLOAD_FUNC] = g_param_spec_pointer(
- "unload-func", "unload-func",
- "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");
-}
-
-/******************************************************************************
- * API
- *****************************************************************************/
-void
-gplugin_python_plugin_register(GPluginNativePlugin *native) {
- gplugin_python_plugin_register_type(G_TYPE_MODULE(native));
-}
--- a/python/gplugin-python-plugin.h Sat Feb 22 03:33:17 2020 -0600
+++ /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_PYTHON_PLUGIN_H
-#define GPLUGIN_PYTHON_PLUGIN_H
-
-#include <gplugin.h>
-#include <gplugin-native.h>
-
-G_BEGIN_DECLS
-
-#define GPLUGIN_PYTHON_TYPE_PLUGIN (gplugin_python_plugin_get_type())
-G_DECLARE_FINAL_TYPE(GPluginPythonPlugin, gplugin_python_plugin, GPLUGIN_PYTHON, PLUGIN, GObject)
-
-void gplugin_python_plugin_register(GPluginNativePlugin *native);
-
-G_END_DECLS
-
-#endif /* GPLUGIN_PYTHON_PLUGIN_H */
--- a/python/gplugin-python-test-pygobject.c Sat Feb 22 03:33:17 2020 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +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 <stdio.h>
-
-#include <glib.h>
-
-#include <Python.h>
-
-#include <pygobject.h>
-
-gint
-main(gint argc, gchar *argv[]) {
- wchar_t *wargv[] = { NULL, NULL };
- size_t len;
-
- /* initialize python */
- if(!Py_IsInitialized())
- Py_InitializeEx(FALSE);
-
- /* setup wargv */
- len = mbstowcs(NULL, argv[0], 0);
- if(len == (size_t)-1)
- return -1;
-
- wargv[0] = g_new0(wchar_t, len + 1);
- len = mbstowcs(wargv[0], argv[0], len + 1);
- if(len == (size_t)-1) {
- g_free(wargv[0]);
- return -1;
- }
-
- /* setup sys.path */
-#if PY_VERSION_HEX < 0x03010300
- PySys_SetArgv(1, wargv);
- PyRun_SimpleString("import sys; sys.path.pop(0)\n");
-#else
- PySys_SetArgvEx(1, wargv, 0);
-#endif
-
- g_free(wargv[0]);
-
- /* initialize pygobject */
- pygobject_init(3, 0, 0);
- if(PyErr_Occurred()) {
- PyErr_Print();
- return -1;
- }
-
- return 0;
-}
--- a/python/gplugin-python-utils.c Sat Feb 22 03:33:17 2020 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +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 <Python.h>
-
-#include <gplugin/gplugin.h>
-
-#include "gplugin-python-utils.h"
-
-#include <string.h>
-
-gchar *
-gplugin_python_filename_to_module(const gchar *filename) {
- gchar *base = NULL;
- 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("."));
- if(e == NULL) {
- return base;
- }
-
- /* now copy the module name into r */
- r = g_malloc(e - base + 1);
- memcpy(r, base, e - base);
- r[e - base] = 0;
-
- /* free the basename */
- g_free(base);
-
- return r;
-}
-
-gboolean
-gplugin_python_add_module_path(const gchar *module_path) {
- PyObject *sys_path = NULL, *path = NULL;
- gboolean ret = FALSE;
-
- sys_path = PySys_GetObject("path");
-
- path = PyUnicode_FromString(module_path);
-
- if(PySequence_Contains(sys_path, path) == 0) {
- PyList_Insert(sys_path, 0, path);
- ret = TRUE;
- }
-
- Py_DECREF(path);
-
- return ret;
-}
-
-GError *
-gplugin_python_exception_to_gerror(void) {
- GError *error = NULL;
- PyObject *type = NULL, *value = NULL, *trace = NULL;
- PyObject *type_name = NULL, *value_str = NULL, *obj = NULL;
-
- if(!PyErr_Occurred())
- return NULL;
-
- PyErr_Fetch(&type, &value, &trace);
- if(type == NULL)
- return NULL;
-
- PyErr_NormalizeException(&type, &value, &trace);
- Py_XDECREF(trace);
-
- type_name = PyObject_GetAttrString(type, "__name__");
- Py_DECREF(type);
-
- value_str = PyObject_Str(value);
- Py_DECREF(value);
-
- /* now decode the utf8 into a string we can use */
- obj = PyUnicode_AsUTF8String(type_name);
- Py_DECREF(type_name);
- type_name = obj;
-
- obj = PyUnicode_AsUTF8String(value_str);
- Py_DECREF(value_str);
- value_str = obj;
-
- error = g_error_new(GPLUGIN_DOMAIN, 0, "%s: %s",
- PyBytes_AsString(type_name),
- PyBytes_AsString(value_str));
-
- Py_DECREF(type_name);
- Py_DECREF(value_str);
-
- return error;
-}
--- a/python/gplugin-python-utils.h Sat Feb 22 03:33:17 2020 -0600
+++ /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/>.
- */
-
-#ifndef GPLUGIN_PYTHON_UTILS_H
-#define GPLUGIN_PYTHON_UTILS_H
-
-#include <glib.h>
-
-#define GPLUGIN_PYTHON_DOMAIN (g_quark_from_static_string("gplugin-python"))
-
-G_BEGIN_DECLS
-
-gchar *gplugin_python_filename_to_module(const gchar *filename);
-
-gboolean gplugin_python_add_module_path(const gchar *module_path);
-
-GError *gplugin_python_exception_to_gerror(void);
-
-G_END_DECLS
-
-#endif /* GPLUGIN_PYTHON_UTILS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python/gplugin-python3-core.c Sat Feb 22 03:41:23 2020 -0600
@@ -0,0 +1,75 @@
+/*
+ * 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.h>
+#include <gplugin-native.h>
+
+#include <glib/gi18n-lib.h>
+
+#include "gplugin-python3-loader.h"
+#include "gplugin-python3-plugin.h"
+
+G_MODULE_EXPORT GPluginPluginInfo *
+gplugin_query(G_GNUC_UNUSED GError **error) {
+ const gchar * const authors[] = {
+ "Gary Kramlich <grim@reaperworld.com>",
+ NULL
+ };
+
+ return gplugin_plugin_info_new(
+ "gplugin/python3-loader",
+ GPLUGIN_NATIVE_PLUGIN_ABI_VERSION,
+ "internal", TRUE,
+ "load-on-query", TRUE,
+ "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.",
+ "authors", authors,
+ "website", GPLUGIN_WEBSITE,
+ "category", "loaders",
+ NULL
+ );
+}
+
+G_MODULE_EXPORT gboolean
+gplugin_load(GPluginNativePlugin *plugin,
+ G_GNUC_UNUSED GError **error)
+{
+ gplugin_python_plugin_register(plugin);
+ gplugin_python_loader_register(plugin);
+
+ gplugin_manager_register_loader(GPLUGIN_PYTHON_TYPE_LOADER);
+
+ return TRUE;
+}
+
+G_MODULE_EXPORT gboolean
+gplugin_unload(G_GNUC_UNUSED GPluginNativePlugin *plugin,
+ GError **error)
+{
+ g_set_error_literal(
+ error,
+ GPLUGIN_DOMAIN,
+ 0,
+ _("The Python loader can not be unloaded")
+ );
+
+ return FALSE;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python/gplugin-python3-loader.c Sat Feb 22 03:41:23 2020 -0600
@@ -0,0 +1,373 @@
+/*
+ * 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 <Python.h>
+
+#include <stdlib.h>
+
+#include "gplugin-python3-loader.h"
+
+#include "gplugin-python3-plugin.h"
+#include "gplugin-python3-utils.h"
+
+#include <glib/gi18n-lib.h>
+
+#include <pygobject.h>
+
+struct _GPluginPythonLoader {
+ GPluginLoader parent;
+
+ PyThreadState *py_thread_state;
+ guint gc_id;
+};
+
+G_DEFINE_DYNAMIC_TYPE(GPluginPythonLoader, gplugin_python_loader, GPLUGIN_TYPE_LOADER);
+
+/******************************************************************************
+ * GPluginLoader Implementation
+ *****************************************************************************/
+static GSList *
+gplugin_python_loader_class_supported_extensions(G_GNUC_UNUSED GPluginLoaderClass *klass) {
+ return g_slist_append(NULL, "py");
+}
+
+static GPluginPlugin *
+gplugin_python_loader_query(GPluginLoader *loader,
+ const gchar *filename,
+ G_GNUC_UNUSED GError **error)
+{
+ GPluginPlugin *plugin = NULL;
+ GObject *info = 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;
+
+ /* lock the gil */
+ 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_python_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_python_add_module_path(dir_name);
+ g_free(dir_name);
+
+ /* import the module */
+ module = PyImport_ImportModuleEx(module_name, NULL, NULL, package_list);
+ if(PyErr_Occurred()) {
+ g_warning(_("Failed to query %s"), filename);
+ PyErr_Print();
+
+ /* clean some stuff up */
+ g_free(module_name);
+ Py_DECREF(package_list);
+
+ pyg_gil_state_release(state);
+
+ return NULL;
+ }
+
+ /* clean some stuff up */
+ g_free(module_name);
+ Py_DECREF(package_list);
+
+ /* at this point we have the module, lets find the query, load, and unload
+ * functions.
+ */
+ module_dict = PyModule_GetDict(module);
+
+ query = PyDict_GetItemString(module_dict, "gplugin_query");
+ if(query == NULL) {
+ g_warning(_("Failed to find the gplugin_query function in %s"),
+ filename);
+
+ Py_DECREF(module);
+ pyg_gil_state_release(state);
+
+ return NULL;
+ }
+ if(!PyCallable_Check(query)) {
+ g_warning(_("Found gplugin_query in %s but it is not a "
+ "function"),
+ filename);
+
+ Py_DECREF(module);
+ pyg_gil_state_release(state);
+
+ return NULL;
+ }
+
+ load = PyDict_GetItemString(module_dict, "gplugin_load");
+ if(load == NULL) {
+ g_warning(_("Failed to find the gplugin_load function in %s"),
+ filename);
+
+ Py_DECREF(module);
+ pyg_gil_state_release(state);
+
+ return NULL;
+ }
+ if(!PyCallable_Check(load)) {
+ g_warning(_("Found gplugin_load in %s but it is not a "
+ "function"),
+ filename);
+
+ Py_DECREF(module);
+ pyg_gil_state_release(state);
+
+ return NULL;
+ }
+
+ unload = PyDict_GetItemString(module_dict, "gplugin_unload");
+ if(unload == NULL) {
+ g_warning(_("Failed to find the gplugin_unload function in %s"),
+ filename);
+
+ Py_DECREF(module);
+ pyg_gil_state_release(state);
+
+ return NULL;
+ }
+ if(!PyCallable_Check(unload)) {
+ g_warning(_("Found gplugin_unload in %s but it is not a "
+ "function"),
+ filename);
+
+ Py_DECREF(module);
+ pyg_gil_state_release(state);
+
+ return NULL;
+ }
+
+ /* now that we have everything, call the query method and get the plugin's
+ * info.
+ */
+ args = PyTuple_New(0);
+ pyinfo = PyObject_Call(query, args, NULL);
+ Py_DECREF(args);
+
+ info = pygobject_get(pyinfo);
+
+ /* now that we have everything, create the plugin */
+ plugin = g_object_new(GPLUGIN_PYTHON_TYPE_PLUGIN,
+ "filename", filename,
+ "loader", loader,
+ "module", module,
+ "info", info,
+ "load-func", load,
+ "unload-func", unload,
+ NULL);
+
+ Py_DECREF(pyinfo);
+ Py_DECREF(module);
+
+ /* unlock the gil */
+ pyg_gil_state_release(state);
+
+ return plugin;
+}
+
+static gboolean
+gplugin_python_loader_load(G_GNUC_UNUSED GPluginLoader *loader,
+ GPluginPlugin *plugin,
+ GError **error)
+{
+ PyObject *load = NULL, *pyplugin = NULL, *result = NULL;
+ gboolean ret = FALSE;
+
+ g_object_get(G_OBJECT(plugin), "load-func", &load, NULL);
+
+ pyplugin = pygobject_new(G_OBJECT(plugin));
+
+ result = PyObject_CallFunctionObjArgs(load, pyplugin, NULL);
+ Py_DECREF(pyplugin);
+
+ if (PyErr_Occurred()) {
+ Py_XDECREF(result);
+
+ if (error) {
+ *error = gplugin_python_exception_to_gerror();
+ }
+
+ return FALSE;
+ }
+
+ ret = PyObject_IsTrue(result);
+ Py_DECREF(result);
+
+ if(!ret) {
+ g_set_error_literal(error, GPLUGIN_DOMAIN, 0,
+ _("Failed to load plugin"));
+ }
+
+ return ret;
+}
+
+static gboolean
+gplugin_python_loader_unload(G_GNUC_UNUSED GPluginLoader *loader,
+ GPluginPlugin *plugin,
+ GError **error)
+{
+ PyObject *unload = NULL, *pyplugin = NULL, *result = NULL;
+ gboolean ret = FALSE;
+
+ g_object_get(G_OBJECT(plugin), "unload-func", &unload, NULL);
+
+ pyplugin = pygobject_new(G_OBJECT(plugin));
+
+ result = PyObject_CallFunctionObjArgs(unload, pyplugin, NULL);
+ Py_DECREF(pyplugin);
+
+ if(PyErr_Occurred()) {
+ PyErr_Print();
+
+ Py_XDECREF(result);
+
+ return FALSE;
+ }
+
+ ret = PyObject_IsTrue(result);
+ Py_DECREF(result);
+
+ if(!ret) {
+ g_set_error_literal(error, GPLUGIN_DOMAIN, 0,
+ _("Failed to unload plugin"));
+ }
+
+ return ret;
+}
+
+/******************************************************************************
+ * Python Stuff
+ *****************************************************************************/
+static gboolean
+gplugin_python_loader_init_pygobject(void) {
+ pygobject_init(3, 0, 0);
+ if(PyErr_Occurred()) {
+ PyObject *type = NULL, *value = NULL, *tb = NULL, *obj = NULL;
+
+ PyErr_Fetch(&type, &value, &tb);
+ Py_DECREF(type);
+ Py_XDECREF(tb);
+
+ obj = PyUnicode_AsUTF8String(value);
+ Py_DECREF(value);
+
+ g_warning("Failed to initialize PyGObject : %s", PyBytes_AsString(obj));
+ Py_DECREF(obj);
+
+ return FALSE;
+ }
+
+ /* enable threads */
+ pyg_enable_threads();
+
+ /* disable g_log redirections */
+ pyg_disable_warning_redirections();
+
+ return TRUE;
+}
+
+static gboolean
+gplugin_python_loader_init_gettext(void) {
+ PyObject *module_dict = NULL, *install = NULL;
+ PyObject *gettext = NULL, *result = NULL;
+
+ gettext = PyImport_ImportModule("gettext");
+ if(gettext == NULL) {
+ g_warning("Failed to import gettext");
+
+ return FALSE;
+ }
+
+ module_dict = PyModule_GetDict(gettext);
+ install = PyDict_GetItemString(module_dict, "install");
+ result = PyObject_CallFunction(install, "ss", GETTEXT_PACKAGE, LOCALEDIR);
+ Py_XDECREF(result);
+ Py_DECREF(gettext);
+
+ return TRUE;
+}
+
+static gboolean
+gplugin_python_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);
+ if(argv[0] == NULL) {
+ g_warning("Could not convert program name to wchar_t string.");
+ return FALSE;
+ }
+
+ /* 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_python_loader_init_pygobject()) {
+ if(gplugin_python_loader_init_gettext()) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/******************************************************************************
+ * Object Stuff
+ *****************************************************************************/
+static void
+gplugin_python_loader_init(G_GNUC_UNUSED GPluginPythonLoader *loader) {
+}
+
+static void
+gplugin_python_loader_class_finalize(G_GNUC_UNUSED GPluginPythonLoaderClass *klass)
+{
+}
+
+static void
+gplugin_python_loader_class_init(GPluginPythonLoaderClass *klass) {
+ GPluginLoaderClass *loader_class = GPLUGIN_LOADER_CLASS(klass);
+
+ loader_class->supported_extensions =
+ gplugin_python_loader_class_supported_extensions;
+ loader_class->query = gplugin_python_loader_query;
+ loader_class->load = gplugin_python_loader_load;
+ loader_class->unload = gplugin_python_loader_unload;
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+void
+gplugin_python_loader_register(GPluginNativePlugin *native) {
+ gplugin_python_loader_register_type(G_TYPE_MODULE(native));
+
+ gplugin_python_loader_init_python();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python/gplugin-python3-loader.h Sat Feb 22 03:41:23 2020 -0600
@@ -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_PYTHON_LOADER_H
+#define GPLUGIN_PYTHON_LOADER_H
+
+#include <gplugin.h>
+#include <gplugin-native.h>
+
+G_BEGIN_DECLS
+
+#define GPLUGIN_PYTHON_TYPE_LOADER (gplugin_python_loader_get_type())
+G_DECLARE_FINAL_TYPE(GPluginPythonLoader, gplugin_python_loader, GPLUGIN_PYTHON, LOADER, GPluginLoader)
+
+void gplugin_python_loader_register(GPluginNativePlugin *native);
+
+G_END_DECLS
+
+#endif /* GPLUGIN_PYTHON_LOADER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python/gplugin-python3-plugin.c Sat Feb 22 03:41:23 2020 -0600
@@ -0,0 +1,277 @@
+/*
+ * 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 <Python.h>
+
+#include "gplugin-python3-plugin.h"
+
+#include <pygobject.h>
+
+/******************************************************************************
+ * Typedefs
+ *****************************************************************************/
+struct _GPluginPythonPlugin {
+ GObject parent;
+
+ PyObject *module;
+ PyObject *query;
+ PyObject *load;
+ PyObject *unload;
+
+ /* overrides */
+ gchar *filename;
+ GPluginLoader *loader;
+ GPluginPluginInfo *info;
+ GPluginPluginState state;
+};
+
+/******************************************************************************
+ * Enums
+ *****************************************************************************/
+enum {
+ PROP_ZERO,
+ PROP_MODULE,
+ PROP_LOAD_FUNC,
+ PROP_UNLOAD_FUNC,
+ N_PROPERTIES,
+ /* overrides */
+ PROP_FILENAME = N_PROPERTIES,
+ PROP_LOADER,
+ PROP_INFO,
+ PROP_STATE
+};
+static GParamSpec *properties[N_PROPERTIES] = {NULL,};
+
+/* I hate forward declarations... */
+static void gplugin_python_plugin_iface_init(GPluginPluginInterface *iface);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED(
+ GPluginPythonPlugin,
+ gplugin_python_plugin,
+ G_TYPE_OBJECT,
+ 0,
+ G_IMPLEMENT_INTERFACE(GPLUGIN_TYPE_PLUGIN, gplugin_python_plugin_iface_init)
+);
+
+/******************************************************************************
+ * GPluginPlugin Implementation
+ *****************************************************************************/
+static void
+gplugin_python_plugin_iface_init(G_GNUC_UNUSED GPluginPluginInterface *iface) {
+}
+
+/******************************************************************************
+ * Private Stuff
+ *****************************************************************************/
+static void
+gplugin_python_plugin_set_module(GPluginPythonPlugin *plugin,
+ PyObject *module)
+{
+ g_return_if_fail(GPLUGIN_IS_PLUGIN(plugin));
+ g_return_if_fail(module);
+
+ Py_XINCREF(module);
+ Py_CLEAR(plugin->module);
+ plugin->module = module;
+}
+
+static gpointer
+gplugin_python_plugin_get_load_func(GPluginPythonPlugin *plugin) {
+ g_return_val_if_fail(GPLUGIN_PYTHON_IS_PLUGIN(plugin), NULL);
+
+ return plugin->load;
+}
+
+static void
+gplugin_python_plugin_set_load_func(GPluginPythonPlugin *plugin,
+ PyObject *func)
+{
+ g_return_if_fail(GPLUGIN_PYTHON_IS_PLUGIN(plugin));
+ g_return_if_fail(func != NULL);
+
+ Py_XINCREF(func);
+ Py_CLEAR(plugin->load);
+ plugin->load = func;
+}
+
+static gpointer
+gplugin_python_plugin_get_unload_func(GPluginPythonPlugin *plugin) {
+ g_return_val_if_fail(GPLUGIN_PYTHON_IS_PLUGIN(plugin), NULL);
+
+ return plugin->unload;
+}
+
+static void
+gplugin_python_plugin_set_unload_func(GPluginPythonPlugin *plugin,
+ PyObject *func)
+{
+ g_return_if_fail(GPLUGIN_PYTHON_IS_PLUGIN(plugin));
+ g_return_if_fail(func != NULL);
+
+ Py_XINCREF(func);
+ Py_CLEAR(plugin->unload);
+ plugin->unload = func;
+}
+
+/******************************************************************************
+ * Object Stuff
+ *****************************************************************************/
+static void
+gplugin_python_plugin_get_property(GObject *obj, guint param_id, GValue *value,
+ GParamSpec *pspec)
+{
+ GPluginPythonPlugin *plugin = GPLUGIN_PYTHON_PLUGIN(obj);
+
+ switch(param_id) {
+ case PROP_MODULE:
+ g_value_set_pointer(value, plugin->module);
+ break;
+ case PROP_LOAD_FUNC:
+ g_value_set_pointer(value,
+ gplugin_python_plugin_get_load_func(plugin));
+ break;
+ case PROP_UNLOAD_FUNC:
+ g_value_set_pointer(value,
+ gplugin_python_plugin_get_unload_func(plugin));
+ break;
+
+ /* overrides */
+ case PROP_FILENAME:
+ g_value_set_string(value, plugin->filename);
+ break;
+ case PROP_LOADER:
+ g_value_set_object(value, plugin->loader);
+ break;
+ case PROP_INFO:
+ g_value_set_object(value, plugin->info);
+ break;
+ case PROP_STATE:
+ g_value_set_enum(value, plugin->state);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gplugin_python_plugin_set_property(GObject *obj, guint param_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ GPluginPythonPlugin *plugin = GPLUGIN_PYTHON_PLUGIN(obj);
+
+ switch(param_id) {
+ case PROP_MODULE:
+ gplugin_python_plugin_set_module(plugin,
+ g_value_get_pointer(value));
+ break;
+ case PROP_LOAD_FUNC:
+ gplugin_python_plugin_set_load_func(plugin,
+ g_value_get_pointer(value));
+ break;
+ case PROP_UNLOAD_FUNC:
+ gplugin_python_plugin_set_unload_func(plugin,
+ g_value_get_pointer(value));
+ break;
+
+ /* overrides */
+ case PROP_FILENAME:
+ plugin->filename = g_value_dup_string(value);
+ break;
+ case PROP_LOADER:
+ plugin->loader = g_value_dup_object(value);
+ break;
+ case PROP_INFO:
+ plugin->info = g_value_dup_object(value);
+ break;
+ case PROP_STATE:
+ plugin->state = g_value_get_enum(value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gplugin_python_plugin_finalize(GObject *obj) {
+ GPluginPythonPlugin *plugin = GPLUGIN_PYTHON_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_OBJECT_CLASS(gplugin_python_plugin_parent_class)->finalize(obj);
+}
+
+static void
+gplugin_python_plugin_init(G_GNUC_UNUSED GPluginPythonPlugin *plugin) {
+}
+
+static void
+gplugin_python_plugin_class_finalize(G_GNUC_UNUSED GPluginPythonPluginClass *klass)
+{
+}
+
+static void
+gplugin_python_plugin_class_init(GPluginPythonPluginClass *klass) {
+ GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+ obj_class->get_property = gplugin_python_plugin_get_property;
+ obj_class->set_property = gplugin_python_plugin_set_property;
+ obj_class->finalize = gplugin_python_plugin_finalize;
+
+ properties[PROP_MODULE] = g_param_spec_pointer(
+ "module", "module",
+ "The python module object",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY
+ );
+
+ properties[PROP_LOAD_FUNC] = g_param_spec_pointer(
+ "load-func", "load-func",
+ "The python load function",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY
+ );
+
+ properties[PROP_UNLOAD_FUNC] = g_param_spec_pointer(
+ "unload-func", "unload-func",
+ "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");
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+void
+gplugin_python_plugin_register(GPluginNativePlugin *native) {
+ gplugin_python_plugin_register_type(G_TYPE_MODULE(native));
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python/gplugin-python3-plugin.h Sat Feb 22 03:41:23 2020 -0600
@@ -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_PYTHON_PLUGIN_H
+#define GPLUGIN_PYTHON_PLUGIN_H
+
+#include <gplugin.h>
+#include <gplugin-native.h>
+
+G_BEGIN_DECLS
+
+#define GPLUGIN_PYTHON_TYPE_PLUGIN (gplugin_python_plugin_get_type())
+G_DECLARE_FINAL_TYPE(GPluginPythonPlugin, gplugin_python_plugin, GPLUGIN_PYTHON, PLUGIN, GObject)
+
+void gplugin_python_plugin_register(GPluginNativePlugin *native);
+
+G_END_DECLS
+
+#endif /* GPLUGIN_PYTHON_PLUGIN_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python/gplugin-python3-test-pygobject.c Sat Feb 22 03:41:23 2020 -0600
@@ -0,0 +1,65 @@
+/*
+ * 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 <stdio.h>
+
+#include <glib.h>
+
+#include <Python.h>
+
+#include <pygobject.h>
+
+gint
+main(gint argc, gchar *argv[]) {
+ wchar_t *wargv[] = { NULL, NULL };
+ size_t len;
+
+ /* initialize python */
+ if(!Py_IsInitialized())
+ Py_InitializeEx(FALSE);
+
+ /* setup wargv */
+ len = mbstowcs(NULL, argv[0], 0);
+ if(len == (size_t)-1)
+ return -1;
+
+ wargv[0] = g_new0(wchar_t, len + 1);
+ len = mbstowcs(wargv[0], argv[0], len + 1);
+ if(len == (size_t)-1) {
+ g_free(wargv[0]);
+ return -1;
+ }
+
+ /* setup sys.path */
+#if PY_VERSION_HEX < 0x03010300
+ PySys_SetArgv(1, wargv);
+ PyRun_SimpleString("import sys; sys.path.pop(0)\n");
+#else
+ PySys_SetArgvEx(1, wargv, 0);
+#endif
+
+ g_free(wargv[0]);
+
+ /* initialize pygobject */
+ pygobject_init(3, 0, 0);
+ if(PyErr_Occurred()) {
+ PyErr_Print();
+ return -1;
+ }
+
+ return 0;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python/gplugin-python3-utils.c Sat Feb 22 03:41:23 2020 -0600
@@ -0,0 +1,111 @@
+/*
+ * 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 <Python.h>
+
+#include <gplugin/gplugin.h>
+
+#include "gplugin-python3-utils.h"
+
+#include <string.h>
+
+gchar *
+gplugin_python_filename_to_module(const gchar *filename) {
+ gchar *base = NULL;
+ 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("."));
+ if(e == NULL) {
+ return base;
+ }
+
+ /* now copy the module name into r */
+ r = g_malloc(e - base + 1);
+ memcpy(r, base, e - base);
+ r[e - base] = 0;
+
+ /* free the basename */
+ g_free(base);
+
+ return r;
+}
+
+gboolean
+gplugin_python_add_module_path(const gchar *module_path) {
+ PyObject *sys_path = NULL, *path = NULL;
+ gboolean ret = FALSE;
+
+ sys_path = PySys_GetObject("path");
+
+ path = PyUnicode_FromString(module_path);
+
+ if(PySequence_Contains(sys_path, path) == 0) {
+ PyList_Insert(sys_path, 0, path);
+ ret = TRUE;
+ }
+
+ Py_DECREF(path);
+
+ return ret;
+}
+
+GError *
+gplugin_python_exception_to_gerror(void) {
+ GError *error = NULL;
+ PyObject *type = NULL, *value = NULL, *trace = NULL;
+ PyObject *type_name = NULL, *value_str = NULL, *obj = NULL;
+
+ if(!PyErr_Occurred())
+ return NULL;
+
+ PyErr_Fetch(&type, &value, &trace);
+ if(type == NULL)
+ return NULL;
+
+ PyErr_NormalizeException(&type, &value, &trace);
+ Py_XDECREF(trace);
+
+ type_name = PyObject_GetAttrString(type, "__name__");
+ Py_DECREF(type);
+
+ value_str = PyObject_Str(value);
+ Py_DECREF(value);
+
+ /* now decode the utf8 into a string we can use */
+ obj = PyUnicode_AsUTF8String(type_name);
+ Py_DECREF(type_name);
+ type_name = obj;
+
+ obj = PyUnicode_AsUTF8String(value_str);
+ Py_DECREF(value_str);
+ value_str = obj;
+
+ error = g_error_new(GPLUGIN_DOMAIN, 0, "%s: %s",
+ PyBytes_AsString(type_name),
+ PyBytes_AsString(value_str));
+
+ Py_DECREF(type_name);
+ Py_DECREF(value_str);
+
+ return error;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python/gplugin-python3-utils.h Sat Feb 22 03:41:23 2020 -0600
@@ -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/>.
+ */
+
+#ifndef GPLUGIN_PYTHON_UTILS_H
+#define GPLUGIN_PYTHON_UTILS_H
+
+#include <glib.h>
+
+#define GPLUGIN_PYTHON_DOMAIN (g_quark_from_static_string("gplugin-python"))
+
+G_BEGIN_DECLS
+
+gchar *gplugin_python_filename_to_module(const gchar *filename);
+
+gboolean gplugin_python_add_module_path(const gchar *module_path);
+
+GError *gplugin_python_exception_to_gerror(void);
+
+G_END_DECLS
+
+#endif /* GPLUGIN_PYTHON_UTILS_H */
--- a/python/meson.build Sat Feb 22 03:33:17 2020 -0600
+++ b/python/meson.build Sat Feb 22 03:41:23 2020 -0600
@@ -3,17 +3,17 @@
error('Python plugin requires GObject Introspection.')
endif
- GPLUGIN_PYTHON_SOURCES = [
- 'gplugin-python-core.c',
- 'gplugin-python-loader.c',
- 'gplugin-python-plugin.c',
- 'gplugin-python-utils.c',
+ GPLUGIN_PYTHON3_SOURCES = [
+ 'gplugin-python3-core.c',
+ 'gplugin-python3-loader.c',
+ 'gplugin-python3-plugin.c',
+ 'gplugin-python3-utils.c',
]
- GPLUGIN_PYTHON_HEADERS = [
- 'gplugin-python-loader.h',
- 'gplugin-python-plugin.h',
- 'gplugin-python-utils.h',
+ 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)
@@ -24,37 +24,37 @@
PYGOBJECT = dependency('pygobject-3.0', version: '>=3.0.0')
# Compile and run our python-gi test program
- python_gi_test = compiler.run(files('gplugin-python-test-pygobject.c'),
+ python3_gi_test = compiler.run(files('gplugin-python3-test-pygobject.c'),
dependencies : [GLIB, PYTHON3, PYGOBJECT],
- name : 'Python GI')
- if not python_gi_test.compiled() or python_gi_test.returncode() != 0
- error('pygobject does not work with python3')
+ name : 'Python3 GI')
+ if not python3_gi_test.compiled() or python3_gi_test.returncode() != 0
+ error('pygobject does not work with Python3')
endif
# Now add our libraries
- gplugin_python_inc = include_directories('.')
- gplugin_python = shared_library('gplugin-python3',
- GPLUGIN_PYTHON_SOURCES,
- GPLUGIN_PYTHON_HEADERS,
+ gplugin_python3_inc = include_directories('.')
+ gplugin_python3 = shared_library('gplugin-python3',
+ GPLUGIN_PYTHON3_SOURCES,
+ GPLUGIN_PYTHON3_HEADERS,
name_prefix : '',
dependencies : [PYTHON3, PYGOBJECT, gplugin_dep],
install : true,
install_dir : join_paths(get_option('libdir'), 'gplugin')
)
- gplugin_python_dep = declare_dependency(
- include_directories : gplugin_python_inc,
- link_with : gplugin_python,
+ gplugin_python3_dep = declare_dependency(
+ include_directories : gplugin_python3_inc,
+ link_with : gplugin_python3,
)
- gplugin_python_static = static_library('gplugin-python-static',
- GPLUGIN_PYTHON_SOURCES,
- GPLUGIN_PYTHON_HEADERS,
+ gplugin_python3_static = static_library('gplugin-python3-static',
+ GPLUGIN_PYTHON3_SOURCES,
+ GPLUGIN_PYTHON3_HEADERS,
dependencies : [PYTHON3, PYGOBJECT, gplugin_dep],
)
- gplugin_python_static_dep = declare_dependency(
- include_directories : gplugin_python_inc,
- link_with : gplugin_python_static,
+ gplugin_python3_static_dep = declare_dependency(
+ include_directories : gplugin_python3_inc,
+ link_with : gplugin_python3_static,
)
-endif # python
+endif # python3
subdir('tests')
--- a/python/tests/meson.build Sat Feb 22 03:33:17 2020 -0600
+++ b/python/tests/meson.build Sat Feb 22 03:41:23 2020 -0600
@@ -16,7 +16,7 @@
include_directories : include_directories('.'),
link_with : [gplugin_loader_tests],
dependencies : [GLIB, GOBJECT, PYTHON3, PYGOBJECT,
- gplugin_python_static_dep])
+ gplugin_python3_static_dep])
test('Python3 utils', e)
endif # python
--- a/python/tests/test-python3-utils.c Sat Feb 22 03:33:17 2020 -0600
+++ b/python/tests/test-python3-utils.c Sat Feb 22 03:41:23 2020 -0600
@@ -17,7 +17,7 @@
#include <Python.h>
-#include "gplugin-python-utils.h"
+#include "gplugin-python3-utils.h"
#include <glib.h>