[Python-modules-commits] [python-cement] 01/13: Import python-cement_2.10.0.orig.tar.gz

Michael Fladischer fladi at moszumanska.debian.org
Thu Sep 8 08:26:39 UTC 2016


This is an automated email from the git hooks/post-receive script.

fladi pushed a commit to branch master
in repository python-cement.

commit b82fca7bb8fa81246ba820510a1a6b3d6488223e
Author: Michael Fladischer <FladischerMichael at fladi.at>
Date:   Mon Jul 18 12:12:33 2016 +0200

    Import python-cement_2.10.0.orig.tar.gz
---
 .gitignore                                       |   3 +
 .travis.yml                                      |   2 +-
 CONTRIBUTORS                                     |   2 +
 ChangeLog                                        |  34 ++-
 README.md                                        |   8 +-
 cement/core/backend.py                           |   6 +-
 cement/core/controller.py                        |   5 +-
 cement/core/extension.py                         |   3 -
 cement/core/foundation.py                        | 217 ++++++++++++--
 cement/core/handler.py                           |  76 ++++-
 cement/core/interface.py                         |   8 +
 cement/core/log.py                               |  11 +-
 cement/core/output.py                            |  52 +++-
 cement/core/plugin.py                            |   2 +-
 cement/ext/ext_argcomplete.py                    |   4 +-
 cement/ext/ext_argparse.py                       |  25 +-
 cement/ext/ext_colorlog.py                       |   2 +-
 cement/ext/ext_configobj.py                      |   4 +-
 cement/ext/ext_configparser.py                   |   3 +-
 cement/ext/ext_dummy.py                          |   2 +-
 cement/ext/ext_genshi.py                         |   3 +-
 cement/ext/ext_handlebars.py                     | 255 ++++++++++++++++
 cement/ext/{ext_genshi.py => ext_jinja2.py}      |  66 +++--
 cement/ext/ext_json.py                           |  62 +++-
 cement/ext/ext_json_configobj.py                 |  16 +-
 cement/ext/ext_logging.py                        |  49 +++-
 cement/ext/ext_memcached.py                      |   1 -
 cement/ext/ext_mustache.py                       |  10 +-
 cement/ext/ext_plugin.py                         |  48 +--
 cement/ext/{ext_memcached.py => ext_redis.py}    | 152 +++++-----
 cement/ext/ext_reload_config.py                  |   5 +-
 cement/ext/ext_tabulate.py                       |   3 +-
 cement/ext/ext_watchdog.py                       | 355 +++++++++++++++++++++++
 cement/ext/ext_yaml.py                           |  12 +-
 cement/ext/ext_yaml_configobj.py                 |   2 -
 cement/utils/misc.py                             |  34 +--
 cement/utils/shell.py                            |   8 +-
 cement/utils/test.py                             |  30 +-
 doc/build/.placeholder                           |   0
 doc/source/api/ext/ext_genshi.rst                |   2 +-
 doc/source/api/ext/ext_handlebars.rst            |   9 +
 doc/source/api/ext/ext_jinja2.rst                |   9 +
 doc/source/api/ext/ext_redis.rst                 |   9 +
 doc/source/api/ext/ext_watchdog.rst              |   9 +
 doc/source/api/index.rst                         |   5 +
 doc/source/conf.py                               |   6 +-
 doc/source/dev/application_design.rst            |   2 +-
 doc/source/dev/boss_templates.rst                |   2 +-
 doc/source/dev/interfaces_and_handlers.rst       |   4 +-
 doc/source/dev/logging.rst                       |   8 +-
 doc/source/dev/output.rst                        |   3 +-
 doc/source/dev/plugins.rst                       |  76 ++++-
 doc/source/dev/quickstart.rst                    |   2 +-
 doc/source/dev/testing.rst                       |   8 +-
 doc/source/examples/sighup_reload.rst            |   4 +-
 doc/source/index.rst                             |   8 +-
 doc/source/upgrading.rst                         |  20 ++
 doc/source/whats_new.rst                         | 159 +++++++++-
 examples/abstract_base_controllers/myapp.py      | 104 +++++++
 examples/app_version/myapp.py                    |  35 +++
 examples/append_config_path/myapp.py             |  39 +++
 examples/arbitrary_extra_arguments/myapp.py      |  48 +++
 examples/bash_auto_completion/myapp.py           |  85 ++++++
 examples/controllers_with_same_label/myapp.py    |  72 +++++
 examples/load_extensions_via_config/myapp.py     |  46 +++
 examples/multiple_stacked_controllers/myapp.py   |  89 ++++++
 examples/reload_config/myapp.py                  |  39 +++
 requirements-dev-py3.txt                         |   5 +
 requirements-dev.txt                             |   5 +
 scripts/devtools.py                              |  18 +-
 scripts/travis.sh                                |   1 +
 scripts/vagrant/up.sh                            |  51 +++-
 setup.cfg                                        |   1 +
 tests/core/backend_tests.py                      |   2 +
 tests/core/config_tests.py                       |   9 +-
 tests/core/foundation_tests.py                   |  52 ++++
 tests/core/handler_tests.py                      |  32 +-
 tests/core/hook_tests.py                         |   2 +
 tests/core/interface_tests.py                    |   5 +
 tests/core/log_tests.py                          |   3 +-
 tests/core/output_tests.py                       |  12 +-
 tests/core/plugin_tests.py                       | 183 +++++-------
 tests/ext/alarm_tests.py                         |   1 +
 tests/ext/argparse_tests.py                      |  28 +-
 tests/ext/configobj_tests.py                     |  17 +-
 tests/ext/daemon_tests.py                        |  26 +-
 tests/ext/genshi_tests.py                        |   1 +
 tests/ext/handlebars_tests.py                    |  61 ++++
 tests/ext/jinja2_tests.py                        |  93 ++++++
 tests/ext/json_configobj_tests.py                |  13 +-
 tests/ext/json_tests.py                          |   7 +-
 tests/ext/logging_tests.py                       |  22 +-
 tests/ext/memcached_tests.py                     |   2 +
 tests/ext/mustache_tests.py                      |   1 +
 tests/ext/redis_tests.py                         |  55 ++++
 tests/ext/tabulate_tests.py                      |   1 +
 tests/ext/watchdog_tests.py                      |  94 ++++++
 tests/ext/yaml_configobj_tests.py                |  17 +-
 tests/ext/yaml_tests.py                          |  11 +-
 tests/templates/bad_template.handlebars          |   0
 tests/templates/bad_template.jinja2              |   0
 tests/templates/test_base_template.handlebars    |   1 +
 tests/templates/test_partial_template.handlebars |   1 +
 tests/templates/test_template.handlebars         |   1 +
 tests/templates/test_template.jinja2             |   1 +
 tests/templates/test_template_child.jinja2       |   2 +
 tests/templates/test_template_parent.jinja2      |   1 +
 tests/templates/test_template_utf8.jinja2        |   1 +
 tests/utils/fs_tests.py                          |  27 +-
 tests/utils/misc_tests.py                        |   7 +-
 tests/utils/version_tests.py                     |   2 +-
 111 files changed, 2792 insertions(+), 565 deletions(-)

