import logging import shlex from flask import request from markupsafe import Markup from flask_admin.base import BaseView, expose from flask_admin.babel import gettext # Set up logger log = logging.getLogger("flask-admin.redis") class CommandError(Exception): """ RedisCli error exception. """ pass class TextWrapper(str): """ Small text wrapper for result formatter to distinguish between different string types. """ pass class RedisCli(BaseView): """ Simple redis console. To use it, simply pass `Redis` connection object to the constructor. """ remapped_commands = { 'del': 'delete' } """ List of redis remapped commands. """ excluded_commands = set(('pubsub', 'set_response_callback', 'from_url')) """ List of excluded commands. """ def __init__(self, redis, name=None, category=None, endpoint=None, url=None): """ Constructor. :param redis: Redis connection :param name: View name. If not provided, will use the model class name :param category: View category :param endpoint: Base endpoint. If not provided, will use the model name + 'view'. For example if model name was 'User', endpoint will be 'userview' :param url: Base URL. If not provided, will use endpoint as a URL. """ super(RedisCli, self).__init__(name, category, endpoint, url) self.redis = redis self.commands = {} self._inspect_commands() self._contribute_commands() def _inspect_commands(self): """ Inspect connection object and extract command names. """ for name in dir(self.redis): if not name.startswith('_'): attr = getattr(self.redis, name) if callable(attr) and name not in self.excluded_commands: doc = (getattr(attr, '__doc__', '') or '').strip() self.commands[name] = (attr, doc) for new, old in self.remapped_commands.items(): self.commands[new] = self.commands[old] def _contribute_commands(self): """ Contribute custom commands. """ self.commands['help'] = (self._cmd_help, 'Help!') def _execute_command(self, name, args): """ Execute single command. :param name: Command name :param args: Command arguments """ # Do some remapping new_cmd = self.remapped_commands.get(name) if new_cmd: name = new_cmd # Execute command if name not in self.commands: return self._error(gettext('Cli: Invalid command.')) handler, _ = self.commands[name] return self._result(handler(*args)) def _parse_cmd(self, cmd): """ Parse command by using shlex module. :param cmd: Command to parse """ return tuple(shlex.split(cmd)) def _error(self, msg): """ Format error message as HTTP response. :param msg: Message to format """ return Markup('