def test_sets(self): # Py2K import sets # end Py2K class SetLike(object): def add(self): pass class ForcedSet(list): __emulates__ = set for type_ in ( set, # Py2K sets.Set, # end Py2K SetLike, ForcedSet): eq_(util.duck_type_collection(type_), set) instance = type_() eq_(util.duck_type_collection(instance), set) for type_ in ( frozenset, # Py2K sets.ImmutableSet # end Py2K ): is_(util.duck_type_collection(type_), None) instance = type_() is_(util.duck_type_collection(instance), None)
def test_sets(self): # Py2K import sets # end Py2K class SetLike(object): def add(self): pass class ForcedSet(list): __emulates__ = set for type_ in (set, # Py2K sets.Set, # end Py2K SetLike, ForcedSet): eq_(util.duck_type_collection(type_), set) instance = type_() eq_(util.duck_type_collection(instance), set) for type_ in (frozenset, # Py2K sets.ImmutableSet # end Py2K ): is_(util.duck_type_collection(type_), None) instance = type_() is_(util.duck_type_collection(instance), None)
def __ior__(self, value): if sautil.duck_type_collection(value) is not Set: return NotImplemented for item in value: if item not in self: self.add(item) return self
def replicate_relation(source, target, attr, target_attr, cache=None): if attr.property.cascade.delete_orphan: process_scalar = replicate_no_merge process_list = replicate_filter else: process_scalar = reflect process_list = reflect_filter value = getattr(source, attr.key) target_attr_model = target_attr.property.mapper.class_ if attr.property.uselist: adapter = collection_adapter(value) if adapter: # XXX The magic passes below are adapted from logic in # CollectionAttributeImpl.set() method without proper # understanding. The `elif` branch isn't even coverered by tests. if hasattr(value, '_sa_iterator'): value = value._sa_iterator() elif duck_type_collection(value) is dict: value = value.values() reflection = process_list(value, target_attr_model, cache=cache) impl = instance_state(target).get_impl(attr.key) impl.set( instance_state(target), instance_dict(target), reflection, # XXX We either have to convert reflection back to original # collection type or use this private parameter. _adapt=False) else: reflection = process_scalar(value, target_attr_model, cache=cache) setattr(target, attr.key, reflection) if (reflection is None and attr.property.direction is MANYTOONE and any(col.primary_key and not col.nullable for col in attr.property.local_columns)): raise _PrimaryKeyIsNull()
def replicate_relation(source, target, attr, target_attr, cache=None): if attr.property.cascade.delete_orphan: process_scalar = replicate_no_merge process_list = replicate_filter else: process_scalar = reflect process_list = reflect_filter value = getattr(source, attr.key) target_attr_model = target_attr.property.mapper.class_ if attr.property.uselist: adapter = collection_adapter(value) if adapter: # XXX The magic passes below are adapted from logic in # CollectionAttributeImpl.set() method without proper # understanding. The `elif` branch isn't even coverered by tests. if hasattr(value, '_sa_iterator'): value = value._sa_iterator() elif duck_type_collection(value) is dict: value = value.values() reflection = process_list(value, target_attr_model, cache=cache) impl = instance_state(target).get_impl(attr.key) impl.set(instance_state(target), instance_dict(target), reflection, # XXX We either have to convert reflection back to original # collection type or use this private parameter. _adapt=False) else: reflection = process_scalar(value, target_attr_model, cache=cache) setattr(target, attr.key, reflection) if (reflection is None and attr.property.direction is MANYTOONE and any(col.primary_key and not col.nullable for col in attr.property.local_columns)): raise _PrimaryKeyIsNull()
def __init__( self, class_, key, callable_, typecallable=None, trackparent=False, extension=None, copy_function=None, compare_function=None, **kwargs ): super(CollectionAttributeImpl, self).__init__( class_, key, callable_, trackparent=trackparent, extension=extension, compare_function=compare_function, **kwargs ) if copy_function is None: copy_function = self.__copy self.copy = copy_function if typecallable is None: typecallable = list self.collection_factory = collections._prepare_instrumentation(typecallable) # may be removed in 0.5: self.collection_interface = util.duck_type_collection(self.collection_factory())
def __init__(self, class_, key, callable_, typecallable=None, trackparent=False, extension=None, copy_function=None, compare_function=None, **kwargs): super(CollectionAttributeImpl, self).__init__(class_, key, callable_, trackparent=trackparent, extension=extension, compare_function=compare_function, **kwargs) if copy_function is None: copy_function = self.__copy self.copy = copy_function if typecallable is None: typecallable = list self.collection_factory = \ collections._prepare_instrumentation(typecallable) # may be removed in 0.5: self.collection_interface = \ util.duck_type_collection(self.collection_factory())
def _new(self, lazy_collection): creator = self.creator and self.creator or self.target_class self.collection_class = util.duck_type_collection(lazy_collection()) if self.proxy_factory: return self.proxy_factory(lazy_collection, creator, self.value_attr, self) if self.getset_factory: getter, setter = self.getset_factory(self.collection_class, self) else: getter, setter = self._default_getset(self.collection_class) if self.collection_class is list: return _AssociationList(lazy_collection, creator, getter, setter, self) elif self.collection_class is dict: return _AssociationDict(lazy_collection, creator, getter, setter, self) elif self.collection_class is set: return _AssociationSet(lazy_collection, creator, getter, setter, self) else: raise exceptions.ArgumentError( 'could not guess which interface to use for ' 'collection_class "%s" backing "%s"; specify a ' 'proxy_factory and proxy_bulk_set manually' % (self.collection_class.__name__, self.target_collection))
def _new(self, lazy_collection): creator = self.creator and self.creator or self.target_class # Prefer class typing here to spot dicts with the required append() # method. collection = lazy_collection() if isinstance(collection.data, dict): self.collection_class = dict else: self.collection_class = util.duck_type_collection(collection.data) del collection if self.proxy_factory: return self.proxy_factory(lazy_collection, creator, self.value_attr) value_attr = self.value_attr getter = lambda o: getattr(o, value_attr) setter = lambda o, v: setattr(o, value_attr, v) if self.collection_class is list: return _AssociationList(lazy_collection, creator, getter, setter) elif self.collection_class is dict: kv_setter = lambda o, k, v: setattr(o, value_attr, v) return _AssociationDict(lazy_collection, creator, getter, kv_setter) elif self.collection_class is util.Set: return _AssociationSet(lazy_collection, creator, getter, setter) else: raise exceptions.ArgumentError( 'could not guess which interface to use for ' 'collection_class "%s" backing "%s"; specify a ' 'proxy_factory and proxy_bulk_set manually' % (self.collection_class.__name__, self.target_collection))
def test_sets(self): class SetLike(object): def add(self): pass class ForcedSet(list): __emulates__ = set for type_ in (set, SetLike, ForcedSet): eq_(util.duck_type_collection(type_), set) instance = type_() eq_(util.duck_type_collection(instance), set) for type_ in (frozenset, ): is_(util.duck_type_collection(type_), None) instance = type_() is_(util.duck_type_collection(instance), None)
def __iand__(self, other): if sautil.duck_type_collection(other) is not Set: return NotImplemented want, have = self.intersection(other), Set(self) remove, add = have - want, want - have for item in remove: self.remove(item) for item in add: self.add(item) return self
def __ixor__(self, other): if sautil.duck_type_collection(other) is not Set: return NotImplemented want, have = self.symmetric_difference(other), Set(self) remove, add = have - want, want - have for item in remove: self.remove(item) for item in add: self.add(item) return self
def __ixor__(self, other): if util.duck_type_collection(other) is not util.Set: return NotImplemented want, have = self.symmetric_difference(other), util.Set(self) remove, add = have - want, want - have for value in remove: self.remove(value) for value in add: self.add(value) return self
def __iand__(self, other): if util.duck_type_collection(other) is not util.Set: return NotImplemented want, have = self.intersection(other), util.Set(self) remove, add = have - want, want - have for value in remove: self.remove(value) for value in add: self.add(value) return self
def adapt_like_to_iterable(self, obj): """Converts collection-compatible objects to an iterable of values. Can be passed any type of object, and if the underlying collection determines that it can be adapted into a stream of values it can use, returns an iterable of values suitable for append()ing. This method may raise TypeError or any other suitable exception if adaptation fails. If a converter implementation is not supplied on the collection, a default duck-typing-based implementation is used. """ converter = getattr(self._data(), '_sa_converter', None) if converter is not None: return converter(obj) setting_type = util.duck_type_collection(obj) receiving_type = util.duck_type_collection(self._data()) if obj is None or setting_type != receiving_type: given = obj is None and 'None' or obj.__class__.__name__ if receiving_type is None: wanted = self._data().__class__.__name__ else: wanted = receiving_type.__name__ raise TypeError( "Incompatible collection type: %s is not %s-like" % ( given, wanted)) # If the object is an adapted collection, return the (iterable) # adapter. if getattr(obj, '_sa_adapter', None) is not None: return getattr(obj, '_sa_adapter') elif setting_type == dict: return getattr(obj, 'itervalues', getattr(obj, 'values'))() else: return iter(obj)
def _convert(self, collection): # TODO We could check if the objects' type is correct. type_ = util.duck_type_collection(collection) if type_ is dict: for key, value in util.dictlike_iteritems(collection): if key != self.keyfunc(value): raise TypeError("Found incompatible key '%r' for value '%r'" % (key, value)) yield value elif type_ in (list, set): for value in collection: yield value else: raise TypeError("Object '%r' is not dict-like nor iterable" % collection)
def _convert(self, coll): # TODO We could check if the objects' type is correct. type_ = util.duck_type_collection(coll) if type_ is dict: for key, value in util.dictlike_iteritems(coll): if key != self.keyfunc(value): raise TypeError( "Found incompatible key '%r' for value '%r'" % (key, value)) yield value elif type_ in (list, set): for value in coll: yield value else: raise TypeError("Object '%r' is not dict-like nor iterable" % coll)
def __init__(self, ftype, type, **kwargs): ''' Construct the field object on an mvc class Parameters: ftype: field type (MVCTypeField, MVCTypeList, or/and MVCTypeParam) type: Datatype (String, Numeric, Date, Time) Args: label: identify label for this field required: identify that value entered in this field is required, thus it must not empty enabled: identify the field is enabled for editing visible: set the field visibility on client browseable: identify if data on this field could be retrieved from lookup browser synchronized: identify any modification made on this field must be synchronized by server charcase: identify input charcase type (ecUpperCase, ecLowerCase) choices: set the multiple choice for this field (usually shown by a combo box control) updateable: set if this field updateable into persistent media (table) ''' self.properties = MVCFieldProperty() if isinstance(type, TypeEngine): self.properties.type = type else: atype = object.__new__(type) atype.__init__() self.properties.type = atype self.properties.ftype = ftype self.properties.label = kwargs.pop('label', None) self.properties.required = kwargs.pop('required', False) self.properties.enabled = kwargs.pop('enabled', True) self.properties.visible = kwargs.pop('visible', True) self.properties.readOnly = kwargs.pop('readOnly', False) self.properties.synchronized = kwargs.pop('synchronized', False) self.properties.browseable = kwargs.pop('browseable', False) self.properties.charcase = kwargs.pop('charcase', ecNormal) self.properties.updateable = kwargs.pop('updateable', True) choice = kwargs.pop('choices', {}) choice_type = sautil.duck_type_collection(choice) if choice and (choice_type == types.ListType or choice == types.TupleType): for itval in choice: self.properties.choices[itval] = itval else: if (choice_type == types.DictType): self.properties.choices = choice.copy() self.properties.primaryKey = kwargs.pop('primaryKey', False) self.properties.kwargs = kwargs
def set(self, state, value, initiator): """Set a value on the given object. `initiator` is the ``InstrumentedAttribute`` that initiated the ``set()` operation and is used to control the depth of a circular setter operation. """ if initiator is self: return setting_type = util.duck_type_collection(value) if value is None or setting_type != self.collection_interface: raise exceptions.ArgumentError( "Incompatible collection type on assignment: %s is not %s-like" % (type(value).__name__, self.collection_interface.__name__)) if hasattr(value, '_sa_adapter'): value = list(getattr(value, '_sa_adapter')) elif setting_type == dict: value = value.values() # if an instance-wide "trigger" was set, call that if state.trigger: state.call_trigger() old = self.get(state) old_collection = self.get_collection(state, old) new_collection, user_data = self._build_collection(state) self._load_collection(state, value or [], emit_events=True, collection=new_collection) state.dict[self.key] = user_data state.modified = True # mark all the old elements as detached from the parent if old_collection: old_collection.clear_with_event() old_collection.unlink(old)
def _set_binops_check_loose(self, obj): """Allow anything set-like to participate in set binops.""" return (isinstance(obj, _set_binop_bases + (self.__class__,)) or util.duck_type_collection(obj) == set)
def _instrument_class(cls): """Modify methods in a class and install instrumentation.""" # TODO: more formally document this as a decoratorless/Python 2.3 # option for specifying instrumentation. (likely doc'd here in code only, # not in online docs.) Useful for C types too. # # __instrumentation__ = { # 'rolename': 'methodname', # ... # 'methods': { # 'methodname': ('fire_{append,remove}_event', argspec, # 'fire_{append,remove}_event'), # 'append': ('fire_append_event', 1, None), # '__setitem__': ('fire_append_event', 1, 'fire_remove_event'), # 'pop': (None, None, 'fire_remove_event'), # } # } # In the normal call flow, a request for any of the 3 basic collection # types is transformed into one of our trivial subclasses # (e.g. InstrumentedList). Catch anything else that sneaks in here... if cls.__module__ == '__builtin__': raise sa_exc.ArgumentError( "Can not instrument a built-in type. Use a " "subclass, even a trivial one.") collection_type = util.duck_type_collection(cls) if collection_type in __interfaces: roles = __interfaces[collection_type].copy() decorators = roles.pop('_decorators', {}) else: roles, decorators = {}, {} if hasattr(cls, '__instrumentation__'): roles.update(copy.deepcopy(getattr(cls, '__instrumentation__'))) methods = roles.pop('methods', {}) for name in dir(cls): method = getattr(cls, name, None) if not util.callable(method): continue # note role declarations if hasattr(method, '_sa_instrument_role'): role = method._sa_instrument_role assert role in ('appender', 'remover', 'iterator', 'on_link', 'converter') roles[role] = name # transfer instrumentation requests from decorated function # to the combined queue before, after = None, None if hasattr(method, '_sa_instrument_before'): op, argument = method._sa_instrument_before assert op in ('fire_append_event', 'fire_remove_event') before = op, argument if hasattr(method, '_sa_instrument_after'): op = method._sa_instrument_after assert op in ('fire_append_event', 'fire_remove_event') after = op if before: methods[name] = before[0], before[1], after elif after: methods[name] = None, None, after # apply ABC auto-decoration to methods that need it for method, decorator in decorators.items(): fn = getattr(cls, method, None) if (fn and method not in methods and not hasattr(fn, '_sa_instrumented')): setattr(cls, method, decorator(fn)) # ensure all roles are present, and apply implicit instrumentation if # needed if 'appender' not in roles or not hasattr(cls, roles['appender']): raise sa_exc.ArgumentError( "Type %s must elect an appender method to be " "a collection class" % cls.__name__) elif (roles['appender'] not in methods and not hasattr(getattr(cls, roles['appender']), '_sa_instrumented')): methods[roles['appender']] = ('fire_append_event', 1, None) if 'remover' not in roles or not hasattr(cls, roles['remover']): raise sa_exc.ArgumentError( "Type %s must elect a remover method to be " "a collection class" % cls.__name__) elif (roles['remover'] not in methods and not hasattr(getattr(cls, roles['remover']), '_sa_instrumented')): methods[roles['remover']] = ('fire_remove_event', 1, None) if 'iterator' not in roles or not hasattr(cls, roles['iterator']): raise sa_exc.ArgumentError( "Type %s must elect an iterator method to be " "a collection class" % cls.__name__) # apply ad-hoc instrumentation from decorators, class-level defaults # and implicit role declarations for method, (before, argument, after) in methods.items(): setattr(cls, method, _instrument_membership_mutator(getattr(cls, method), before, argument, after)) # intern the role map for role, method in roles.items(): setattr(cls, '_sa_%s' % role, getattr(cls, method)) setattr(cls, '_sa_instrumented', id(cls))
def _instrument_class(cls): """Modify methods in a class and install instrumentation.""" # FIXME: more formally document this as a decoratorless/Python 2.3 # option for specifying instrumentation. (likely doc'd here in code only, # not in online docs.) # # __instrumentation__ = { # 'rolename': 'methodname', # ... # 'methods': { # 'methodname': ('fire_{append,remove}_event', argspec, # 'fire_{append,remove}_event'), # 'append': ('fire_append_event', 1, None), # '__setitem__': ('fire_append_event', 1, 'fire_remove_event'), # 'pop': (None, None, 'fire_remove_event'), # } # } # In the normal call flow, a request for any of the 3 basic collection # types is transformed into one of our trivial subclasses # (e.g. InstrumentedList). Catch anything else that sneaks in here... if cls.__module__ == '__builtin__': raise exceptions.ArgumentError( "Can not instrument a built-in type. Use a " "subclass, even a trivial one.") collection_type = sautil.duck_type_collection(cls) if collection_type in __interfaces: roles = __interfaces[collection_type].copy() decorators = roles.pop('_decorators', {}) else: roles, decorators = {}, {} if hasattr(cls, '__instrumentation__'): roles.update(copy.deepcopy(getattr(cls, '__instrumentation__'))) methods = roles.pop('methods', {}) for name in dir(cls): method = getattr(cls, name) if not callable(method): continue # note role declarations if hasattr(method, '_sa_instrument_role'): role = method._sa_instrument_role assert role in ('appender', 'remover', 'iterator', 'on_link') roles[role] = name # transfer instrumentation requests from decorated function # to the combined queue before, after = None, None if hasattr(method, '_sa_instrument_before'): op, argument = method._sa_instrument_before assert op in ('fire_append_event', 'fire_remove_event') before = op, argument if hasattr(method, '_sa_instrument_after'): op = method._sa_instrument_after assert op in ('fire_append_event', 'fire_remove_event') after = op if before: methods[name] = before[0], before[1], after elif after: methods[name] = None, None, after # apply ABC auto-decoration to methods that need it for method, decorator in decorators.items(): fn = getattr(cls, method, None) if fn and method not in methods and not hasattr( fn, '_sa_instrumented'): setattr(cls, method, decorator(fn)) # ensure all roles are present, and apply implicit instrumentation if # needed if 'appender' not in roles or not hasattr(cls, roles['appender']): raise exceptions.ArgumentError( "Type %s must elect an appender method to be " "a collection class" % cls.__name__) elif (roles['appender'] not in methods and not hasattr(getattr(cls, roles['appender']), '_sa_instrumented')): methods[roles['appender']] = ('fire_append_event', 1, None) if 'remover' not in roles or not hasattr(cls, roles['remover']): raise exceptions.ArgumentError( "Type %s must elect a remover method to be " "a collection class" % cls.__name__) elif (roles['remover'] not in methods and not hasattr(getattr(cls, roles['remover']), '_sa_instrumented')): methods[roles['remover']] = ('fire_remove_event', 1, None) if 'iterator' not in roles or not hasattr(cls, roles['iterator']): raise exceptions.ArgumentError( "Type %s must elect an iterator method to be " "a collection class" % cls.__name__) # apply ad-hoc instrumentation from decorators, class-level defaults # and implicit role declarations for method, (before, argument, after) in methods.items(): setattr( cls, method, _instrument_membership_mutator(getattr(cls, method), before, argument, after)) # intern the role map for role, method in roles.items(): setattr(cls, '_sa_%s' % role, getattr(cls, method)) setattr(cls, '_sa_instrumented', id(cls))
def __isub__(self, other): if util.duck_type_collection(other) is not util.Set: return NotImplemented for value in other: self.discard(value) return self
def __isub__(self, value): if sautil.duck_type_collection(value) is not Set: return NotImplemented for item in value: self.discard(item) return self
def __init__(self, entity, *a, **kw): kw.setdefault('bundle_errors', True) self.default_location = kw.pop('location', []) self.relation_overlay = kw.pop('relation_overlay', False) super(EntityParser, self).__init__(*a, **kw) columns = inspect(entity).columns relation_column = {} for relationship in inspect(entity).relationships: if len(relationship.local_columns): column, = relationship.local_columns relation_column[column.name] = relationship.key for column in columns: # TODO: better validation if column.name in ['namespace' ]: # TODO: move this to columns defination continue type_ = column.type.python_type if type_ == datetime: type_ = inputs.datetime_from_iso8601 self.add_argument(column.name if (not self.relation_overlay or column.name not in relation_column) else relation_column[column.name], type=type_, location=self.default_location, store_missing=False, required=FuncBool( self.default_required, column.default is None and not column.nullable), dest=column.name) for attr in entity.attribute_models.values(): duck_type = duck_type_collection(attr.__collector__()) default = None # Don't give None on empty for compatibility with associate proxy action = 'store' if duck_type in (dict, ): default = duck_type() elif duck_type in (list, set): type_ = duck_type action = 'append' def duck_type(x): return x else: default = None if not duck_type: logger.error( 'Unsupported attribute collection for attribute: {}'. format(attr)) self.add_argument(attr.ref_name, type=duck_type, location=self.default_location, store_missing=False, default=default, action=action) self.normal_arg_names = [arg.name for arg in self.args]