diff --git a/.gitignore b/.gitignore
index f1675f3..8f2ebcc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,3 +65,6 @@ extensions
 .env
 .vagrant
 myapp*.py
+
+# redis test artifacts
+dump.rdb
diff --git a/.travis.yml b/.travis.yml
index 1b179aa..37fff20 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,9 +6,9 @@ os:
 python:
   - 2.6
   - 2.7
-  - 3.2
   - 3.3
   - 3.4
   - 3.5
 services:
   - memcached
+  - redis
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 6479cba..432e9f7 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -7,3 +7,5 @@ documentation, or testing.
     * BJ Dierkes (derks) - Creator, Primary Maintainer
     * Kyle Rockman (rocktavious)
     * Tomasz Czyż (spinus)
+    * Ildar Akhmetgaleev (akhilman)
+    * Nicolas Brisac (zacbri)
diff --git a/ChangeLog b/ChangeLog
index 3362442..ffe228a 100755
--- a/ChangeLog
+++ b/ChangeLog
@@ -19,27 +19,53 @@ any incompatible changes, and how to update your application to fix them.
 Also check out the :ref:`whats_new` section for details on new features.
 
 
-2.8.2 - Fri Feb 26, 2016
+2.10.0 - Thu July 14, 2016
 ------------------------------------------------------------------------------
 
 Bugs:
 
+    * :issue:`363` - CementTestCase does not delete temporary 
+      files/directories
     * :issue:`346` - AttributeError: 'module' object has no attribute 'SIGHUP'
       on Windows
-
+    * :issue:`352` - ``CementApp.extend()`` breaks on ``CementApp.reload()``
+    * :issue:`366` - Output handler override options dissappear
+    * :issue:`385` - JsonOutputHandler/YamlOutputHandler/MustacheOutputHandler 
+      Do not pass keyword args down to backend render functions
+    * :issue:`393` - ``CementApp.Meta.hooks`` ignored for hooks defined by 
+      extensions
 
 Features:
 
-    * None
+    * :issue:`350` - Support for plugin directories
+    * :issue:`370` - Handlebars templating support
+    * :pr:`371` - Jinja2 templating support
+    * :issue:`373` - Switch over to using Flake8 for PEP8 and style compliance
+    * :pr:`375` - Redis cache handler support
+    * :issue:`379` - Support for alternative config file extensions
+    * :issue:`380` - Support for Cython/Compiled Plugins
+    * :issue:`389` - ConfigObj support for Python 3
+    * :issue:`394` - Watchdog extension for cross-platform filesystem event 
+      monitoring
+    * :issue:`395` - Ability to pass metadata keyword arguments to handlers
+      via ``CementApp.Meta.meta_defaults``.
 
 Refactoring;
 
