mirror of
https://github.com/datafolklabs/cement.git
synced 2026-02-06 14:16:46 +00:00
Alternative Resolution for Issue #387
This commit is contained in:
parent
739d2b82f3
commit
0b1e97f89b
@ -1064,8 +1064,8 @@ 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)
|
||||
|
||||
|
||||
@ -158,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
|
||||
@ -166,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`
|
||||
|
||||
@ -210,8 +212,18 @@ class HandlerManager(object):
|
||||
handler_type)
|
||||
if obj._meta.label in self.__handlers__[handler_type] and \
|
||||
self.__handlers__[handler_type][obj._meta.label] != orig_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 = self.__handlers__[handler_type]['__interface__']
|
||||
if hasattr(interface.IMeta, 'validator'):
|
||||
@ -528,7 +540,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.
|
||||
@ -542,6 +554,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
|
||||
|
||||
@ -595,8 +609,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'):
|
||||
|
||||
@ -14,11 +14,8 @@ Requirements
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
This extension supports the following application metadata settings:
|
||||
This extension does not support any configuration settings.
|
||||
|
||||
* ``CementApp.Meta.alternative_module_mapping`` - By using the alternative
|
||||
module mapping feature, the developer can optionally replace the ``json``
|
||||
module with another drop-in replacement module such as ``ujson``.
|
||||
|
||||
Usage
|
||||
_____
|
||||
@ -71,6 +68,31 @@ See ``CementApp.Meta.handler_override_options``.
|
||||
$ python myapp.py -o json
|
||||
{"foo": "bar"}
|
||||
|
||||
|
||||
What if I Want To Use UltraJson or Something Else?
|
||||
--------------------------------------------------
|
||||
|
||||
It is possible to override the backend ``json`` library module to use, for
|
||||
example if you wanted to use UltraJson (``ujson``) or another
|
||||
**drop-in replacement** library. The recommended solution would be to
|
||||
override the ``JsonOutputHandler`` with you're own sub-classed version, and
|
||||
modify the ``json_module`` meta-data option.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from cement.ext.ext_json import JsonOutputHandler
|
||||
|
||||
class MyJsonHandler(JsonOutputHandler):
|
||||
class Meta:
|
||||
json_module = 'ujson'
|
||||
|
||||
# then, the class must be replaced via a 'post_setup' hook
|
||||
|
||||
def override_json(app):
|
||||
app.handler.register(MyJsonHandler, force=True)
|
||||
|
||||
app.hook.register('post_setup', override_json)
|
||||
|
||||
"""
|
||||
|
||||
from ..core import output
|
||||
@ -149,11 +171,11 @@ class JsonOutputHandler(output.CementOutputHandler):
|
||||
label = 'json'
|
||||
"""The string identifier of this handler."""
|
||||
|
||||
#: Whether or not to include ``json`` as an available to choice
|
||||
#: Whether or not to include ``json`` as an available choice
|
||||
#: to override the ``output_handler`` via command line options.
|
||||
overridable = True
|
||||
|
||||
# Backend JSON library module to use
|
||||
#: Backend JSON library module to use (`json`, `ujson`)
|
||||
json_module = 'json'
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
@ -162,7 +184,8 @@ class JsonOutputHandler(output.CementOutputHandler):
|
||||
|
||||
def _setup(self, app):
|
||||
super(JsonOutputHandler, self)._setup(app)
|
||||
self._json = self.app.__import__('json')
|
||||
self._json = __import__(self._meta.json_module,
|
||||
globals(), locals(), [], 0)
|
||||
|
||||
def render(self, data_dict, template=None, **kw):
|
||||
"""
|
||||
@ -196,7 +219,7 @@ class JsonConfigHandler(ConfigParserConfigHandler):
|
||||
|
||||
label = 'json'
|
||||
|
||||
# Backend JSON library module to use
|
||||
#: Backend JSON library module to use (`json`, `ujson`).
|
||||
json_module = 'json'
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
@ -205,7 +228,8 @@ class JsonConfigHandler(ConfigParserConfigHandler):
|
||||
|
||||
def _setup(self, app):
|
||||
super(JsonConfigHandler, self)._setup(app)
|
||||
self._json = self.app.__import__('json')
|
||||
self._json = __import__(self._meta.json_module,
|
||||
globals(), locals(), [], 0)
|
||||
|
||||
def _parse_file(self, file_path):
|
||||
"""
|
||||
|
||||
@ -13,11 +13,7 @@ Requirements
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
This extension supports the following application metadata settings:
|
||||
|
||||
* ``CementApp.Meta.alternative_module_mapping`` - By using the alternative
|
||||
module mapping feature, the developer can optionally replace the ``json``
|
||||
module with another drop-in replacement module such as ``ujson``.
|
||||
This extension does not support any configuration settings.
|
||||
|
||||
|
||||
Usage
|
||||
@ -87,7 +83,7 @@ class JsonConfigObjConfigHandler(ConfigObjConfigHandler):
|
||||
#: The string identifier of this handler.
|
||||
label = 'json_configobj'
|
||||
|
||||
#: Backend JSON module to use
|
||||
#: Backend JSON module to use (``json``, ``ujson``, etc)
|
||||
json_module = 'json'
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
@ -96,7 +92,8 @@ class JsonConfigObjConfigHandler(ConfigObjConfigHandler):
|
||||
|
||||
def _setup(self, app):
|
||||
super(JsonConfigObjConfigHandler, self)._setup(app)
|
||||
self._json = self.app.__import__('json')
|
||||
self._json = __import__(self._meta.json_module,
|
||||
globals(), locals(), [], 0)
|
||||
|
||||
def _parse_file(self, file_path):
|
||||
"""
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
from cement.core import exc, backend, handler, output, meta
|
||||
from cement.core import interface
|
||||
from cement.utils import test
|
||||
from cement.ext import ext_dummy
|
||||
from cement.ext.ext_configparser import ConfigParserConfigHandler
|
||||
|
||||
|
||||
@ -91,13 +92,40 @@ class HandlerTestCase(test.CementCoreTestCase):
|
||||
|
||||
@test.raises(exc.FrameworkError)
|
||||
def test_register_duplicate_handler(self):
|
||||
from cement.ext import ext_dummy
|
||||
self.app.handler.register(ext_dummy.DummyOutputHandler)
|
||||
try:
|
||||
self.app.handler.register(DuplicateHandler)
|
||||
except exc.FrameworkError:
|
||||
raise
|
||||
|
||||
def test_register_force(self):
|
||||
class MyDummy(ext_dummy.DummyOutputHandler):
|
||||
pass
|
||||
|
||||
# register once, verify
|
||||
self.app.handler.register(ext_dummy.DummyOutputHandler)
|
||||
res = self.app.handler.get('output', 'dummy')
|
||||
self.eq(res, ext_dummy.DummyOutputHandler)
|
||||
|
||||
# register again with force, and verify we get new class back
|
||||
self.app.handler.register(MyDummy, force=True)
|
||||
res = self.app.handler.get('output', 'dummy')
|
||||
self.eq(res, MyDummy)
|
||||
|
||||
def test_register_force_deprecated(self):
|
||||
class MyDummy(ext_dummy.DummyOutputHandler):
|
||||
pass
|
||||
|
||||
# register once, verify
|
||||
handler.register(ext_dummy.DummyOutputHandler)
|
||||
res = self.app.handler.get('output', 'dummy')
|
||||
self.eq(res, ext_dummy.DummyOutputHandler)
|
||||
|
||||
# register again with force, and verify we get new class back
|
||||
handler.register(MyDummy, force=True)
|
||||
res = self.app.handler.get('output', 'dummy')
|
||||
self.eq(res, MyDummy)
|
||||
|
||||
@test.raises(exc.InterfaceError)
|
||||
def test_register_unproviding_handler(self):
|
||||
try:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user