Example #1
0
    def _generate_derived_type_dictionary (cls, options):
        """
        Generate an iterable of pairs in the form (Python identifier, value) for a new
        type created by C{L{derive_type}}.  Exact pairs should be influenced by
        C{options}, which are C{options} as passed to C{derive_type} plus C{cls} (for
        convenience) and C{new_class_name}.

        This method is not meant to be callable from outside, use C{L{derive_type}} for
        that instead.

        Overriden implementations of this method are recommended but not required to be
        generator functions.  They should generally start like this:

            >>> def _generate_derived_type_dictionary (cls, options):
            ...     for attribute in super (..., cls)._generate_derived_type_dictionary (options):
            ...         yield attribute
            ...
            ...     ...

        That is only an approximation and you can, for instance, change or override
        attributes returned by super-method.

        C{options} dictionary is constructed in such a way you should be able to evaluate
        all function-defining statements in it.  For instance, you can write own
        C{_generate_derived_type_dictionary} like this:

            >>> def _generate_derived_type_dictionary (cls, options):
            ...     ...
            ...
            ...     functions = {}
            ...
            ...     if 'foo_value' in options:
            ...         exec 'def foo (self): return foo_value' \
            ...              in { 'foo_value': options['foo_value'] }, functions
            ...
            ...     ...
            ...
            ...     for function in functions.iteritems ():
            ...         yield function

        Returned value for C{__slots__} is treated specially.  While normally values
        associated with the same name override previous values, values for C{__slots__}
        are combined into a tuple instead.

        Note that it is not recommended to use C{options} for execution globals or locals
        dictionary directly.  This way your code may become vulnerable to other option
        addition, e.g. for some derivative of the class.  For instance, you may use
        C{property} built-in, then setting it in C{options} will hide the built-in from
        your code.  Consider using C{L{_filter_options}} utility method.

        @param options:    dictionary of options passed to C{L{derive_type}} method, plus
                           C{cls} and C{new_class_name}.
        @type  options:    C{dict}

        @rtype:            iterable
        @returns:          Pairs of (Python identifier, value) for the new type.

        @raises exception: if there is any error in C{options}.
        """

        functions        = {}
        filtered_options = AbstractValueObject._filter_options (options, 'cls', 'getter', 'setter')


        if 'object' in options:
            object = options['object']
            if not is_valid_identifier (object):
                raise ValueError ("'%s' is not a valid Python identifier" % object)

            yield '__slots__', mangle_identifier (options['new_class_name'], object)

            execute (('def __init__(self, %s):\n'
                      '    cls.__init__(self)\n'
                      '    %s = %s')
                     % (object, AbstractValueObject._get_object (options), object),
                     filtered_options, functions)

            if 'property' in options:
                property = options['property']
                if property == object:
                    raise ValueError ("'property' option cannot be the same as 'object'")

                if not is_valid_identifier (property):
                    raise ValueError ("'%s' is not a valid Python identifier" % property)

                execute ('%s = property (lambda self: %s)'
                         % (mangle_identifier (options['new_class_name'], property),
                            AbstractValueObject._get_object (options)),
                         functions)

        else:
            if 'property' in options:
                raise ValueError ("'property' without 'object' option doesn't make sense")

        if 'dict' in options and options['dict']:
            # Gracefully ignore if this type already has a dict.
            if not _type_has_dictionary (cls):
                yield '__slots__', '__dict__'

        if 'getter' in options:
            if not is_callable (options['getter']):
                raise TypeError ("'getter' must be a callable")

            execute ('def get (self): return getter (%s)'
                     % AbstractValueObject._get_object (options),
                     filtered_options, functions)

        if 'setter' in options:
            if not is_callable (options['setter']):
                raise TypeError ("'setter' must be a callable")

            execute ('def set (self, value): return setter (%s, value)'
                     % AbstractValueObject._get_object (options),
                     filtered_options, functions)

        for function in functions.items ():
            yield function