-    * None
+    * :issue:`386` - Partially deprecated use of ``imp`` in favor of 
+      ``importlib`` on Python >= 3.1
+    * :issue:`390` - ArgparseArgumentHandler should store unknown arguments
 
 Incompatible:
 
     * None
 
+Deprecation:
+
+    * :issue:`365` - Deprecated ``LoggingLogHandler.warn()``
+    * :issue:`372` - Deprecated Explicit Python 3.2 Support
+    * :issue:`376` - Deprecated ``cement.core.interface.list()``
+
 
 2.8.0 - Wed Feb 24, 2016
 ------------------------------------------------------------------------------
diff --git a/README.md b/README.md
index 81b66b6..6eab661 100644
--- a/README.md
+++ b/README.md
@@ -30,10 +30,10 @@ Cement core features include (but are not limited to):
  * Cache handler interface adds caching support for improved performance
  * Controller handler supports sub-commands, and nested controllers
  * Zero external dependencies* (not including optional extensions)
- * 100% test coverage using `nose`
- * 100% PEP8 compliant using `pep8` and `autopep8` tools
+ * 100% test coverage using `nose` and `coverage`
+ * 100% PEP8 and style compliant using `flake8`
  * Extensive Sphinx documentation
- * Tested on Python 2.6, 2.7, 3.2, 3.3, 3.4, and 3.5
+ * Tested on Python 2.6, 2.7, 3.3, 3.4, and 3.5
 
 *Note that argparse is required as an external dependency for Python < 2.7
 and < 3.2.  Additionally, some optional extensions that are shipped with the
@@ -45,7 +45,7 @@ along with their application, as Cement explicitly does not include them.*
 More Information
 ----------------
 
- * DOCS: http://builtoncement.com/2.8/
+ * DOCS: http://builtoncement.com/2.10/
  * CODE: http://github.com/datafolklabs/cement/
  * PYPI: http://pypi.python.org/pypi/cement/
  * SITE: http://builtoncement.com/
diff --git a/cement/core/backend.py b/cement/core/backend.py
index 3f2b053..5866f9a 100644
--- a/cement/core/backend.py
+++ b/cement/core/backend.py
@@ -1,7 +1,7 @@
 """Cement core backend module."""
 
-VERSION = (2, 8, 2, 'final', 0)  # pragma: nocover
+VERSION = (2, 10, 0, 'final', 0)  # pragma: nocover
 
 # global hooks/handlers (DEPRECATED)
-__handlers__ = {}  # pragma: nocover
-__hooks__ = {}  # pragma: nocover
+__handlers__ = {}   # pragma: nocover
+__hooks__ = {}      # pragma: nocover
diff --git a/cement/core/controller.py b/cement/core/controller.py
index d39a9ee..24ae042 100644
--- a/cement/core/controller.py
+++ b/cement/core/controller.py
@@ -171,7 +171,7 @@ class expose(object):
         metadict['func_name'] = func.__name__
         metadict['exposed'] = True
         metadict['hide'] = self.hide
-        metadict['help'] = self.help
+        metadict['help'] = self.help or func.__doc__
         metadict['aliases'] = self.aliases
         metadict['aliases_only'] = self.aliases_only
         metadict['controller'] = None  # added by the controller
@@ -365,7 +365,7 @@ class CementBaseController(handler.CementBaseHandler):
                 commands.append(func)
 
         # process stacked controllers second for commands and args
-        for contr in handler.list('controller'):
+        for contr in self.app.handler.list('controller'):
             # don't include self here
             if contr == self.__class__:
                 continue
@@ -428,7 +428,6 @@ class CementBaseController(handler.CementBaseHandler):
         self._visible_commands.sort()
 
     def _get_dispatch_command(self):
-        default_func = self._meta.default_func
         default_func_key = re.sub('_', '-', self._meta.default_func)
 
         if (len(self.app.argv) <= 0) or (self.app.argv[0].startswith('-')):
diff --git a/cement/core/extension.py b/cement/core/extension.py
index c689442..389e1b4 100644
--- a/cement/core/extension.py
+++ b/cement/core/extension.py
@@ -4,9 +4,6 @@ import sys
 from ..core import exc, interface, handler
 from ..utils.misc import minimal_logger
 
-if sys.version_info[0] >= 3:
-    from imp import reload  # pragma: no cover
-
 LOG = minimal_logger(__name__)
 
 
diff --git a/cement/core/foundation.py b/cement/core/foundation.py
index 7c0b204..c392e61 100644
--- a/cement/core/foundation.py
+++ b/cement/core/foundation.py
@@ -1,25 +1,31 @@
 """Cement core foundation module."""
 
-import re
 import os
 import sys
 import signal
-import copy
 import platform
 from time import sleep
