[pitivi] pluginmanager: Write and read activated plugins from the configuration file



commit ca40c6bb5fc24829c132ab4c15325f7453811ffe
Author: Fabian Orccon <cfoch fabian gmail com>
Date:   Wed May 31 15:39:09 2017 -0500

    pluginmanager: Write and read activated plugins from the configuration file
    
    Differential Revision: https://phabricator.freedesktop.org/D1812

 pitivi/pluginmanager.py      |   36 +++++++++++++++++++-
 pitivi/settings.py           |   42 +++++++++++++++--------
 tests/test_plugin_manager.py |   76 ++++++++++++++++++++++++++++++++++++++++++
 tests/test_settings.py       |   25 +++++++++++++-
 4 files changed, 163 insertions(+), 16 deletions(-)
---
diff --git a/pitivi/pluginmanager.py b/pitivi/pluginmanager.py
index ef953d6..e748488 100644
--- a/pitivi/pluginmanager.py
+++ b/pitivi/pluginmanager.py
@@ -23,6 +23,14 @@ from gi.repository import Peas
 
 from pitivi.configure import get_plugins_dir
 from pitivi.configure import get_user_plugins_dir
+from pitivi.settings import GlobalSettings
+from pitivi.utils.loggable import Loggable
+
+
+GlobalSettings.addConfigSection("plugins")
+GlobalSettings.addConfigOption("ActivePlugins",
+                               section="plugins", key="active-plugins",
+                               default=[])
 
 
 class API(GObject.GObject):
@@ -33,7 +41,7 @@ class API(GObject.GObject):
         self.app = app
 
 
-class PluginManager:
+class PluginManager(Loggable):
     """Pitivi Plugin Manager to handle a set of plugins.
 
     Attributes:
@@ -45,8 +53,14 @@ class PluginManager:
     DEFAULT_LOADERS = ("python3", )
 
     def __init__(self, app):
+        Loggable.__init__(self)
         self.app = app
         self.engine = Peas.Engine.get_default()
+        # Many plugins need access to the main window. However, by the time a
+        # plugin is loaded from settings (as soon Pitivi application starts),
+        # the main window doesn't exist yet. So we load plugins from settings
+        # after the main window is added.
+        self.app.connect("window-added", self.__window_added_cb)
 
         for loader in self.DEFAULT_LOADERS:
             self.engine.enable_loader(loader)
@@ -59,6 +73,16 @@ class PluginManager:
         """Gets the engine's plugin list."""
         return self.engine.get_plugin_list()
 
+    def _load_plugins(self):
+        """Loads plugins from settings."""
+        plugin_names = self.app.settings.ActivePlugins
+        for plugin_name in plugin_names:
+            plugin_info = self.engine.get_plugin_info(plugin_name)
+            if plugin_info not in self.plugins:
+                self.warning("Plugin missing: %s", plugin_name)
+                continue
+            self.engine.load_plugin(plugin_info)
+
     def _setup_extension_set(self):
         plugin_iface = API(self.app)
         self.extension_set =\
@@ -86,3 +110,13 @@ class PluginManager:
     @staticmethod
     def __extension_added_cb(unused_set, unused_plugin_info, extension):
         extension.activate()
+
+    def __window_added_cb(self, unused_app, unused_window):
+        """Handles the addition of a window to the application."""
+        self._load_plugins()
+        self.engine.connect("notify::loaded-plugins", self.__loaded_plugins_cb)
+        self.app.disconnect_by_func(self.__window_added_cb)
+
+    def __loaded_plugins_cb(self, engine, unused_pspec):
+        """Handles the changing of the loaded plugin list."""
+        self.app.settings.ActivePlugins = engine.get_property("loaded-plugins")
diff --git a/pitivi/settings.py b/pitivi/settings.py
index 55110e1..4bf75cc 100644
--- a/pitivi/settings.py
+++ b/pitivi/settings.py
@@ -137,6 +137,32 @@ class GlobalSettings(GObject.Object, Loggable):
         self._readSettingsFromConfigurationFile()
         self._readSettingsFromEnvironmentVariables()
 
