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