-from ..core import backend, exc, log, config, plugin, interface
+from ..core import backend, exc, log, config, plugin
 from ..core import output, extension, arg, controller, meta, cache, mail
 from ..core.handler import HandlerManager
 from ..core.hook import HookManager
 from ..utils.misc import is_true, minimal_logger
 from ..utils import fs
 
-if sys.version_info[0] >= 3:
-    from imp import reload  # pragma: nocover
+# The `imp` module is deprecated in favor of `importlib` in 3.4, but it
+# wasn't introduced until 3.1.  Finally, reload is a builtin on Python < 3
+pyver = sys.version_info
+if pyver[0] >= 3 and pyver[1] >= 4:                # pragma: nocover  # noqa
+    from importlib import reload as reload_module  # pragma: nocover  # noqa
+elif pyver[0] >= 3:                                # pragma: nocover  # noqa
+    from imp import reload as reload_module        # pragma: nocover  # noqa
+else:                                              # pragma: nocover  # noqa
+    reload_module = reload                         # pragma: nocover  # noqa
+
 
 LOG = minimal_logger(__name__)
 if platform.system() == 'Windows':
-    SIGNALS = [signal.SIGTERM, signal.SIGINT]
+    SIGNALS = [signal.SIGTERM, signal.SIGINT]   # pragma: nocover
 else:
     SIGNALS = [signal.SIGTERM, signal.SIGINT, signal.SIGHUP]
 
@@ -36,7 +42,7 @@ def add_handler_override_options(app):
         return
 
     for i in app._meta.handler_override_options:
-        if i not in interface.list():
+        if i not in app.handler.list_types():
             LOG.debug("interface '%s'" % i +
                       " is not defined, can not override handlers")
             continue
@@ -204,6 +210,11 @@ class CementApp(meta.MetaMixin):
         ``sys.exit(X)`` where ``X`` is ``self.exit_code``.
         """
 
+        config_extension = '.conf'
+        """
+        Extension used to identify application and plugin configuration files.
+        """
+
         config_files = None
         """
         List of config files to parse.
@@ -222,6 +233,9 @@ class CementApp(meta.MetaMixin):
         Files are loaded in order, and have precedence in order.  Therefore,
         the last configuration loaded has precedence (and overwrites settings
         loaded from previous configuration files).
+
+        Note that ``.conf`` is the default config file extension, defined by
+        ``CementApp.Meta.config_extension``.
         """
 
         plugins = []
@@ -234,7 +248,8 @@ class CementApp(meta.MetaMixin):
         plugin_config_dirs = None
         """
         A list of directory paths where plugin config files can be found.
-        Files must end in `.conf` or they will be ignored.
+        Files must end in ``.conf`` (or the extension defined by
+        ``CementApp.Meta.config_extension``) or they will be ignored.
 
         Note: Though ``CementApp.Meta.plugin_config_dirs`` is ``None``, Cement
         will set this to a default list based on ``CementApp.Meta.label``.
@@ -252,9 +267,11 @@ class CementApp(meta.MetaMixin):
 
         plugin_config_dir = None
         """
-        A directory path where plugin config files can be found.  Files
-        must end in `.conf`.  By default, this setting is also overridden
-        by the ``[<app_label>] -> plugin_config_dir`` config setting parsed in
+        A directory path where plugin config files can be found.  Files must
+        end in ``.conf`` (or the extension defined by
+        ``CementApp.Meta.config_extension``) or they will be ignored.  By
+        default, this setting is also overridden by the
+        ``[<app_label>] -> plugin_config_dir`` config setting parsed in
         any of the application configuration files.
 
         If set, this item will be **appended** to
@@ -399,6 +416,32 @@ class CementApp(meta.MetaMixin):
         config_defaults = None
         """Default configuration dictionary.  Must be of type 'dict'."""
 
+        meta_defaults = {}
+        """
+        Default metadata dictionary used to pass high level options from the
+        application down to handlers at the point they are registered by the
+        framework **if the handler has not already been instantiated**.
+
+        For example, if requiring the ``json`` extension, you might want to
+        override ``JsonOutputHandler.Meta.json_module`` with ``ujson`` by
+        doing the following
+
+        .. code-block:: python
+
+            from cement.core.foundation import CementApp
+            from cement.utils.misc import init_defaults
+
+            META = init_defaults('output.json')
+            META['output.json']['json_module'] = 'ujson'
+
+            class MyApp(CementApp):
+                class Meta:
+                    label = 'myapp'
+                    extensions = ['json']
+                    meta_defaults = META
+
+        """
+
         catch_signals = SIGNALS
         """
         List of signals to catch, and raise exc.CaughtSignal for.