Example #2
0
    def _generate_derived_type_dictionary (cls, options):
        allowed_values      = options.get ('allowed_values')
        allowed_value_types = options.get ('allowed_value_types')

        if allowed_value_types is not None:
            if not isinstance (allowed_value_types, tuple):
                allowed_value_types = (allowed_value_types,)

            for allowed_type in allowed_value_types:
                if not isinstance (allowed_type, ClassTypes):
                    raise TypeError ("'allowed_value_types' must be a tuple of types and classes")

        for attribute in (super (AbstractValueTrackingVariable, cls)
                          ._generate_derived_type_dictionary (options)):
            if attribute[0] not in ('get', 'set'):
                yield attribute

        functions        = {}
        object           = options.get ('object')
        filtered_options = AbstractValueObject._filter_options (options,
                                                                'cls',
                                                                'allowed_values',
                                                                'allowed_value_types',
                                                                'getter', 'setter',
                                                                'default_value')

        if allowed_values is not None or allowed_value_types is not None:
            if allowed_values is not None:
                if allowed_value_types is not None:
                    execute ('def is_allowed_value (self, value):\n'
                             '    return value in allowed_values\n'
                             '           and isinstance (value, allowed_value_types)',
                             filtered_options, functions)
                else:
                    execute ('def is_allowed_value (self, value):\n'
                             '    return value in allowed_values\n',
                             filtered_options, functions)
            else:
                execute ('def is_allowed_value (self, value):\n'
                         '    return isinstance (value, allowed_value_types)',
                         filtered_options, functions)

        if 'getter' in options:
            if object is not None:
                execute (('def __init__(self, %s):\n'
                          '    cls.__init__(self, getter (%s))\n'
                          '    %s = %s')
                         % (object, object, AbstractValueObject._get_object (options), object),
                         filtered_options, functions)
            else:
                execute ('def __init__(self):\n'
                         '    cls.__init__(self, getter (self))\n',
                         filtered_options, functions)

            execute (('def resynchronize_with_backend (self):\n'
                      '    self._set (getter (%s))')
                     % AbstractValueObject._get_object (options),
                     filtered_options, functions)

        else:
            if 'default_value' in options:
                if (    'is_allowed_value' in functions
                    and not functions['is_allowed_value'] (None, options['default_value'])):
                   raise ValueError ("'default_value' of '%s' is not within allowed value set"
                                     % (options['default_value'],))

                initial_default = ' = default_value'

            # Since our is_allowed_value() implementation never accesses `self', it is OK
            # to pass None as that.
            elif 'is_allowed_value' not in functions or functions['is_allowed_value'] (None, None):
                initial_default = ' = None'

            else:
                initial_default = ''

            if 'setter' in options:
                setter_statement = ('setter (%s, initial_value)'
                                    % AbstractValueObject._get_object (options))
            else:
                setter_statement = ''

            if object is not None:
                execute (('def __init__(self, %s, initial_value%s):\n'
                          '    cls.__init__(self, initial_value)\n'
                          '    %s = %s\n'
                          '    %s\n')
                         % (object, initial_default,
                            AbstractValueObject._get_object (options), object, setter_statement),
                         filtered_options, functions)
            else:
                execute (('def __init__(self, initial_value%s):\n'
                          '    cls.__init__(self, initial_value)\n'
                          '    %s\n')
                         % (initial_default, setter_statement),
                         filtered_options, functions)

        if 'setter' in options:
            execute (('def _set (self, value):\n'
                      '    if self.get () != value:\n'
                      '        if not self.is_allowed_value (value):\n'
                      '            raise ValueError \\\n'
                      '                ("\'%%s\' is not allowed as value of the variable" %% value)\n'
                      '        setter (%s, value)\n'
                      '        self._AbstractValueTrackingVariable__value = value\n'
                      '        return self._value_changed (value)\n'
                      '    else:\n'
                      '        return False')
                     % AbstractValueObject._get_object (options),
                     filtered_options, functions)

            execute ('def set (self, value): return self._set (value)', functions)

        for function in functions.items ():
            yield function
