Exemple #1
0
def _handle_opt_preprocess(name, dcl):
    """
    Process properties, that cause modification of parsed argument names before
    passing them to ``verify_options()`` or ``transform_options()``. If any of
    handled properties is supplied, it causes ``_preprocess_options()`` to be
    overriden, where all of desired name modifications will be made.
    Currently handled properties are:

        ``OPT_NO_UNDERSCORES`` : ``bool``
            When making a function's parameter name out of option, the leading
            dashes are replaced with underscore. If this property is True,
            dashes will be removed completely with no replacement.
        ``ARG_ARRAY_SUFFIX`` : ``bool``
            Add given suffix to all arguments resulting in list objects.

    :param string name: Command class name.
    :param dictionary dcl: Class dictionary being modified by this method.
    """
    if (dcl.get('__metaclass__', None) is not EndPointCommandMetaClass
            and '_preprocess_options' in dcl):
        raise errors.LmiCommandError(
            dcl['__module__'], name,
            '_preprocess_options() method must not be overriden in the'
            'body of command class; use transform_options() instead')
    arr_suffix = dcl.pop('ARG_ARRAY_SUFFIX', '')
    if (not isinstance(arr_suffix, str)
            or not RE_ARRAY_SUFFIX.match(arr_suffix)):
        raise errors.LmiCommandInvalidProperty(
            dcl['__module__'], name,
            'ARG_ARRAY_SUFFIX must be a string matching regular'
            ' expression "%s"' % RE_ARRAY_SUFFIX.pattern)
    opt_no_underscores = dcl.pop('OPT_NO_UNDERSCORES', False)
    if arr_suffix or opt_no_underscores:

        def _new_preprocess_options(_self, options):
            """ Modify (in-place) given options dictionary by renaming keys. """
            for do_it, cond, transform in (
                (arr_suffix, lambda _, v: isinstance(v, list), lambda n:
                 ('<' + util.RE_OPT_BRACKET_ARGUMENT.match(n).group(1) +
                  arr_suffix + '>')
                 if util.RE_OPT_BRACKET_ARGUMENT.match(n) else
                 (n + arr_suffix)),
                (opt_no_underscores, lambda n, _: RE_OPTION.match(n),
                 lambda n: RE_OPTION.match(n).group('name'))):
                if not do_it:
                    continue
                to_rename = (name for name, value in options.items()
                             if cond(name, value))
                for name in to_rename:
                    new_name = transform(name)
                    LOG().debug('renaming option "%s" to "%s"', name, new_name)
                    if new_name in options:
                        LOG().warn(
                            'existing option named "%s" replaced with "%s"',
                            new_name, name)
                    options[new_name] = options.pop(name)

        dcl['_preprocess_options'] = _new_preprocess_options
Exemple #2
0
    def __new__(mcs, name, bases, dcl):
        if dcl.get('__metaclass__', None) is not MultiplexerMetaClass:
            module_name = dcl.get('__module__', name)
            # check COMMANDS property and make it a classmethod
            if not 'COMMANDS' in dcl:
                raise errors.LmiCommandError(module_name, name,
                                             'missing COMMANDS property')
            cmds = dcl.pop('COMMANDS')
            if not isinstance(cmds, dict):
                raise errors.LmiCommandInvalidProperty(
                    module_name, name, 'COMMANDS must be a dictionary')
            if not all(isinstance(c, basestring) for c in cmds.keys()):
                raise errors.LmiCommandInvalidProperty(
                    module_name, name,
                    'keys of COMMANDS dictionary must contain command'
                    ' names as strings')
            for cmd_name, cmd in cmds.items():
                if not base.RE_COMMAND_NAME.match(cmd_name):
                    raise errors.LmiCommandInvalidName(module_name, name,
                                                       cmd_name)
                if not issubclass(cmd, base.LmiBaseCommand):
                    raise errors.LmiCommandError(
                        module_name, name,
                        'COMMANDS dictionary must be composed of'
                        ' LmiCommandBase subclasses, failed class: "%s"' %
                        cmd.__name__)
                if not cmd.is_end_point():
                    cmd.__doc__ = dcl['__doc__']

            def _new_child_commands(_cls):
                """ Returns list of subcommands. """
                return cmds

            dcl['child_commands'] = classmethod(_new_child_commands)

            # check documentation
            if dcl.get('__doc__', None) is None:
                LOG().warn('Command "%s.%s" is missing description string.',
                           dcl['__module__'], name)

            _handle_usage(name, dcl)

        return super(MultiplexerMetaClass, mcs).__new__(mcs, name, bases, dcl)
Exemple #3
0
    def __new__(mcs, name, bases, dcl):
        cols = dcl.pop('COLUMNS', None)
        if cols is not None:
            if not isinstance(cols, (list, tuple)):
                raise errors.LmiCommandInvalidProperty(
                    dcl['__module__'], name,
                    'COLUMNS class property must be either list or tuple')
            if not all(isinstance(c, basestring) for c in cols):
                raise errors.LmiCommandInvalidProperty(
                    dcl['__module__'], name,
                    'COLUMNS must contain just column names as strings')

            def _new_get_columns(_cls):
                """ Return column names. """
                return cols

            dcl['get_columns'] = classmethod(_new_get_columns)

        return super(ListerMetaClass, mcs).__new__(mcs, name, bases, dcl)
Exemple #4
0
def _check_render_properties(name, dcl, props):
    """
    Make sanity check for ``PROPERTIES`` class property. Exception will be
    raised when any flaw discovered.

    :param string name: Name of class to be created.
    :param dictionary dcl: Class dictionary.
    :param list props: List of properties or ``None``.
    """
    if props is not None:
        for prop in props:
            if not isinstance(prop, (basestring, tuple, list)):
                raise errors.LmiCommandInvalidProperty(
                    dcl['__module__'], name,
                    'PROPERTIES must be a list of strings or tuples')
            if isinstance(prop, (tuple, list)):
                if (len(prop) != 2 or not isinstance(prop[0], basestring)
                        or (not callable(prop[1])
                            and not isinstance(prop[1], basestring))):
                    raise errors.LmiCommandInvalidProperty(
                        dcl['__module__'], name,
                        'tuples in PROPERTIES must be: ("name",'
                        ' callable or property_name)')
Exemple #5
0
def _handle_usage(name, dcl):
    """
    Take care of ``OWN_USAGE`` property. Supported values:

        `True`` :
            Means that documentation string of class is a usage string.
        ``False`` :
            No usage string for this command is defined.
        ``"usage string"`` :
            This property is a usage string.

    Defaults to ``False``.

    Usage string is an input parameter to ``docopt`` command-line options
    parser.

    :param string name: Name o command class.
    :param dictionary dcl: Class dictionary, which is modified by this
        function.
    """
    has_own_usage = False
    hlp = dcl.pop('OWN_USAGE', False)
    if hlp is True:
        if dcl['__doc__'] is None:
            raise errors.LmiCommandInvalidProperty(
                dcl['__module__'], name,
                "OWN_USAGE set to True, but no __doc__ string present!")
        has_own_usage = True
    elif isinstance(hlp, basestring):
        if not '__doc__' in dcl:
            dcl['__doc__'] = hlp
        else:
            if not 'get_usage' in dcl:

                def _new_get_usage(_self, proper=False):
                    """ Get the usage string for ``doctopt`` parser. """
                    return hlp

                dcl['get_usage'] = _new_get_usage
        has_own_usage = True
    if has_own_usage:
        if not 'has_own_usage' in dcl:
            dcl['has_own_usage'] = classmethod(lambda _cls: True)