@@ -634,6 +677,41 @@ class CementApp(meta.MetaMixin):
         has changed or exists.
         """
 
+        alternative_module_mapping = {}
+        """
+        EXPERIMENTAL FEATURE: This is an experimental feature added in Cement
+        2.9.x and may or may not be removed in future versions of Cement.
+
+        Dictionary of alternative, **drop-in** replacement modules to use
+        selectively throughout the application, framework, or
+        extensions.  Developers can optionally use the
+        ``CementApp.__import__()`` method to import simple modules, and if
+        that module exists in this mapping it will import the alternative
+        library in it's place.
+
+        This is a low-level feature, and may not produce the results you are
+        expecting.  It's purpose is to allow the developer to replace specific
+        modules at a high level.  Example: For an application wanting to use
+        ``ujson`` in place of ``json``, the developer could set the following:
+
+        .. code-block:: python
+
+            alternative_module_mapping = {
+                'json' : 'ujson',
+            }
+
+        In the app, you would then load ``json`` as:
+
+        .. code-block:: python
+
+            _json = app.__import__('json')
+            _json.dumps(data)
+
+
+        Obviously, the replacement module **must be** a drop-in replace and
+        function the same.
+        """
+
     def __init__(self, label=None, **kw):
         super(CementApp, self).__init__(**kw)
 
@@ -651,8 +729,10 @@ class CementApp(meta.MetaMixin):
         self._loaded_bootstrap = None
         self._parsed_args = None
         self._last_rendered = None
+        self._extended_members = []
         self.__saved_stdout__ = None
         self.__saved_stderr__ = None
+        self.__retry_hooks__ = []
         self.handler = None
         self.hook = None
 
@@ -714,6 +794,8 @@ class CementApp(meta.MetaMixin):
         LOG.debug("extending appication with '.%s' (%s)" %
                   (member_name, member_object))
         setattr(self, member_name, member_object)
+        if member_name not in self._extended_members:
+            self._extended_members.append(member_name)
 
     def _validate_label(self):
         if not self._meta.label:
@@ -756,7 +838,7 @@ class CementApp(meta.MetaMixin):
 
                 self._loaded_bootstrap = sys.modules[self._meta.bootstrap]
             else:
-                reload(self._loaded_bootstrap)
+                reload_module(self._loaded_bootstrap)
 
         for res in self.hook.run('pre_setup', self):
             pass
@@ -772,6 +854,9 @@ class CementApp(meta.MetaMixin):
         self._setup_output_handler()
         self._setup_controllers()
 
+        for hook_spec in self.__retry_hooks__:
+            self.hook.register(*hook_spec)
+
         for res in self.hook.run('post_setup', self):
             pass
 
@@ -843,6 +928,9 @@ class CementApp(meta.MetaMixin):
         :returns: ``None``
         """
         LOG.debug('reloading the %s application' % self._meta.label)
+        for member in self._extended_members:
+            delattr(self, member)
+        self._extended_members = []
         self.handler.__handlers__ = {}
         self.hook.__hooks__ = {}
         self._lay_cement()
@@ -931,11 +1019,11 @@ class CementApp(meta.MetaMixin):
 
         """
         if not is_true(self._meta.ignore_deprecation_warnings):
-            self.log.warn("Cement Deprecation Warning: " +
-                          "CementApp.get_last_rendered() has been " +
-                          "deprecated, and will be removed in future " +
-                          "versions of Cement.  You should use the " +
-                          "CementApp.last_rendered property instead.")
+            self.log.warning("Cement Deprecation Warning: " +
+                             "CementApp.get_last_rendered() has been " +
+                             "deprecated, and will be removed in future " +
+                             "versions of Cement.  You should use the " +
+                             "CementApp.last_rendered property instead.")
         return self._last_rendered
 
     @property
@@ -987,7 +1075,7 @@ class CementApp(meta.MetaMixin):
             self._suppress_output()
 
         # Forward/Backward compat, see Issue #311
-        if self._meta.use_backend_globals:
+        if self._meta.use_backend_globals is True:
             backend.__hooks__ = {}
             backend.__handlers__ = {}
             self.handler = HandlerManager(use_backend_globals=True)
@@ -1014,14 +1102,24 @@ class CementApp(meta.MetaMixin):
             self.hook.define(label)
 
         # register some built-in framework hooks
-        self.hook.register(
-            'post_setup', add_handler_override_options, weight=-99)
+        self.hook.register('post_setup', add_handler_override_options,
+                           weight=-99)
         self.hook.register('post_argument_parsing',
                            handler_override, weight=-99)
 
-        # register application hooks from meta
-        for label, func in self._meta.hooks:
-            self.hook.register(label, func)
+        # register application hooks from meta.  the hooks listed in
+        # CementApp.Meta.hooks are registered here, so obviously can not be
+        # for any hooks other than the builtin framework hooks that we just
+        # defined here (above).  Anything that we couldn't register here
+        # will be retried after setup
+        self.__retry_hooks__ = []
+        for hook_spec in self._meta.hooks:
+            if not self.hook.defined(hook_spec[0]):
+                LOG.debug('hook %s not defined, will retry after setup' %
+                          hook_spec[0])
+                self.__retry_hooks__.append(hook_spec)
+            else:
+                self.hook.register(*hook_spec)
 
         # define and register handlers
         self.handler.define(extension.IExtension)
@@ -1098,7 +1196,17 @@ class CementApp(meta.MetaMixin):
             self.catch_signal(signum)
 
     def _resolve_handler(self, handler_type, handler_def, raise_error=True):
-        han = self.handler.resolve(handler_type, handler_def, raise_error)
+        meta_defaults = {}
+        if type(handler_def) == str:
+            _meta_label = "%s.%s" % (handler_type, handler_def)
+            meta_defaults = self._meta.meta_defaults.get(_meta_label, {})
+        elif hasattr(handler_def, 'Meta'):
+            _meta_label = "%s.%s" % (handler_type, handler_def.Meta.label)
+            meta_defaults = self._meta.meta_defaults.get(_meta_label, {})
+
+        han = self.handler.resolve(handler_type, handler_def,
+                                   raise_error=raise_error,
+                                   meta_defaults=meta_defaults)
         if han is not None:
             han._setup(self)
             return han
@@ -1123,10 +1231,11 @@ class CementApp(meta.MetaMixin):
 
         if self._meta.config_files is None:
             label = self._meta.label
+            ext = self._meta.config_extension
 
             self._meta.config_files = [
-                os.path.join('/', 'etc', label, '%s.conf' % label),
-                os.path.join(fs.HOME_DIR, '.%s.conf' % label),
+                os.path.join('/', 'etc', label, '%s%s' % (label, ext)),
+                os.path.join(fs.HOME_DIR, '.%s%s' % (label, ext)),
                 os.path.join(fs.HOME_DIR, '.%s' % label, 'config'),
             ]
 
@@ -1238,10 +1347,14 @@ class CementApp(meta.MetaMixin):
 
         # template dirs
         if self._meta.template_dirs is None:
-            self._meta.template_dirs = [
+            self._meta.template_dirs = []
+            paths = [
                 os.path.join(fs.HOME_DIR, '.%s' % label, 'templates'),
                 '/usr/lib/%s/templates' % label,
             ]
+            for path in paths:
+                self.add_template_dir(path)
+
         template_dir = self._meta.template_dir
         if template_dir is not None:
             if template_dir not in self._meta.template_dirs:
@@ -1327,6 +1440,56 @@ class CementApp(meta.MetaMixin):
         """
         pass
 