Example #3
0
    def _generate_derived_type_dictionary(cls, options):
        allowed_values = options.get('allowed_values')
        allowed_value_types = options.get('allowed_value_types')

        if allowed_value_types is not None:
            if not isinstance(allowed_value_types, tuple):
                allowed_value_types = (allowed_value_types, )

            for allowed_type in allowed_value_types:
                if not isinstance(allowed_type, ClassTypes):
                    raise TypeError(
                        "'allowed_value_types' must be a tuple of types and classes"
                    )

        for attribute in (super(
                AbstractValueTrackingVariable,
                cls)._generate_derived_type_dictionary(options)):
            if attribute[0] not in ('get', 'set'):
                yield attribute

        functions = {}
        object = options.get('object')
        filtered_options = AbstractValueObject._filter_options(
            options, 'cls', 'allowed_values', 'allowed_value_types', 'getter',
            'setter', 'default_value')

        if allowed_values is not None or allowed_value_types is not None:
            if allowed_values is not None:
                if allowed_value_types is not None:
                    execute(
                        'def is_allowed_value (self, value):\n'
                        '    return value in allowed_values\n'
                        '           and isinstance (value, allowed_value_types)',
                        filtered_options, functions)
                else:
                    execute(
                        'def is_allowed_value (self, value):\n'
                        '    return value in allowed_values\n',
                        filtered_options, functions)
            else:
                execute(
                    'def is_allowed_value (self, value):\n'
                    '    return isinstance (value, allowed_value_types)',
                    filtered_options, functions)

        if 'getter' in options:
            if object is not None:
                execute(('def __init__(self, %s):\n'
                         '    cls.__init__(self, getter (%s))\n'
                         '    %s = %s') %
                        (object, object,
                         AbstractValueObject._get_object(options), object),
                        filtered_options, functions)
            else:
                execute(
                    'def __init__(self):\n'
                    '    cls.__init__(self, getter (self))\n',
                    filtered_options, functions)

            execute(('def resynchronize_with_backend (self):\n'
                     '    self._set (getter (%s))') %
                    AbstractValueObject._get_object(options), filtered_options,
                    functions)

        else:
            if 'default_value' in options:
                if ('is_allowed_value' in functions
                        and not functions['is_allowed_value'](
                            None, options['default_value'])):
                    raise ValueError(
                        "'default_value' of '%s' is not within allowed value set"
                        % (options['default_value'], ))

                initial_default = ' = default_value'

            # Since our is_allowed_value() implementation never accesses `self', it is OK
            # to pass None as that.
            elif 'is_allowed_value' not in functions or functions[
                    'is_allowed_value'](None, None):
                initial_default = ' = None'

            else:
                initial_default = ''

            if 'setter' in options:
                setter_statement = ('setter (%s, initial_value)' %
                                    AbstractValueObject._get_object(options))
            else:
                setter_statement = ''

            if object is not None:
                execute(
                    ('def __init__(self, %s, initial_value%s):\n'
                     '    cls.__init__(self, initial_value)\n'
                     '    %s = %s\n'
                     '    %s\n') % (object, initial_default,
                                    AbstractValueObject._get_object(options),
                                    object, setter_statement),
                    filtered_options, functions)
            else:
                execute(('def __init__(self, initial_value%s):\n'
                         '    cls.__init__(self, initial_value)\n'
                         '    %s\n') % (initial_default, setter_statement),
                        filtered_options, functions)

        if 'setter' in options:
            execute((
                'def _set (self, value):\n'
                '    if self.get () != value:\n'
                '        if not self.is_allowed_value (value):\n'
                '            raise ValueError \\\n'
                '                ("\'%%s\' is not allowed as value of the variable" %% value)\n'
                '        setter (%s, value)\n'
                '        self._AbstractValueTrackingVariable__value = value\n'
                '        return self._value_changed (value)\n'
                '    else:\n'
                '        return False') %
                    AbstractValueObject._get_object(options), filtered_options,
                    functions)

            execute('def set (self, value): return self._set (value)',
                    functions)

        for function in functions.items():
            yield function
