[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