+    def add_template_dir(self, path):
+        """
+        Append a directory path to the list of template directories to parse
+        for templates.
+
+        :param path: Directory path that contains template files.
+
+        Usage:
+
+        .. code-block:: python
+
+            app.add_template_dir('/path/to/my/templates')
+
+        """
+        path = fs.abspath(path)
+        if path not in self._meta.template_dirs:
+            self._meta.template_dirs.append(path)
+
+    def remove_template_dir(self, path):
+        """
+        Remove a directory path from the list of template directories to parse
+        for templates.
+
+        :param path: Directory path that contains template files.
+
+        Usage:
+
+        .. code-block:: python
+
+            app.remove_template_dir('/path/to/my/templates')
+
+        """
+        path = fs.abspath(path)
+        if path in self._meta.template_dirs:
+            self._meta.template_dirs.remove(path)
+
+    def __import__(self, obj, from_module=None):
+        # EXPERIMENTAL == UNDOCUMENTED
+        mapping = self._meta.alternative_module_mapping
+
+        if from_module is not None:
+            _from = mapping.get(from_module, from_module)
+            _loaded = __import__(_from, globals(), locals(), [obj], 0)
+            return getattr(_loaded, obj)
+        else:
+            obj = mapping.get(obj, obj)
+            _loaded = __import__(obj, globals(), locals(), [], 0)
+
+        return _loaded
+
     def __enter__(self):
         self.setup()
         return self
diff --git a/cement/core/handler.py b/cement/core/handler.py
index d8360cc..df2bcb3 100644
--- a/cement/core/handler.py
+++ b/cement/core/handler.py
@@ -86,6 +86,23 @@ class HandlerManager(object):
             res.append(self.__handlers__[handler_type][label])
         return res
 
+    def list_types(self):
+        """
+        Return a list of handler types (interface labels).
+
+        :returns: List of handlers types (interface labels).
+        :rtype: ``list``
+        :raises: :class:`cement.core.exc.FrameworkError`
+
+        Usage:
+
+        .. code-block:: python
+
+            app.handler.list_types()
+
+        """
+        return self.__handlers__.keys()
+
     def define(self, interface):
         """
         Define a handler based on the provided interface.  Defines a handler
@@ -141,7 +158,7 @@ class HandlerManager(object):
         else:
             return False
 
-    def register(self, handler_obj):
+    def register(self, handler_obj, force=False):
         """
         Register a handler object to a handler.  If the same object is already
         registered then no exception is raised, however if a different object
@@ -149,6 +166,8 @@ class HandlerManager(object):
         raised.
 
         :param handler_obj: The uninstantiated handler object to register.
