Example #1
0
    def __init__(self, *args, **kwargs):
        # initialize option's value dictionary, used by descriptor implementation (see Option).
        self._options_values = {**kwargs}

        # set option values.
        for name, value in kwargs.items():
            setattr(self, name, value)

        position = 0
        for name, option in self.__options__:
            if not option.positional:
                break  # option orders make all positional options first

            # value was overriden? Skip.
            maybe_value = getattr(type(self), name)
            if not isoption(maybe_value):
                continue

            if len(args) <= position:
                break

            if name in self._options_values:
                raise ValueError(
                    'Already got a value for option {}'.format(name))

            setattr(self, name, args[position])
            position += 1
Example #2
0
    def __new__(cls, *args, _final=False, **kwargs):
        """
        Custom instance builder. If not all options are fulfilled, will return a :class:`PartiallyConfigured` instance
        which is just a :class:`functools.partial` object that behaves like a :class:`Configurable` instance.

        The special `_final` argument can be used to force final instance to be created, or an error raised if options
        are missing.

        :param args:
        :param _final: bool
        :param kwargs:
        :return: Configurable or PartiallyConfigured
        """
        options = tuple(cls.__options__)
        # compute missing options, given the kwargs.
        missing = set()
        for name, option in options:
            if option.required and not option.name in kwargs:
                missing.add(name)

        # transform positional arguments in keyword arguments if possible.
        position = 0
        for name, option in options:
            if not option.positional:
                break  # option orders make all positional options first, job done.

            if not isoption(getattr(cls, name)):
                missing.remove(name)
                continue

            if len(args) <= position:
                break  # no more positional arguments given.

            position += 1
            if name in missing:
                missing.remove(name)

        # complain if there is more options than possible.
        extraneous = set(kwargs.keys()) - (set(next(zip(*options))) if len(options) else set())
        if len(extraneous):
            raise TypeError(
                '{}() got {} unexpected option{}: {}.'.format(
                    cls.__name__, len(extraneous), 's'
                    if len(extraneous) > 1 else '', ', '.join(map(repr, sorted(extraneous)))
                )
            )

        # missing options? we'll return a partial instance to finish the work later, unless we're required to be
        # "final".
        if len(missing):
            if _final:
                raise TypeError(
                    '{}() missing {} required option{}: {}.'.format(
                        cls.__name__, len(missing), 's'
                        if len(missing) > 1 else '', ', '.join(map(repr, sorted(missing)))
                    )
                )
            return PartiallyConfigured(cls, *args, **kwargs)

        return super(Configurable, cls).__new__(cls)
Example #3
0
    def __init__(cls, what, bases=None, dict=None):
        super().__init__(what, bases, dict)

        cls.__processors = sortedlist()
        cls.__methods = sortedlist()
        cls.__options = sortedlist()
        cls.__names = set()

        # cls.__kwoptions = []

        for typ in cls.__mro__:
            for name, value in filter(lambda x: isoption(x[1]),
                                      typ.__dict__.items()):
                if iscontextprocessor(value):
                    cls.__processors.insort((value._creation_counter, value))
                    continue

                if not value.name:
                    value.name = name

                if not name in cls.__names:
                    cls.__names.add(name)
                    cls.__options.insort(
                        (not value.positional, value._creation_counter, name,
                         value))
Example #4
0
    def __init__(cls, what, bases=None, dict=None):
        super().__init__(what, bases, dict)

        cls.__processors = sortedlist()
        cls.__processors_cache = None
        cls.__methods = sortedlist()
        cls.__options = sortedlist()
        cls.__names = set()

        # cls.__kwoptions = []

        for typ in cls.__mro__:
            for name, value in filter(lambda x: isoption(x[1]), typ.__dict__.items()):
                if iscontextprocessor(value):
                    cls.__processors.insort((value._creation_counter, value))
                    continue

                if not value.name:
                    value.name = name

                if not name in cls.__names:
                    cls.__names.add(name)
                    cls.__options.insort((not value.positional, value._creation_counter, name, value))

        # Docstring formating
        _options_doc = []
        for _positional, _counter, _name, _value in cls.__options:
            _param = _name
            if _value.type:
                _param = get_name(_value.type) + ' ' + _param

            prefix = ':param {}: '.format(_param)
            for lineno, line in enumerate((_value.__doc__ or '').split('\n')):
                _options_doc.append((' ' * len(prefix) if lineno else prefix) + line)
        cls.__doc__ = '\n\n'.join(
            map(
                str.strip,
                filter(None, (
                    cls.__doc__,
                    '\n'.join(_options_doc)
                ))
            )
        )