+    def _read_value(self, section, key, type_):
+        if type_ == int:
+            try:
+                value = self._config.getint(section, key)
+            except ValueError:
+                # In previous configurations we incorrectly stored
+                # ints using float values.
+                value = int(self._config.getfloat(section, key))
+        elif type_ == float:
+            value = self._config.getfloat(section, key)
+        elif type_ == bool:
+            value = self._config.getboolean(section, key)
+        elif type_ == list:
+            tmp_value = self._config.get(section, key)
+            value = [token.strip() for token in tmp_value.split("\n") if token]
+        else:
+            value = self._config.get(section, key)
+        return value
+
+    def _write_value(self, section, key, value):
+        if type(value) == list:
+            value = "\n" + "\n".join(value)
+            self._config.set(section, key, value)
+        else:
+            self._config.set(section, key, str(value))
+
     def _readSettingsFromConfigurationFile(self):
         """Reads the settings from the user configuration file."""
         try:
@@ -153,19 +179,7 @@ class GlobalSettings(GObject.Object, Loggable):
             if not self._config.has_section(section):
                 continue
             if key and self._config.has_option(section, key):
-                if typ == int or typ == int:
-                    try:
-                        value = self._config.getint(section, key)
-                    except ValueError:
-                        # In previous configurations we incorrectly stored
-                        # ints using float values.
-                        value = int(self._config.getfloat(section, key))
-                elif typ == float:
-                    value = self._config.getfloat(section, key)
-                elif typ == bool:
-                    value = self._config.getboolean(section, key)
-                else:
-                    value = self._config.get(section, key)
+                value = self._read_value(section, key, typ)
                 setattr(self, attrname, value)
 
     @classmethod
@@ -210,7 +224,7 @@ class GlobalSettings(GObject.Object, Loggable):
                 self._config.add_section(section)
             if key:
                 if value is not None:
-                    self._config.set(section, key, str(value))
+                    self._write_value(section, key, value)
                 else:
                     self._config.remove_option(section, key)
         try:
diff --git a/tests/test_plugin_manager.py b/tests/test_plugin_manager.py
new file mode 100644
index 0000000..0958091
--- /dev/null
+++ b/tests/test_plugin_manager.py
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+# Pitivi video editor
+# Copyright (c) 2017, Fabian Orccon <cfoch fabian gmail com>
+#
+# This program 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.1 of the License, or (at your option) any later version.
+#
+# This program 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 program; if not, write to the
+# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+"""Test the Plugin Manager"""
+import os
+import tempfile
+import unittest
+from unittest import mock
+
+from gi.repository import GObject
+
+from pitivi.pluginmanager import PluginManager
+from pitivi.settings import GlobalSettings
+
+
+class TestPluginManager(unittest.TestCase):
+    """Test the behavior of the Plugin Manager"""
+
+    def test_load_plugins_from_settings(self):
+        """Checks if the plugin manager loads plugins from GlobalSettings."""
+
+        class App(GObject.Object):
+            """A representation of the Pitivi Application for test purposes"""
+            __gsignals__ = {
+                "window-added": (GObject.SIGNAL_RUN_LAST, None, (object, ))
+            }
+
+            def __init__(self):
+                GObject.Object.__init__(self)
+                self.settings = GlobalSettings()
+
+        with mock.patch("pitivi.pluginmanager.get_plugins_dir") as get_plugins_dir,\
+                mock.patch("pitivi.pluginmanager.get_user_plugins_dir") as get_user_plugins_dir,\
+                tempfile.TemporaryDirectory() as temp_dir:
+
+            plugin_content = ("[Plugin]\n"
+                              "Module=pluginA\n"
+                              "Name=PluginA\n"
+                              "Loader=Python3")
+
+            py_content = ("from gi.repository import GObject\n"
+                          "class PluginA(GObject.GObject):\n"
+                          "    def __init__(self):\n"
+                          "        GObject.Object.__init__(self)")
+
+            with open(os.path.join(temp_dir, "pluginA.plugin"), "w") as plugin_file:
+                plugin_file.write(plugin_content)
+            with open(os.path.join(temp_dir, "pluginA.py"), "w") as py_file:
+                py_file.write(py_content)
+
+            get_plugins_dir.return_value = temp_dir
+            get_user_plugins_dir.return_value = temp_dir
+
+            app = App()
+            app.settings.ActivePlugins = ["pluginA"]
+
+            plugin_manager = PluginManager(app)
+            app.emit("window-added", None)
+
+            loaded_plugins = plugin_manager.engine.get_loaded_plugins()
+            self.assertCountEqual(loaded_plugins, app.settings.ActivePlugins)
diff --git a/tests/test_settings.py b/tests/test_settings.py
index a948cb2..a0e51c4 100644
--- a/tests/test_settings.py
+++ b/tests/test_settings.py
@@ -91,15 +91,26 @@ class TestGlobalSettings(unittest.TestCase):
                                        key="option-b", default=False)
         GlobalSettings.addConfigOption("section1OptionC", section="section-1",
                                        key="option-c", default="")