+        :param force: Whether to allow replacement if an existing
+         handler of the same ``label`` is already registered.
         :raises: :class:`cement.core.exc.InterfaceError`
         :raises: :class:`cement.core.exc.FrameworkError`
 
@@ -192,9 +211,19 @@ class HandlerManager(object):
             raise exc.FrameworkError("Handler type '%s' doesn't exist." %
                                      handler_type)
         if obj._meta.label in self.__handlers__[handler_type] and \
-                self.__handlers__[handler_type][obj._meta.label] != obj:
-            raise exc.FrameworkError("handlers['%s']['%s'] already exists" %
-                                     (handler_type, obj._meta.label))
+                self.__handlers__[handler_type][obj._meta.label] != orig_obj:
+
+            if force is True:
+                LOG.debug(
+                    "handlers['%s']['%s'] already exists" %
+                    (handler_type, obj._meta.label) +
+                    ", but `force==True`"
+                )
+            else:
+                raise exc.FrameworkError(
+                    "handlers['%s']['%s'] already exists" %
+                    (handler_type, obj._meta.label)
+                )
 
         interface = self.__handlers__[handler_type]['__interface__']
         if hasattr(interface.IMeta, 'validator'):
@@ -203,7 +232,7 @@ class HandlerManager(object):
             LOG.debug("Interface '%s' does not have a validator() function!" %
                       interface)
 
-        self.__handlers__[handler_type][obj.Meta.label] = orig_obj
+        self.__handlers__[handler_type][obj._meta.label] = orig_obj
 
     def registered(self, handler_type, handler_label):
         """
@@ -227,18 +256,21 @@ class HandlerManager(object):
 
         return False
 
-    def resolve(self, handler_type, handler_def, raise_error=True):
+    def resolve(self, handler_type, handler_def, **kwargs):
         """
         Resolves the actual handler, as it can be either a string identifying
         the handler to load from self.__handlers__, or it can be an
         instantiated or non-instantiated handler class.
 
         :param handler_type: The type of handler (aka the interface label)
-        :param hander_def: The handler as defined in CementApp.Meta.
+        :param handler_def: The handler as defined in CementApp.Meta.
         :type handler_def: str, uninstantiated object, or instantiated object
-        :param raise_error: Whether or not to raise an exception if unable
+        :keyword raise_error: Whether or not to raise an exception if unable
             to resolve the handler.
         :type raise_error: boolean
+        :keywork meta_defaults: Optional meta-data dictionary used as
+         defaults to pass when instantiating uninstantiated handlers.  See
+         ``CementApp.Meta.meta_defaults``.
         :returns: The instantiated handler object.
 
         Usage:
@@ -255,15 +287,18 @@ class HandlerManager(object):
             log = app.handler.resolve('log', ColorLogHandler())
 
         """
+        raise_error = kwargs.get('raise_error', True)
+        meta_defaults = kwargs.get('meta_defaults', {})
         han = None
+
         if type(handler_def) == str:
-            han = self.get(handler_type, handler_def)()
+            han = self.get(handler_type, handler_def)(**meta_defaults)
         elif hasattr(handler_def, '_meta'):
             if not self.registered(handler_type, handler_def._meta.label):
                 self.register(handler_def.__class__)
             han = handler_def
         elif hasattr(handler_def, 'Meta'):
-            han = handler_def()
+            han = handler_def(**meta_defaults)
             if not self.registered(handler_type, han._meta.label):
                 self.register(handler_def)
 
@@ -416,9 +451,9 @@ def list(handler_type):
     # only log debug for now as this won't be removed until Cement 3.x and
     # we don't have access to CementApp.Meta.ignore_deprecation_warnings here
     LOG.debug(
-        'Cement Deprecation Warning: `handler.get()` has been deprecated, '
+        'Cement Deprecation Warning: `handler.list()` has been deprecated, '
         'and will be removed in future versions of Cement.  You should now '
-        'use `CementApp.handler.get()` instead.'
+        'use `CementApp.handler.list()` instead.'
     )
 
     if handler_type not in backend.__handlers__:
@@ -511,7 +546,7 @@ def defined(handler_type):
         return False
 
 
-def register(handler_obj):
+def register(handler_obj, force=False):
     """
     DEPRECATION WARNING: This function is deprecated as of Cement 2.7.x and
     will be removed in future versions of Cement.
@@ -525,6 +560,8 @@ def register(handler_obj):
     raised.
 
     :param handler_obj: The uninstantiated handler object to register.
+    :param force: Whether to allow replacement if an existing
+     handler of the same ``label`` is already registered.
     :raises: cement.core.exc.InterfaceError
     :raises: cement.core.exc.FrameworkError
 
@@ -578,8 +615,17 @@ def register(handler_obj):
                                  handler_type)
     if obj._meta.label in backend.__handlers__[handler_type] and \
             backend.__handlers__[handler_type][obj._meta.label] != obj:
