--- a/src/pyplugin.py Sat Mar 23 01:39:49 2013 -0500
+++ b/src/pyplugin.py Sat Mar 23 03:37:41 2013 -0500
@@ -14,9 +14,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# we use a list since it is a mutable sequence type. Meaning we can add to it @@ -49,7 +53,15 @@
+ Clears all search paths +def find(cls, recurse=False): Find all plugins that are subclasses of cls in the current search paths
@@ -62,6 +74,9 @@
mod = importlib.import_module(path)
+ if recurse and _is_package(mod): for symbol_name in dir(mod):
if symbol_name == cls_name:
@@ -77,4 +92,42 @@
+def _is_package(module): + Returns true if the module's name is __init__, false otherwise + filename = os.path.basename(module.__file__) + base, _ = os.path.splitext(filename) + return base == '__init__' + Adds additional modules from a package + dirname = os.path.dirname(module.__file__) + make_module = lambda name: '.'.join((module.__name__, name)) + for name in os.listdir(dirname): + base, _ = os.path.splitext(name) + filename = os.path.join(dirname, name) + if os.path.isdir(filename): + add_path(make_module(base)) + elif os.path.isfile(filename): + if fnmatch.fnmatch(name, '*.py') or \ + fnmatch.fnmatch(name, '*.py[co]'): + add_path(make_module(base)) __all__ = [add_path, remove_path, get_paths, find]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/modules/deep/__init__.py Sat Mar 23 03:37:41 2013 -0500
@@ -0,0 +1,28 @@
+# pyplugin - A python plugin finder +# Copyright (C) 2013 Gary Kramlich <grim@reaperworld.com> +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 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 General Public License for more details. +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +This module contains a plugin and another module that contains another plugin +from tests import Plugin +class DeepRecursion(Plugin): # pylint:disable-msg=R0903 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/modules/deep/deeper.py Sat Mar 23 03:37:41 2013 -0500
@@ -0,0 +1,28 @@
+# pyplugin - A python plugin finder +# Copyright (C) 2013 Gary Kramlich <grim@reaperworld.com> +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 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 General Public License for more details. +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +This module contains a plugin and another module that contains another plugin +from tests import Plugin +class DeeperRecursion(Plugin): # pylint:disable-msg=R0903 --- a/tests/tests.py Sat Mar 23 01:39:49 2013 -0500
+++ b/tests/tests.py Sat Mar 23 03:37:41 2013 -0500
@@ -26,6 +26,29 @@
+def test_path(test, path, count, recurse=False): + Given a module path, test that we find count plugins + pyplugin.add_path(path) + gen = pyplugin.find(Plugin, recurse=recurse) + test.assertTrue(inspect.isgenerator(gen)) + test.assertEqual(len(found), count, 'plugins found: {}'.format(found)) +def test_path_count(test, count): + Asserts if the number of paths doesn't match count + paths = pyplugin.get_paths() + test.assertEqual(len(paths), count, 'search paths {}'.format(paths)) class Plugin(object): # pylint:disable-msg=R0903
The class all the test plugins descend from
@@ -39,24 +62,13 @@
Unit tests for path manipulation
- def _test_path_count(self, count):
- Modular form to check how many paths are in the search paths
- paths = pyplugin.get_paths()
- self.assertEqual(len(paths), count,
- 'search paths {}'.format(paths))
def setUp(self): # pylint:disable-msg=C0103
- paths = pyplugin.get_paths()
- pyplugin.remove_path(path)
def tearDown(self): # pylint:disable-msg=C0103
- self._test_path_count(0)
+ test_path_count(self, 0) def test_add_remove(self):
@@ -65,7 +77,7 @@
- self._test_path_count(1)
+ test_path_count(self, 1) pyplugin.remove_path(PATH)
@@ -76,7 +88,7 @@
- self._test_path_count(1)
+ test_path_count(self, 1) pyplugin.remove_path(PATH)
@@ -97,10 +109,10 @@
second = '{}.1'.format(PATH)
- self._test_path_count(1)
+ test_path_count(self, 1) pyplugin.add_path(second)
- self._test_path_count(2)
+ test_path_count(self, 2) pyplugin.remove_path(PATH)
pyplugin.remove_path(second)
@@ -162,50 +174,52 @@
class TestModule(unittest.TestCase): # pylint:disable-msg=R0904
- Tests the discovery method of pyplugin
- def _test_path(self, path, count):
- Given a module path, test that we find count plugins
+ """ Tests the discovery method of pyplugin """ - self.assertEqual(len(pyplugin.get_paths()), 0)
- pyplugin.add_path(path)
- gen = pyplugin.find(Plugin)
- self.assertTrue(inspect.isgenerator(gen))
- self.assertEqual(len(list(gen)), count)
def setUp(self): # pylint:disable-msg=C0103
- paths = pyplugin.get_paths()
- pyplugin.remove_path(path)
+ def tearDown(self): # pylint:disable-msg=C0103
- Test a module with a single plugin
- self._test_path('modules.single', 1)
+ """ Test a module with a single plugin """ + test_path(self, 'modules.single', 1)
- Test a module with multiple plugins
- self._test_path('modules.multiple', 2)
+ """ Test a module with multiple plugins """ + test_path(self, 'modules.multiple', 2)
- Test a module with more than just plugins
+ """ Test a module with more than just plugins """ + test_path(self, 'modules.mixed', 2) +class TestPackage(unittest.TestCase): # pylint:disable-msg=R0904 + """ Tests the find method of pyplugin on a package """ - self._test_path('modules.mixed', 2)
+ def setUp(self): # pylint:disable-msg=C0103 + def tearDown(self): # pylint:disable-msg=C0103 + def test_package_without_recurse(self): + """ Test a package without recursion """ + test_path(self, 'modules', 0) + def test_package_recursion(self): + """ Test a package with recursion """ + test_path(self, 'modules.deep', 2, recurse=True) + def test_package_deep_recursion(self): + """ Test a package with recursion """ + test_path(self, 'modules', 7, recurse=True)