Example #4
0
    def _generate_derived_type_dictionary(cls, options):
        for attribute in (super(
                AbstractStateTrackingCondition,
                cls)._generate_derived_type_dictionary(options)):
            if attribute[0] not in ('get', 'set'):
                yield attribute

        functions = {}
        object = options.get('object')
        filtered_options = AbstractValueObject._filter_options(
            options, 'cls', 'getter', 'setter')

        if 'getter' in options:
            if object is not None:
                execute(('def __init__(self, %s):\n'
                         '    cls.__init__(self, getter (%s))\n'
                         '    %s = %s') %
                        (object, object,
                         AbstractValueObject._get_object(options), object),
                        filtered_options, functions)
            else:
                execute(
                    'def __init__(self):\n'
                    '    cls.__init__(self, getter (self))\n',
                    filtered_options, functions)

            execute(('def resynchronize_with_backend (self):\n'
                     '    self._set (getter (%s))') %
                    AbstractValueObject._get_object(options), filtered_options,
                    functions)

        else:
            if 'setter' in options:
                setter_statement = ('setter (%s, initial_state)' %
                                    AbstractValueObject._get_object(options))
            else:
                setter_statement = ''

            if object is not None:
                execute(('def __init__(self, %s, initial_state):\n'
                         '    cls.__init__(self, initial_state)\n'
                         '    %s = %s\n'
                         '    %s\n') %
                        (object, AbstractValueObject._get_object(options),
                         object, setter_statement), filtered_options,
                        functions)
            else:
                execute(('def __init__(self, initial_state):\n'
                         '    cls.__init__(self, initial_state)\n'
                         '    %s\n') % setter_statement, filtered_options,
                        functions)

        if 'setter' in options:
            execute((
                'def _set (self, value):\n'
                '    state = bool (value)\n'
                '    if self.get () != state:\n'
                '        setter (%s, state)\n'
                '        self._AbstractStateTrackingCondition__state = state\n'
                '        return self._value_changed (state)\n'
                '    else:\n'
                '        return False') %
                    AbstractValueObject._get_object(options), filtered_options,
                    functions)

            execute('def set (self, value): return self._set (value)',
                    functions)

        for function in functions.items():
            yield function
Example #5
0
    def _generate_derived_type_dictionary(cls, options):
        """
        Generate an iterable of pairs in the form (Python identifier, value) for a new
        type created by C{L{derive_type}}.  Exact pairs should be influenced by
        C{options}, which are C{options} as passed to C{derive_type} plus C{cls} (for
        convenience) and C{new_class_name}.

        This method is not meant to be callable from outside, use C{L{derive_type}} for
        that instead.

        Overriden implementations of this method are recommended but not required to be
        generator functions.  They should generally start like this:

            >>> def _generate_derived_type_dictionary (cls, options):
            ...     for attribute in super (..., cls)._generate_derived_type_dictionary (options):
            ...         yield attribute
            ...
            ...     ...

        That is only an approximation and you can, for instance, change or override
        attributes returned by super-method.

        C{options} dictionary is constructed in such a way you should be able to evaluate
        all function-defining statements in it.  For instance, you can write own
        C{_generate_derived_type_dictionary} like this:

            >>> def _generate_derived_type_dictionary (cls, options):
            ...     ...
            ...
            ...     functions = {}
            ...
            ...     if 'foo_value' in options:
            ...         exec 'def foo (self): return foo_value' \
            ...              in { 'foo_value': options['foo_value'] }, functions
            ...
            ...     ...
            ...
            ...     for function in functions.iteritems ():
            ...         yield function

        Returned value for C{__slots__} is treated specially.  While normally values
        associated with the same name override previous values, values for C{__slots__}
        are combined into a tuple instead.

        Note that it is not recommended to use C{options} for execution globals or locals
        dictionary directly.  This way your code may become vulnerable to other option
        addition, e.g. for some derivative of the class.  For instance, you may use
        C{property} built-in, then setting it in C{options} will hide the built-in from
        your code.  Consider using C{L{_filter_options}} utility method.

        @param options:    dictionary of options passed to C{L{derive_type}} method, plus
                           C{cls} and C{new_class_name}.
        @type  options:    C{dict}

        @rtype:            iterable
        @returns:          Pairs of (Python identifier, value) for the new type.

        @raises exception: if there is any error in C{options}.
        """

        functions = {}
        filtered_options = AbstractValueObject._filter_options(
            options, 'cls', 'getter', 'setter')

        if 'object' in options:
            object = options['object']
            if not is_valid_identifier(object):
                raise ValueError("'%s' is not a valid Python identifier" %
                                 object)

            yield '__slots__', mangle_identifier(options['new_class_name'],
                                                 object)

            execute(('def __init__(self, %s):\n'
                     '    cls.__init__(self)\n'
                     '    %s = %s') %
                    (object, AbstractValueObject._get_object(options), object),
                    filtered_options, functions)

            if 'property' in options:
                property = options['property']
                if property == object:
                    raise ValueError(
                        "'property' option cannot be the same as 'object'")

                if not is_valid_identifier(property):
                    raise ValueError("'%s' is not a valid Python identifier" %
                                     property)

                execute(
                    '%s = property (lambda self: %s)' %
                    (mangle_identifier(options['new_class_name'], property),
                     AbstractValueObject._get_object(options)), functions)

        else:
            if 'property' in options:
                raise ValueError(
                    "'property' without 'object' option doesn't make sense")

        if 'dict' in options and options['dict']:
            # Gracefully ignore if this type already has a dict.
            if not _type_has_dictionary(cls):
                yield '__slots__', '__dict__'

        if 'getter' in options:
            if not is_callable(options['getter']):
                raise TypeError("'getter' must be a callable")

            execute(
                'def get (self): return getter (%s)' %
                AbstractValueObject._get_object(options), filtered_options,
                functions)

        if 'setter' in options:
            if not is_callable(options['setter']):
                raise TypeError("'setter' must be a callable")

            execute(
                'def set (self, value): return setter (%s, value)' %
                AbstractValueObject._get_object(options), filtered_options,
                functions)

        for function in functions.items():
            yield function