-        raise exc.FrameworkError("handlers['%s']['%s'] already exists" %
-                                 (handler_type, obj._meta.label))
+        if force is True:
+            LOG.debug(
+                "handlers['%s']['%s'] already exists" %
+                (handler_type, obj._meta.label) +
+                ", but `force==True`"
+            )
+        else:
+            raise exc.FrameworkError(
+                "handlers['%s']['%s'] already exists" %
+                (handler_type, obj._meta.label)
+            )
 
     interface = backend.__handlers__[handler_type]['__interface__']
     if hasattr(interface.IMeta, 'validator'):
diff --git a/cement/core/interface.py b/cement/core/interface.py
index bca357b..0dc3c15 100644
--- a/cement/core/interface.py
+++ b/cement/core/interface.py
@@ -10,12 +10,20 @@ DEFAULT_META = ['interface', 'label', 'config_defaults', 'config_section']
 
 def list():
     """
+    DEPRECATION WARNING: This function is deprecated as of Cement 2.9
+    in favor of the `CementApp.handler.list_types()` function, and will be
+    removed in future versions of Cement.
+
     Return a list of defined interfaces (handler types).
 
     :returns: List of defined interfaces
     :rtype: ``list``
 
     """
+
+    # FIXME: Can't print a deprecation warning here because we don't have
+    # access to the app... and this is too deep to use minimal logger... ;\
+
     return backend.__handlers__.keys()
 
 
diff --git a/cement/core/log.py b/cement/core/log.py
index c3a9c20..efbe229 100644
--- a/cement/core/log.py
+++ b/cement/core/log.py
@@ -3,7 +3,7 @@ Cement core log module.
 
 """
 
-from ..core import exc, interface, handler
+from ..core import interface, handler
 
 
 def log_validator(klass, obj):
@@ -14,7 +14,8 @@ def log_validator(klass, obj):
         'set_level',
         'get_level',
         'info',
-        'warn',
+        'warn',  # DEPRECATED
+        'warning',
         'error',
         'fatal',
         'debug',
@@ -72,7 +73,7 @@ class ILog(interface.Interface):
     def set_level():
         """
         Set the log level.  Must except atleast one of:
-            ``['INFO', 'WARN', 'ERROR', 'DEBUG', or 'FATAL']``.
+            ``['INFO', 'WARNING', 'ERROR', 'DEBUG', or 'FATAL']``.
 
         """
 
@@ -87,9 +88,9 @@ class ILog(interface.Interface):
 
         """
 
-    def warn(self, msg):
+    def warning(self, msg):
         """
-        Log to the 'WARN' facility.
+        Log to the 'WARNING' facility.
 
         :param msg: The message to log.
 
diff --git a/cement/core/output.py b/cement/core/output.py
index c66023c..6bdd201 100644
--- a/cement/core/output.py
+++ b/cement/core/output.py
@@ -3,7 +3,8 @@
 import os
 import sys
 import pkgutil
-from ..core import backend, exc, interface, handler
+import re
+from ..core import exc, interface, handler
 from ..utils.misc import minimal_logger
 from ..utils import fs
 
@@ -121,17 +122,19 @@ class TemplateOutputHandler(CementOutputHandler):
                 content = open(full_path, 'r').read()
                 LOG.debug("loaded output template from file %s" %
                           full_path)
-                return content
+                return (content, full_path)
             else:
                 LOG.debug("output template file %s does not exist" %
                           full_path)
                 continue
 
-        return None
+        return (None, None)
 
     def _load_template_from_module(self, template_path):
         template_module = self.app._meta.template_module
         template_path = template_path.lstrip('/')
+        full_module_path = "%s.%s" % (template_module,
+                                      re.sub('/', '.', template_path))
 
         LOG.debug("attemping to load output template '%s' from module %s" %
                   (template_path, template_module))
@@ -143,25 +146,24 @@ class TemplateOutputHandler(CementOutputHandler):
             except ImportError as e:
                 LOG.debug("unable to import template module '%s'."
                           % template_module)
-                return None
+                return (None, None)
 
         # get the template content
         try:
             content = pkgutil.get_data(template_module, template_path)
             LOG.debug("loaded output template '%s' from module %s" %
                       (template_path, template_module))
-            return content
+            return (content, full_module_path)
         except IOError as e:
             LOG.debug("output template '%s' does not exist in module %s" %
                       (template_path, template_module))
-            return None
+            return (None, None)
 
     def load_template(self, template_path):
         """
         Loads a template file first from ``self.app._meta.template_dirs`` and
         secondly from ``self.app._meta.template_module``.  The
         ``template_dirs`` have presedence.
-
         :param template_path: The secondary path of the template **after**
             either ``template_module`` or ``template_dirs`` prefix (set via
             ``CementApp.Meta``)
@@ -169,20 +171,46 @@ class TemplateOutputHandler(CementOutputHandler):
         :raises: FrameworkError if the template does not exist in either the
             ``template_module`` or ``template_dirs``.
         """
+        res = self.load_template_with_location(template_path)
... 5027 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-cement.git



More information about the Python-modules-commits mailing list