diff --git a/.github/workflows/automatic-tests.yml b/.github/workflows/automatic-tests.yml index adebe20..84baf24 100644 --- a/.github/workflows/automatic-tests.yml +++ b/.github/workflows/automatic-tests.yml @@ -8,12 +8,12 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies @@ -31,7 +31,7 @@ jobs: run: | pytest --cov --cov-report=lcov - name: Coveralls - uses: coverallsapp/github-action@master + uses: coverallsapp/github-action@v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} path-to-lcov: coverage.lcov diff --git a/package/setup.py b/package/setup.py index 58705e1..0044f58 100644 --- a/package/setup.py +++ b/package/setup.py @@ -62,6 +62,9 @@ 'Programming Language :: Python :: 3', 'Topic :: Software Development :: Libraries :: Python Modules'], platforms='All', + install_requires = [ + "packaging", + ] ) finally: diff --git a/package/test/pluginsasdirs/SimplePlugin/__init__.py b/package/test/pluginsasdirs/SimplePlugin/__init__.py index 909fb75..7d04865 100644 --- a/package/test/pluginsasdirs/SimplePlugin/__init__.py +++ b/package/test/pluginsasdirs/SimplePlugin/__init__.py @@ -5,6 +5,7 @@ """ from yapsy.IPlugin import IPlugin +from .hello import hello class SimplePlugin(IPlugin): """ @@ -25,6 +26,7 @@ def activate(self): """ # get the automatic procedure from IPlugin IPlugin.activate(self) + hello.print() return diff --git a/package/test/pluginsasdirs/SimplePlugin/hello.py b/package/test/pluginsasdirs/SimplePlugin/hello.py new file mode 100644 index 0000000..e8ffeee --- /dev/null +++ b/package/test/pluginsasdirs/SimplePlugin/hello.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: t; python-indent: 4 -*- + + +class hello: + + @staticmethod + def print(): + print(f"Some Random Message!") diff --git a/package/test/pluginsasdirs/pluginsasdirs2/SimplePluginAsDir/SimplePluginAsDir.py b/package/test/pluginsasdirs/pluginsasdirs2/SimplePluginAsDir/SimplePluginAsDir.py new file mode 100644 index 0000000..257d9c7 --- /dev/null +++ b/package/test/pluginsasdirs/pluginsasdirs2/SimplePluginAsDir/SimplePluginAsDir.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: t; python-indent: 4 -*- + +""" +This is certainly the second simplest plugin ever. +""" + +from yapsy.IPlugin import IPlugin +from .somerandom import somerandom + + +class SimplePluginAsDir(IPlugin): + """ + Only trigger the expected test results. + """ + + def __init__(self): + """ + init + """ + # initialise parent class + IPlugin.__init__(self) + inst = somerandom(100) + inst.print() + + def activate(self): + """ + On activation tell that this has been successful. + """ + # get the automatic procedure from IPlugin + IPlugin.activate(self) + s = somerandom() + s.print() + return + + def deactivate(self): + """ + On deactivation check that the 'activated' flag was on then + tell everything's ok to the test procedure. + """ + IPlugin.deactivate(self) diff --git a/package/test/pluginsasdirs/pluginsasdirs2/SimplePluginAsDir/__init__.py b/package/test/pluginsasdirs/pluginsasdirs2/SimplePluginAsDir/__init__.py new file mode 100644 index 0000000..2cbaa18 --- /dev/null +++ b/package/test/pluginsasdirs/pluginsasdirs2/SimplePluginAsDir/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: t; python-indent: 4 -*- +from .SimplePluginAsDir import SimplePluginAsDir diff --git a/package/test/pluginsasdirs/pluginsasdirs2/SimplePluginAsDir/somerandom.py b/package/test/pluginsasdirs/pluginsasdirs2/SimplePluginAsDir/somerandom.py new file mode 100644 index 0000000..590f8f2 --- /dev/null +++ b/package/test/pluginsasdirs/pluginsasdirs2/SimplePluginAsDir/somerandom.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: t; python-indent: 4 -*- +class somerandom: + + def __init__(self, n: int = 42): + self.n = n + + def print(self): + print(f"Answer to everything {self.n}") diff --git a/package/test/pluginsasdirs/pluginsasdirs2/simplepluginasdir.yapsy-plugin b/package/test/pluginsasdirs/pluginsasdirs2/simplepluginasdir.yapsy-plugin new file mode 100644 index 0000000..2038171 --- /dev/null +++ b/package/test/pluginsasdirs/pluginsasdirs2/simplepluginasdir.yapsy-plugin @@ -0,0 +1,8 @@ +[Core] +Name = Simple Plugin As Dir +Module = SimplePluginAsDir + +[Documentation] +Author = Ameya Vikram Singh +Version = 0.1 +Description = A simple plugin useful for basic testing diff --git a/package/test/test_PluginFileLocator.py b/package/test/test_PluginFileLocator.py index 79405f7..b8eeab3 100644 --- a/package/test/test_PluginFileLocator.py +++ b/package/test/test_PluginFileLocator.py @@ -238,7 +238,7 @@ def test_locatePlugins_when_plugin_is_a_directory(self): pl = PluginFileLocator() pl.setPluginPlaces([self.plugin_as_dir_directory]) candidates, num = pl.locatePlugins() - self.assertEqual(num,1) + self.assertEqual(num,2) self.assertEqual(len(candidates),num) self.assertEqual(os.path.join(self.plugin_as_dir_directory,self.plugin_info_file), candidates[0][0]) @@ -279,7 +279,7 @@ def test_locatePlugins_recursively_when_plugin_is_a_directory(self): pl = PluginFileLocator() pl.setPluginPlaces([temp_dir]) candidates, num = pl.locatePlugins() - self.assertEqual(num,1) + self.assertEqual(num,2) self.assertEqual(len(candidates),num) self.assertEqual(os.path.join(temp_sub_dir,self.plugin_info_file), candidates[0][0]) @@ -343,7 +343,7 @@ def test_locatePlugins_recursively_when_plugin_parent_dir_is_a_symlinked_directo pl = PluginFileLocator() pl.setPluginPlaces([temp_dir]) candidates, num = pl.locatePlugins() - self.assertEqual(num,1) + self.assertEqual(num,2) self.assertEqual(len(candidates),num) self.assertEqual(os.path.join(temp_sub_dir,self.plugin_info_file), candidates[0][0]) @@ -423,7 +423,7 @@ class SpecificPluginInfo(PluginInfo): self.assertEqual(1,len(simple_plugins)) for p in simple_plugins: self.assertTrue(isinstance(p[2],SpecificPluginInfo)) - + class PluginManagerSetUpTest(unittest.TestCase): diff --git a/package/test/test_SimplePlugin.py b/package/test/test_SimplePlugin.py index 9fc5ec1..b968b20 100644 --- a/package/test/test_SimplePlugin.py +++ b/package/test/test_SimplePlugin.py @@ -299,7 +299,7 @@ def testRecursivePluginlocation(self): self.assertEqual(len(spm.getCategories()),1) sole_category = spm.getCategories()[0] # check the getPluginsOfCategory - self.assertEqual(len(spm.getPluginsOfCategory(sole_category)),2) + self.assertEqual(len(spm.getPluginsOfCategory(sole_category)),3) def testDisablingRecursivePluginLocationIsEnforced(self): """ diff --git a/package/yapsy/PluginManager.py b/package/yapsy/PluginManager.py index 55ec649..ddc672c 100644 --- a/package/yapsy/PluginManager.py +++ b/package/yapsy/PluginManager.py @@ -128,7 +128,7 @@ import sys import os -import importlib +import importlib.util from yapsy import log from yapsy import NormalizePluginNameForModuleName @@ -144,6 +144,7 @@ # imported for backward compatibility (this PluginInfo was imported # here before 1.10) from yapsy.PluginInfo import PluginInfo +import inspect class PluginManager(object): @@ -529,7 +530,7 @@ def loadPlugins(self, callback=None, callback_after=None): plugin_info_reference = None for category_name in self.categories_interfaces: try: - is_correct_subclass = issubclass(element, self.categories_interfaces[category_name]) + is_correct_subclass = inspect.isclass(element) and issubclass(element, self.categories_interfaces[category_name]) except Exception: exc_info = sys.exc_info() log.debug("correct subclass tests failed for: %s in %s" % (element_name, candidate_filepath), exc_info=exc_info) @@ -573,19 +574,20 @@ def _importModule(plugin_module_name, candidate_filepath): .. note:: Isolated and provided to be reused, but not to be reimplemented ! """ - # use imp to correctly load the plugin as a module candidate_module = None - filepath_base = candidate_filepath.split('/')[-1] + submodule_search_locations = None if os.path.isdir(candidate_filepath): location = candidate_filepath + '/__init__.py' + submodule_search_locations = [] else: location = candidate_filepath + '.py' - spec = importlib.util.spec_from_file_location(filepath_base, location) - if (spec): + spec = importlib.util.spec_from_file_location(plugin_module_name, location, submodule_search_locations=submodule_search_locations) + if spec != None: candidate_module = importlib.util.module_from_spec(spec) sys.modules[plugin_module_name] = candidate_module spec.loader.exec_module(candidate_module) return candidate_module + def instanciateElementWithImportInfo(self, element, element_name, plugin_module_name, candidate_filepath):