Example #6
0
    def _generate_derived_type_dictionary (cls, options):
        for attribute in (super (AbstractStateTrackingCondition, cls)
                          ._generate_derived_type_dictionary (options)):
            if attribute[0] not in ('get', 'set'):
                yield attribute

        functions        = {}
        object           = options.get ('object')
        filtered_options = AbstractValueObject._filter_options (options, 'cls', 'getter', 'setter')

        if 'getter' in options:
            if object is not None:
                execute (('def __init__(self, %s):\n'
                          '    cls.__init__(self, getter (%s))\n'
                          '    %s = %s')
                         % (object, object, AbstractValueObject._get_object (options), object),
                         filtered_options, functions)
            else:
                execute ('def __init__(self):\n'
                         '    cls.__init__(self, getter (self))\n',
                         filtered_options, functions)

            execute (('def resynchronize_with_backend (self):\n'
                      '    self._set (getter (%s))')
                     % AbstractValueObject._get_object (options),
                     filtered_options, functions)

        else:
            if 'setter' in options:
                setter_statement = ('setter (%s, initial_state)'
                                    % AbstractValueObject._get_object (options))
            else:
                setter_statement = ''

            if object is not None:
                execute (('def __init__(self, %s, initial_state):\n'
                          '    cls.__init__(self, initial_state)\n'
                          '    %s = %s\n'
                          '    %s\n')
                         % (object, AbstractValueObject._get_object (options), object,
                            setter_statement),
                         filtered_options, functions)
            else:
                execute (('def __init__(self, initial_state):\n'
                          '    cls.__init__(self, initial_state)\n'
                          '    %s\n')
                         % setter_statement,
                         filtered_options, functions)

        if 'setter' in options:
            execute (('def _set (self, value):\n'
                      '    state = bool (value)\n'
                      '    if self.get () != state:\n'
                      '        setter (%s, state)\n'
                      '        self._AbstractStateTrackingCondition__state = state\n'
                      '        return self._value_changed (state)\n'
                      '    else:\n'
                      '        return False')
                     % AbstractValueObject._get_object (options),
                     filtered_options, functions)

            execute ('def set (self, value): return self._set (value)', functions)

        for function in functions.items ():
            yield function