diff --git a/.moban.yml b/.moban.yml index 2c05c21..216b88e 100644 --- a/.moban.yml +++ b/.moban.yml @@ -11,3 +11,7 @@ targets: - "docs/source/conf.py": "docs/source/myconf.py.jj2" - "docs/source/index.rst": "docs/source/index.rst.jj2" - test.sh: test.sh.jj2 + - "lml/_version.py": _version.py.jj2 + - output: CHANGELOG.rst + configuration: changelog.yml + template: CHANGELOG.rst.jj2 diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a060cff..4bdc70f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,13 +1,29 @@ Change log -=========== +================================================================================ -0.0.2 - 23.10.2017 +0.0.3 - 12/06/2018 -------------------------------------------------------------------------------- -#. pyexcel `#103 `_, include +Added +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +#. `dict` can be a pluggable type in addition to `function`, `class` +#. get primary tag of your tag, helping you find out which category of plugins + your tag points to + +0.0.2 - 23/10/2017 +-------------------------------------------------------------------------------- + +Updated +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +#. `pyexcel#103 `_: include LICENSE in tar ball 0.0.1 - 30/05/2017 -------------------------------------------------------------------------------- -first release +Added +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +#. First release diff --git a/README.rst b/README.rst index 98574e9..665349a 100644 --- a/README.rst +++ b/README.rst @@ -1,12 +1,13 @@ ================================================================================ -lml - Load me later. A lazy loading plugin management system. +lml - Load me later. A lazy plugin management system. ================================================================================ -.. image:: https://api.travis-ci.org/chfw/lml.svg?branch=master +.. image:: https://api.travis-ci.org/chfw/lml.svg :target: http://travis-ci.org/chfw/lml -.. image:: https://codecov.io/gh/chfw/lml/branch/master/graph/badge.svg - :target: https://codecov.io/gh/chfw/lml +.. image:: https://codecov.io/github/chfw/lml/coverage.png + :target: https://codecov.io/github/chfw/lml + .. image:: https://readthedocs.org/projects/lml/badge/?version=latest :target: http://lml.readthedocs.org/en/latest/ @@ -54,4 +55,3 @@ License ================================================================================ New BSD - diff --git a/changelog.yml b/changelog.yml new file mode 100644 index 0000000..0d1b8ec --- /dev/null +++ b/changelog.yml @@ -0,0 +1,22 @@ +name: lml +organisation: chfw +releases: +- changes: + - action: Added + details: + - "`dict` can be a pluggable type in addition to `function`, `class`" + - get primary tag of your tag, helping you find out which category of plugins your tag points to + date: 12/06/2018 + version: 0.0.3 +- changes: + - action: Updated + details: + - "`pyexcel#103 `_: include LICENSE in tar ball" + date: 23/10/2017 + version: 0.0.2 +- changes: + - action: Added + details: + - First release + date: 30/05/2017 + version: 0.0.1 diff --git a/docs/source/conf.py b/docs/source/conf.py index e54a1f4..bb41cb7 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- DESCRIPTION = ( - 'Load me later. A lazy loading plugin management system.' + + 'Load me later. A loading plugin management system.' + '' ) extensions = [ @@ -17,9 +17,9 @@ source_suffix = '.rst' master_doc = 'index' project = u'lml' -copyright = u'2017 Onni Software Ltd.' -version = '0.0.2' -release = '0.0.2' +copyright = u'2017-2018 Onni Software Ltd.' +version = '0.0.3' +release = '0.0.3' exclude_patterns = [] pygments_style = 'sphinx' html_theme = 'default' diff --git a/docs/source/index.rst b/docs/source/index.rst index 86daf7f..616adf0 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,4 +1,4 @@ -`lml` - Load me later. A lazy loading plugin management system. +`lml` - Load me later. A loading plugin management system. ================================================================================ diff --git a/lml.yml b/lml.yml index a1c961e..97f5318 100644 --- a/lml.yml +++ b/lml.yml @@ -1,13 +1,13 @@ name: "lml" -full_name: "Load me later. A lazy loading plugin management system." +full_name: "Load me later. A lazy plugin management system." organisation: "chfw" author: "C.W." contact: "wangc_2011@hotmail.com" company: "Onni Software Ltd." -version: "0.0.2" -current_version: "0.0.2" -release: "0.0.2" -copyright_year: 2017 +version: "0.0.3" +current_version: "0.0.3" +release: "0.0.3" +copyright_year: 2017-2018 license: New BSD dependencies: [] -description: "Load me later. A lazy loading plugin management system." \ No newline at end of file +description: "Load me later. A loading plugin management system." \ No newline at end of file diff --git a/lml/__init__.py b/lml/__init__.py index 5550684..602898d 100644 --- a/lml/__init__.py +++ b/lml/__init__.py @@ -4,10 +4,12 @@ Load me later. A lazy loading plugin management system. - :copyright: (c) 2017 by Onni Software Ltd. + :copyright: (c) 2017-2018 by Onni Software Ltd. :license: New BSD License, see LICENSE for more details """ import logging +from lml._version import __version__ # flake8: noqa +from lml._version import __author__ # flake8: noqa try: from logging import NullHandler diff --git a/lml/_version.py b/lml/_version.py new file mode 100644 index 0000000..f4af5d3 --- /dev/null +++ b/lml/_version.py @@ -0,0 +1,2 @@ +__version__ = '0.0.3' +__author__ = 'C.W.' diff --git a/lml/loader.py b/lml/loader.py index 6177571..f5840f4 100644 --- a/lml/loader.py +++ b/lml/loader.py @@ -6,7 +6,7 @@ and pyinstaller. :func:`~lml.loader.scan_plugins` is expected to be called in the main package of yours at an earliest time of convenience. - :copyright: (c) 2017 by Onni Software Ltd. + :copyright: (c) 2017-2018 by Onni Software Ltd. :license: New BSD License, see LICENSE for more details """ import pkgutil diff --git a/lml/plugin.py b/lml/plugin.py index 8aeb35f..dc8835c 100644 --- a/lml/plugin.py +++ b/lml/plugin.py @@ -22,7 +22,7 @@ can be overridden to help its matching :class:`~lml.plugin.PluginManager` to look itself up. - :copyright: (c) 2017 by Onni Software Ltd. + :copyright: (c) 2017-2018 by Onni Software Ltd. :license: New BSD License, see LICENSE for more details """ import logging @@ -204,6 +204,7 @@ class PluginManager(object): def __init__(self, plugin_type): self.plugin_name = plugin_type self.registry = defaultdict(list) + self.tag_groups = dict() self._logger = logging.getLogger( self.__class__.__module__ + '.' + self.__class__.__name__) _register_class(self) @@ -273,7 +274,7 @@ class PluginManager(object): if __key in self.registry: for plugin_info in self.registry[__key]: cls = self.dynamic_load_library(plugin_info) - module_name = _get_me_pypi_package_name(cls.__module__) + module_name = _get_me_pypi_package_name(cls) if library and module_name != library: continue else: @@ -316,10 +317,19 @@ class PluginManager(object): plugin_info: a instance of plugin info """ - self._logger.debug("register " + plugin_cls.__name__) - for key in plugin_info.tags(): + self._logger.debug("register %s", + _show_me_your_name(plugin_cls)) + primary_tag = None + for index, key in enumerate(plugin_info.tags()): plugin_info.cls = plugin_cls self.registry[key.lower()].append(plugin_info) + if index == 0: + primary_tag = key.lower() + self.tag_groups[key.lower()] = primary_tag + + def get_primary_key(self, key): + __key = key.lower() + return self.tag_groups.get(__key, None) def _register_class(cls): @@ -335,7 +345,7 @@ def _register_class(cls): plugin_info.absolute_import_path) else: log.debug("load cached plugin info: %s", - plugin_info.cls.__name__) + _show_me_your_name(plugin_info.cls)) cls.load_me_later(plugin_info) del CACHED_PLUGIN_INFO[cls.plugin_name] @@ -348,7 +358,8 @@ def _register_a_plugin(plugin_info, plugin_cls): manager.register_a_plugin(plugin_cls, plugin_info) else: # let's cache it and wait the manager to be registered - log.debug("caching %s", plugin_cls.__name__) + log.debug("caching %s", + _show_me_your_name(plugin_cls.__name__)) CACHED_PLUGIN_INFO[plugin_info.plugin_type].append(plugin_info) @@ -365,6 +376,17 @@ def _load_me_later(plugin_info): CACHED_PLUGIN_INFO[plugin_info.plugin_type].append(plugin_info) -def _get_me_pypi_package_name(module_name): - root_module_name = module_name.split('.')[0] - return root_module_name.replace('_', '-') +def _get_me_pypi_package_name(module): + try: + module_name = module.__module__ + root_module_name = module_name.split('.')[0] + return root_module_name.replace('_', '-') + except AttributeError: + return None + + +def _show_me_your_name(cls_func_or_data_type): + try: + return cls_func_or_data_type.__name__ + except AttributeError: + return str(type(cls_func_or_data_type)) diff --git a/lml/utils.py b/lml/utils.py index e6d178e..31caadd 100644 --- a/lml/utils.py +++ b/lml/utils.py @@ -4,7 +4,7 @@ json utils for dump plugin info class - :copyright: (c) 2017 by Onni Software Ltd. + :copyright: (c) 2017-2018 by Onni Software Ltd. :license: New BSD License, see LICENSE for more details """ import sys diff --git a/setup.py b/setup.py index 827d8a9..43c7d14 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,6 @@ -# Template by setupmobans +#!/usr/bin/env python3 + +# Template by pypi-mobans import os import sys import codecs @@ -9,23 +11,20 @@ PY26 = PY2 and sys.version_info[1] < 7 NAME = 'lml' AUTHOR = 'C.W.' -VERSION = '0.0.2' +VERSION = '0.0.3' EMAIL = 'wangc_2011@hotmail.com' LICENSE = 'New BSD' DESCRIPTION = ( - 'Load me later. A lazy loading plugin management system.' + - '' + 'Load me later. A loading plugin management system.' ) URL = 'https://github.com/chfw/lml' -DOWNLOAD_URL = '%s/archive/0.0.2.tar.gz' % URL -FILES = ['README.rst', 'CHANGELOG.rst'] +DOWNLOAD_URL = '%s/archive/0.0.3.tar.gz' % URL +FILES = ['README.rst', 'CHANGELOG.rst'] KEYWORDS = [ 'python' ] CLASSIFIERS = [ - 'Topic :: Office/Business', - 'Topic :: Utilities', 'Topic :: Software Development :: Libraries', 'Programming Language :: Python', 'Intended Audience :: Developers', @@ -39,6 +38,7 @@ CLASSIFIERS = [ INSTALL_REQUIRES = [ ] +SETUP_COMMANDS = {} PACKAGES = find_packages(exclude=['ez_setup', 'examples', 'tests']) @@ -46,11 +46,12 @@ EXTRAS_REQUIRE = {} # You do not need to read beyond this line PUBLISH_COMMAND = '{0} setup.py sdist bdist_wheel upload -r pypi'.format( sys.executable) -GS_COMMAND = ('gs lml v0.0.2 ' + - "Find 0.0.2 in changelog for more details") +GS_COMMAND = ('gs lml v0.0.3 ' + + "Find 0.0.3 in changelog for more details") NO_GS_MESSAGE = ('Automatic github release is disabled. ' + 'Please install gease to enable it.') -UPLOAD_FAILED_MSG = ('Upload failed. please run "%s" yourself.') +UPLOAD_FAILED_MSG = ( + 'Upload failed. please run "%s" yourself.' % PUBLISH_COMMAND) HERE = os.path.abspath(os.path.dirname(__file__)) @@ -75,6 +76,8 @@ class PublishCommand(Command): try: self.status('Removing previous builds...') rmtree(os.path.join(HERE, 'dist')) + rmtree(os.path.join(HERE, 'build')) + rmtree(os.path.join(HERE, 'lml.egg-info')) except OSError: pass @@ -91,6 +94,11 @@ class PublishCommand(Command): sys.exit() +SETUP_COMMANDS.update({ + 'publish': PublishCommand +}) + + def has_gease(): """ test if github release command is installed @@ -115,7 +123,8 @@ def read_files(*files): def read(afile): """Read a file into setup""" - with codecs.open(afile, 'r', 'utf-8') as opened_file: + the_relative_file = os.path.join(HERE, afile) + with codecs.open(the_relative_file, 'r', 'utf-8') as opened_file: content = filter_out_test_code(opened_file) content = "".join(list(content)) return content @@ -164,7 +173,5 @@ if __name__ == '__main__': include_package_data=True, zip_safe=False, classifiers=CLASSIFIERS, - cmdclass={ - 'publish': PublishCommand, - } + cmdclass=SETUP_COMMANDS ) diff --git a/tests/test_plugin_manager.py b/tests/test_plugin_manager.py index 723d74f..a49d2fa 100644 --- a/tests/test_plugin_manager.py +++ b/tests/test_plugin_manager.py @@ -1,6 +1,6 @@ from mock import patch from lml.plugin import PluginManager, PLUG_IN_MANAGERS -from lml.plugin import PluginInfo +from lml.plugin import PluginInfo, _show_me_your_name from lml.plugin import CACHED_PLUGIN_INFO from nose.tools import eq_, raises @@ -140,5 +140,38 @@ def test_register_a_plugin_function_2(): assert non_existent_plugin in CACHED_PLUGIN_INFO +def test_primary_key(): + manager = PluginManager("test plugin2") + + @PluginInfo('test plugin2', tags=['primary key', 'key 1', 'key 2']) + class MyPlugin(object): + pass + + pk = manager.get_primary_key('key 1') + eq_(pk, 'primary key') + + +def test_dict_as_plugin_payload(): + manager = PluginManager("test plugin3") + + plugin = PluginInfo('test plugin3', tags=['primary key', 'key 1', 'key 2']) + plugin(dict(B=1)) + + instance = manager.load_me_now('key 1') + eq_(instance, dict(B=1)) + + +def test_show_me_your_name(): + + class Test(object): + pass + + name = _show_me_your_name(Test) + eq_(name, 'Test') + + name2 = _show_me_your_name(dict(A=1)) + assert 'dict' in name2 + + def make_me_a_plugin_info(plugin_name): return PluginInfo(plugin_name, 'abs_path', custom='property')