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
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)
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)
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)')
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)