+        GlobalSettings.addConfigOption("section1OptionD", section="section-1",
+                                       key="option-d", default=[])
+        GlobalSettings.addConfigOption("section1OptionE", section="section-1",
+                                       key="option-e", default=["foo"])
 
         self.assertEqual(GlobalSettings.section1OptionA, 50)
         self.assertEqual(GlobalSettings.section1OptionB, False)
         self.assertEqual(GlobalSettings.section1OptionC, "")
+        self.assertEqual(GlobalSettings.section1OptionD, [])
+        self.assertEqual(GlobalSettings.section1OptionE, ["foo"])
 
         conf_file_content = ("[section-1]\n"
                              "option-a = 10\n"
                              "option-b = True\n"
-                             "option-c = Pigs fly\n")
+                             "option-c = Pigs fly\n"
+                             "option-d=\n"
+                             "option-e=\n"
+                             "     elmo\n"
+                             "          knows\n"
+                             "     where you live\n")
 
         with mock.patch("pitivi.settings.xdg_config_home") as xdg_config_home,\
                 tempfile.TemporaryDirectory() as temp_dir:
@@ -111,12 +122,22 @@ class TestGlobalSettings(unittest.TestCase):
         self.assertEqual(settings.section1OptionA, 10)
         self.assertEqual(settings.section1OptionB, True)
         self.assertEqual(settings.section1OptionC, "Pigs fly")
+        self.assertEqual(settings.section1OptionD, [])
+        expected_e_value = [
+            "elmo",
+            "knows",
+            "where you live"
+        ]
+        self.assertEqual(settings.section1OptionE, expected_e_value)
 
     def test_write_config_file(self):
         GlobalSettings.addConfigSection("section-new")
         GlobalSettings.addConfigOption("sectionNewOptionA",
                                        section="section-new", key="option-a",
                                        default="elmo")
+        GlobalSettings.addConfigOption("sectionNewOptionB",
+                                       section="section-new", key="option-b",
+                                       default=["foo"])
 
         with mock.patch("pitivi.settings.xdg_config_home") as xdg_config_home,\
                 tempfile.TemporaryDirectory() as temp_dir:
@@ -124,7 +145,9 @@ class TestGlobalSettings(unittest.TestCase):
             settings1 = GlobalSettings()
 
             settings1.sectionNewOptionA = "kermit"
+            settings1.sectionNewOptionB = []
             settings1.storeSettings()
 
             settings2 = GlobalSettings()
             self.assertEqual(settings2.sectionNewOptionA, "kermit")
+            self.assertEqual(settings2.sectionNewOptionB, [])


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]