mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
frontend: merge baseldap.CallbackRegistry into Command
Also make it possible for subclasses to introduce new callback types. https://fedorahosted.org/freeipa/ticket/4739 Reviewed-By: David Kupka <dkupka@redhat.com>
This commit is contained in:
parent
a30bc8a351
commit
60fa6ed444
@ -369,6 +369,9 @@ class HasParam(Plugin):
|
|||||||
return context.current_frame
|
return context.current_frame
|
||||||
|
|
||||||
|
|
||||||
|
_callback_registry = {}
|
||||||
|
|
||||||
|
|
||||||
class Command(HasParam):
|
class Command(HasParam):
|
||||||
"""
|
"""
|
||||||
A public IPA atomic operation.
|
A public IPA atomic operation.
|
||||||
@ -390,6 +393,14 @@ class Command(HasParam):
|
|||||||
['my_command']
|
['my_command']
|
||||||
>>> api.Command.my_command # doctest:+ELLIPSIS
|
>>> api.Command.my_command # doctest:+ELLIPSIS
|
||||||
ipalib.frontend.my_command()
|
ipalib.frontend.my_command()
|
||||||
|
|
||||||
|
This class's subclasses allow different types of callbacks to be added and
|
||||||
|
removed to them.
|
||||||
|
Registering a callback is done either by ``register_callback``, or by
|
||||||
|
defining a ``<type>_callback`` method.
|
||||||
|
|
||||||
|
Subclasses should define the `callback_types` attribute as a tuple of
|
||||||
|
allowed callback types.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
finalize_early = False
|
finalize_early = False
|
||||||
@ -414,6 +425,8 @@ class Command(HasParam):
|
|||||||
msg_summary = None
|
msg_summary = None
|
||||||
msg_truncated = _('Results are truncated, try a more specific search')
|
msg_truncated = _('Results are truncated, try a more specific search')
|
||||||
|
|
||||||
|
callback_types = ()
|
||||||
|
|
||||||
def __call__(self, *args, **options):
|
def __call__(self, *args, **options):
|
||||||
"""
|
"""
|
||||||
Perform validation and then execute the command.
|
Perform validation and then execute the command.
|
||||||
@ -1088,6 +1101,46 @@ class Command(HasParam):
|
|||||||
|
|
||||||
return json_dict
|
return json_dict
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_callbacks(cls, callback_type):
|
||||||
|
"""Yield callbacks of the given type"""
|
||||||
|
# Use one shared callback registry, keyed on class, to avoid problems
|
||||||
|
# with missing attributes being looked up in superclasses
|
||||||
|
callbacks = _callback_registry.get(callback_type, {}).get(cls, [None])
|
||||||
|
for callback in callbacks:
|
||||||
|
if callback is None:
|
||||||
|
try:
|
||||||
|
yield getattr(cls, '%s_callback' % callback_type)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
yield callback
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def register_callback(cls, callback_type, callback, first=False):
|
||||||
|
"""Register a callback
|
||||||
|
|
||||||
|
:param callback_type: The callback type (e.g. 'pre', 'post')
|
||||||
|
:param callback: The callable added
|
||||||
|
:param first: If true, the new callback will be added before all
|
||||||
|
existing callbacks; otherwise it's added after them
|
||||||
|
|
||||||
|
Note that callbacks registered this way will be attached to this class
|
||||||
|
only, not to its subclasses.
|
||||||
|
"""
|
||||||
|
assert callback_type in cls.callback_types
|
||||||
|
assert callable(callback)
|
||||||
|
_callback_registry.setdefault(callback_type, {})
|
||||||
|
try:
|
||||||
|
callbacks = _callback_registry[callback_type][cls]
|
||||||
|
except KeyError:
|
||||||
|
callbacks = _callback_registry[callback_type][cls] = [None]
|
||||||
|
if first:
|
||||||
|
callbacks.insert(0, callback)
|
||||||
|
else:
|
||||||
|
callbacks.append(callback)
|
||||||
|
|
||||||
|
|
||||||
class LocalOrRemote(Command):
|
class LocalOrRemote(Command):
|
||||||
"""
|
"""
|
||||||
A command that is explicitly executed locally or remotely.
|
A command that is explicitly executed locally or remotely.
|
||||||
|
@ -28,7 +28,7 @@ import base64
|
|||||||
import six
|
import six
|
||||||
|
|
||||||
from ipalib import api, crud, errors
|
from ipalib import api, crud, errors
|
||||||
from ipalib import Method, Object, Command
|
from ipalib import Method, Object
|
||||||
from ipalib import Flag, Int, Str
|
from ipalib import Flag, Int, Str
|
||||||
from ipalib.cli import to_cli
|
from ipalib.cli import to_cli
|
||||||
from ipalib import output
|
from ipalib import output
|
||||||
@ -865,59 +865,7 @@ def _check_limit_object_class(attributes, attrs, allow_only):
|
|||||||
attribute=limitattrs[0]))
|
attribute=limitattrs[0]))
|
||||||
|
|
||||||
|
|
||||||
class CallbackInterface(Method):
|
class BaseLDAPCommand(Method):
|
||||||
"""Callback registration interface
|
|
||||||
|
|
||||||
This class's subclasses allow different types of callbacks to be added and
|
|
||||||
removed to them.
|
|
||||||
Registering a callback is done either by ``register_callback``, or by
|
|
||||||
defining a ``<type>_callback`` method.
|
|
||||||
|
|
||||||
Subclasses should define the `_callback_registry` attribute as a dictionary
|
|
||||||
mapping allowed callback types to (initially) empty dictionaries.
|
|
||||||
"""
|
|
||||||
|
|
||||||
_callback_registry = dict()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_callbacks(cls, callback_type):
|
|
||||||
"""Yield callbacks of the given type"""
|
|
||||||
# Use one shared callback registry, keyed on class, to avoid problems
|
|
||||||
# with missing attributes being looked up in superclasses
|
|
||||||
callbacks = cls._callback_registry[callback_type].get(cls, [None])
|
|
||||||
for callback in callbacks:
|
|
||||||
if callback is None:
|
|
||||||
try:
|
|
||||||
yield getattr(cls, '%s_callback' % callback_type)
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
yield callback
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def register_callback(cls, callback_type, callback, first=False):
|
|
||||||
"""Register a callback
|
|
||||||
|
|
||||||
:param callback_type: The callback type (e.g. 'pre', 'post')
|
|
||||||
:param callback: The callable added
|
|
||||||
:param first: If true, the new callback will be added before all
|
|
||||||
existing callbacks; otherwise it's added after them
|
|
||||||
|
|
||||||
Note that callbacks registered this way will be attached to this class
|
|
||||||
only, not to its subclasses.
|
|
||||||
"""
|
|
||||||
assert callable(callback)
|
|
||||||
try:
|
|
||||||
callbacks = cls._callback_registry[callback_type][cls]
|
|
||||||
except KeyError:
|
|
||||||
callbacks = cls._callback_registry[callback_type][cls] = [None]
|
|
||||||
if first:
|
|
||||||
callbacks.insert(0, callback)
|
|
||||||
else:
|
|
||||||
callbacks.append(callback)
|
|
||||||
|
|
||||||
|
|
||||||
class BaseLDAPCommand(CallbackInterface, Command):
|
|
||||||
"""
|
"""
|
||||||
Base class for Base LDAP Commands.
|
Base class for Base LDAP Commands.
|
||||||
"""
|
"""
|
||||||
@ -940,7 +888,10 @@ last, after all sets and adds."""),
|
|||||||
exclude='webui',
|
exclude='webui',
|
||||||
)
|
)
|
||||||
|
|
||||||
_callback_registry = dict(pre={}, post={}, exc={}, interactive_prompt={})
|
callback_types = Method.callback_types + ('pre',
|
||||||
|
'post',
|
||||||
|
'exc',
|
||||||
|
'interactive_prompt')
|
||||||
|
|
||||||
def get_summary_default(self, output):
|
def get_summary_default(self, output):
|
||||||
if 'value' in output:
|
if 'value' in output:
|
||||||
|
@ -26,6 +26,7 @@ import ldap
|
|||||||
from ipapython.dn import DN
|
from ipapython.dn import DN
|
||||||
from ipapython import ipaldap
|
from ipapython import ipaldap
|
||||||
from ipalib import errors
|
from ipalib import errors
|
||||||
|
from ipalib.frontend import Command
|
||||||
from ipalib.plugins import baseldap
|
from ipalib.plugins import baseldap
|
||||||
from ipatests.util import assert_deepequal
|
from ipatests.util import assert_deepequal
|
||||||
import pytest
|
import pytest
|
||||||
@ -33,7 +34,7 @@ import pytest
|
|||||||
|
|
||||||
@pytest.mark.tier0
|
@pytest.mark.tier0
|
||||||
def test_exc_wrapper():
|
def test_exc_wrapper():
|
||||||
"""Test the CallbackInterface._exc_wrapper helper method"""
|
"""Test the BaseLDAPCommand._exc_wrapper helper method"""
|
||||||
handled_exceptions = []
|
handled_exceptions = []
|
||||||
|
|
||||||
class test_callback(baseldap.BaseLDAPCommand):
|
class test_callback(baseldap.BaseLDAPCommand):
|
||||||
@ -77,8 +78,8 @@ def test_exc_wrapper():
|
|||||||
|
|
||||||
@pytest.mark.tier0
|
@pytest.mark.tier0
|
||||||
def test_callback_registration():
|
def test_callback_registration():
|
||||||
class callbacktest_base(baseldap.CallbackInterface):
|
class callbacktest_base(Command):
|
||||||
_callback_registry = dict(test={})
|
callback_types = Command.callback_types + ('test',)
|
||||||
|
|
||||||
def test_callback(self, param):
|
def test_callback(self, param):
|
||||||
messages.append(('Base test_callback', param))
|
messages.append(('Base test_callback', param))
|
||||||
|
Loading…
Reference in New Issue
Block a user