def replicate_attributes(source, target, cache=None): '''Replicates common SQLAlchemy attributes from the `source` object to the `target` object.''' target_manager = manager_of_class(type(target)) column_attrs = set() relationship_attrs = set() relationship_columns = set() for attr in manager_of_class(type(source)).attributes: if attr.key not in target_manager: # It's not common attribute continue target_attr = target_manager[attr.key] if isinstance(attr.property, ColumnProperty): assert isinstance(target_attr.property, ColumnProperty) column_attrs.add(attr) elif isinstance(attr.property, RelationshipProperty): assert isinstance(target_attr.property, RelationshipProperty) relationship_attrs.add(attr) if attr.property.direction is MANYTOONE: relationship_columns.update(attr.property.local_columns) for attr in column_attrs: if _column_property_in_registry(attr.property, _excluded): continue elif (not _column_property_in_registry(attr.property, _included) and all(column in relationship_columns for column in attr.property.columns)): continue setattr(target, attr.key, getattr(source, attr.key)) for attr in relationship_attrs: target_attr_model = target_manager[attr.key].property.argument if not is_relation_replicatable(attr): continue replicate_relation(source, target, attr, target_manager[attr.key], cache=cache)
def test_uninstrument(self): class A(object):pass manager = attributes.register_class(A) assert attributes.manager_of_class(A) is manager attributes.unregister_class(A) assert attributes.manager_of_class(A) is None
def test_uninstrument(self): class A(object): pass manager = attributes.register_class(A) assert attributes.manager_of_class(A) is manager attributes.unregister_class(A) assert attributes.manager_of_class(A) is None
def test_null_instrumentation(self): class Foo(MyBaseClass): pass attributes.register_class(Foo) attributes.register_attribute(Foo, "name", uselist=False, useobject=False) attributes.register_attribute(Foo, "bars", uselist=True, trackparent=True, useobject=True) assert Foo.name == attributes.manager_of_class(Foo)['name'] assert Foo.bars == attributes.manager_of_class(Foo)['bars']
def test_rebuild_state(self): """not much of a 'test', but illustrate how to remove instance-level state before pickling. """ mapper(User, users) u1 = User() attributes.manager_of_class(User).teardown_instance(u1) assert not u1.__dict__ u2 = pickle.loads(pickle.dumps(u1)) attributes.manager_of_class(User).setup_instance(u2) assert attributes.instance_state(u2)
def _entity_descriptor(entity, key): """Return attribute/property information given an entity and string name. Returns a 2-tuple representing InstrumentedAttribute/MapperProperty. """ if isinstance(entity, AliasedClass): try: desc = getattr(entity, key) return desc, desc.property except AttributeError: raise sa_exc.InvalidRequestError("Entity '%s' has no property '%s'" % (entity, key)) elif isinstance(entity, type): try: desc = attributes.manager_of_class(entity)[key] return desc, desc.property except KeyError: raise sa_exc.InvalidRequestError("Entity '%s' has no property '%s'" % (entity, key)) else: try: desc = entity.class_manager[key] return desc, desc.property except KeyError: raise sa_exc.InvalidRequestError("Entity '%s' has no property '%s'" % (entity, key))
def __new__(cls, schema, id_fields=None, **fields): if isinstance(schema, basestring): table = metadata.tables.get(schema, None) if table is None: raise ValueError("%s is not defined in the metadata" % schema) managed_class = managed_class_of_table(table) elif isinstance(schema, Table): table = schema managed_class = managed_class_of_table(table) elif isinstance(schema, Mapper): table = schema.local_table managed_class = schema.class_ else: manager = manager_of_class(schema) if manager is not None: managed_class = manager table = manager.mapper.local_table else: raise TypeError( "schema must be either a table name or a %s instance" % Table.__name__) if managed_class is not None: assert not issubclass(managed_class, DatumBase) _cls = lookup_mixin_class(managed_class) else: _cls = cls newinstance = object.__new__(_cls) newinstance._tableau_table = table return newinstance
def test_standard(self): class A(object): pass attributes.register_class(A) eq_(type(attributes.manager_of_class(A)), attributes.ClassManager)
def __build_operation_from_file(self, project, operation_file): """ Create Operation entity from metadata file. """ operation_dict = XMLReader(operation_file).read_metadata() operation_entity = manager_of_class(model.Operation).new_instance() return operation_entity.from_dict(operation_dict, dao, self.user_id, project.gid)
def build_operation_from_file(self, project, operation_file): """ Create Operation entity from metadata file. """ operation_dict = StorageInterface().read_metadata_from_xml(operation_file) operation_entity = manager_of_class(Operation).new_instance() return operation_entity.from_dict(operation_dict, dao, self.user_id, project.gid)
def __new__(cls, schema, id_fields=None, **fields): if isinstance(schema, basestring): table = metadata.tables.get(schema, None) if table is None: raise ValueError("%s is not defined in the metadata" % schema) managed_class = managed_class_of_table(table) elif isinstance(schema, Table): table = schema managed_class = managed_class_of_table(table) elif isinstance(schema, Mapper): table = schema.local_table managed_class = schema.class_ else: manager = manager_of_class(schema) if manager is not None: managed_class = manager table = manager.mapper.local_table else: raise TypeError("schema must be either a table name or a %s instance" % Table.__name__) if managed_class is not None: assert not issubclass(managed_class, DatumBase) _cls = lookup_mixin_class(managed_class) else: _cls = cls newinstance = object.__new__(_cls) newinstance._tableau_table = table return newinstance
def __setstate__(self, state): self.obj = weakref.ref(state['instance'], self._cleanup) self.class_ = state['instance'].__class__ self.manager = manager = manager_of_class(self.class_) if manager is None: raise orm_exc.UnmappedInstanceError( state['instance'], "Cannot deserialize object of type %r - no mapper() has" " been configured for this class within the current Python process!" % self.class_) elif manager.is_mapped and not manager.mapper.compiled: manager.mapper.compile() self.committed_state = state.get('committed_state', {}) self.pending = state.get('pending', {}) self.parents = state.get('parents', {}) self.modified = state.get('modified', False) self.expired = state.get('expired', False) self.callables = state.get('callables', {}) if self.modified: self._strong_obj = state['instance'] self.__dict__.update([ (k, state[k]) for k in ( 'key', 'load_options', 'mutable_dict' ) if k in state ]) if 'load_path' in state: self.load_path = interfaces.deserialize_path(state['load_path'])
def _entity_info(entity, compile=True): """Return mapping information given a class, mapper, or AliasedClass. Returns 3-tuple of: mapper, mapped selectable, boolean indicating if this is an aliased() construct. If the given entity is not a mapper, mapped class, or aliased construct, returns None, the entity, False. This is typically used to allow unmapped selectables through. """ if isinstance(entity, AliasedClass): return entity._AliasedClass__mapper, entity._AliasedClass__alias, True if isinstance(entity, mapperlib.Mapper): mapper = entity elif isinstance(entity, type): class_manager = attributes.manager_of_class(entity) if class_manager is None: return None, entity, False mapper = class_manager.mapper else: return None, entity, False if compile and mapperlib.module._new_mappers: mapperlib.configure_mappers() return mapper, mapper._with_polymorphic_selectable, False
def test_nativeext_submanager(self): class Mine(attributes.ClassManager): pass class A(object): __sa_instrumentation_manager__ = Mine attributes.register_class(A) eq_(type(attributes.manager_of_class(A)), Mine)
def _entity_info(entity, compile=True): """Return mapping information given a class, mapper, or AliasedClass. Returns 3-tuple of: mapper, mapped selectable, boolean indicating if this is an aliased() construct. If the given entity is not a mapper, mapped class, or aliased construct, returns None, the entity, False. This is typically used to allow unmapped selectables through. """ if isinstance(entity, AliasedClass): return entity._AliasedClass__mapper, entity._AliasedClass__alias, True if isinstance(entity, mapperlib.Mapper): mapper = entity elif isinstance(entity, type): class_manager = attributes.manager_of_class(entity) if class_manager is None: return None, entity, False mapper = class_manager.mapper else: return None, entity, False if compile: mapper = mapper.compile() return mapper, mapper._with_polymorphic_selectable, False
def __setstate__(self, state): self.obj = weakref.ref(state["instance"], self._cleanup) self.class_ = state["instance"].__class__ self.manager = manager = manager_of_class(self.class_) if manager is None: raise orm_exc.UnmappedInstanceError( state["instance"], "Cannot deserialize object of type %r - no mapper() has" " been configured for this class within the current Python process!" % self.class_, ) elif manager.mapper and not manager.mapper.compiled: manager.mapper.compile() self.committed_state = state.get("committed_state", {}) self.pending = state.get("pending", {}) self.parents = state.get("parents", {}) self.modified = state.get("modified", False) self.expired = state.get("expired", False) self.callables = state.get("callables", {}) if self.modified: self._strong_obj = state["instance"] self.__dict__.update([(k, state[k]) for k in ("key", "load_options", "mutable_dict") if k in state]) if "load_path" in state: self.load_path = interfaces.deserialize_path(state["load_path"])
def _entity_descriptor(entity, key): """Return attribute/property information given an entity and string name. Returns a 2-tuple representing InstrumentedAttribute/MapperProperty. """ if isinstance(entity, AliasedClass): try: desc = getattr(entity, key) return desc, desc.property except AttributeError: raise sa_exc.InvalidRequestError( "Entity '%s' has no property '%s'" % (entity, key)) elif isinstance(entity, type): try: desc = attributes.manager_of_class(entity)[key] return desc, desc.property except KeyError: raise sa_exc.InvalidRequestError( "Entity '%s' has no property '%s'" % (entity, key)) else: try: desc = entity.class_manager[key] return desc, desc.property except KeyError: raise sa_exc.InvalidRequestError( "Entity '%s' has no property '%s'" % (entity, key))
def _import_image(self, src_folder, metadata_file, project_id, target_images_path): """ Create and store a image entity. """ figure_dict = XMLReader(os.path.join(src_folder, metadata_file)).read_metadata() actual_figure = os.path.join( src_folder, os.path.split(figure_dict['file_path'])[1]) if not os.path.exists(actual_figure): self.logger.warning("Expected to find image path %s .Skipping" % actual_figure) return figure_dict['fk_user_id'] = self.user_id figure_dict['fk_project_id'] = project_id figure_entity = manager_of_class(ResultFigure).new_instance() figure_entity = figure_entity.from_dict(figure_dict) stored_entity = dao.store_entity(figure_entity) # Update image meta-data with the new details after import figure = dao.load_figure(stored_entity.id) shutil.move(actual_figure, target_images_path) self.logger.debug("Store imported figure") self.files_helper.write_image_metadata(figure)
def __setstate__(self, state): self.obj = weakref.ref(state['instance'], self._cleanup) self.class_ = state['instance'].__class__ self.manager = manager = manager_of_class(self.class_) if manager is None: raise orm_exc.UnmappedInstanceError( state['instance'], "Cannot deserialize object of type %r - no mapper() has" " been configured for this class within the current Python process!" % self.class_) elif manager.is_mapped and not manager.mapper.compiled: manager.mapper.compile() self.committed_state = state.get('committed_state', {}) self.pending = state.get('pending', {}) self.parents = state.get('parents', {}) self.modified = state.get('modified', False) self.expired = state.get('expired', False) self.callables = state.get('callables', {}) if self.modified: self._strong_obj = state['instance'] self.__dict__.update([(k, state[k]) for k in ('key', 'load_options', 'mutable_dict') if k in state]) if 'load_path' in state: self.load_path = interfaces.deserialize_path(state['load_path'])
def _setup_table(self, table=None): cls = self.cls tablename = self.tablename table_args = self.table_args dict_ = self.dict_ declared_columns = self.declared_columns manager = attributes.manager_of_class(cls) declared_columns = self.declared_columns = sorted( declared_columns, key=lambda c: c._creation_order ) if "__table__" not in dict_ and table is None: if hasattr(cls, "__table_cls__"): table_cls = util.unbound_method_to_callable(cls.__table_cls__) else: table_cls = Table if tablename is not None: args, table_kw = (), {} if table_args: if isinstance(table_args, dict): table_kw = table_args elif isinstance(table_args, tuple): if isinstance(table_args[-1], dict): args, table_kw = table_args[0:-1], table_args[-1] else: args = table_args autoload_with = dict_.get("__autoload_with__") if autoload_with: table_kw["autoload_with"] = autoload_with autoload = dict_.get("__autoload__") if autoload: table_kw["autoload"] = True table = self.set_cls_attribute( "__table__", table_cls( tablename, self._metadata_for_cls(manager), *(tuple(declared_columns) + tuple(args)), **table_kw ), ) else: if table is None: table = cls.__table__ if declared_columns: for c in declared_columns: if not table.c.contains_column(c): raise exc.ArgumentError( "Can't add additional column %r when " "specifying __table__" % c.key ) self.local_table = table
def _is_mapped_class(cls): from sqlalchemy.orm import mapperlib as mapper if isinstance(cls, (AliasedClass, mapper.Mapper)): return True if isinstance(cls, expression.ClauseElement): return False manager = attributes.manager_of_class(cls) return manager and _INSTRUMENTOR in manager.info
def test_customfinder_pass(self): class A(object): pass def find(cls): return None attributes.instrumentation_finders.insert(0, find) attributes.register_class(A) eq_(type(attributes.manager_of_class(A)), attributes.ClassManager)
def test_collectionclasses(self): class Foo(object):pass attributes.register_class(Foo) attributes.register_attribute(Foo, "collection", uselist=True, typecallable=set, useobject=True) assert attributes.manager_of_class(Foo).is_instrumented("collection") assert isinstance(Foo().collection, set) attributes.unregister_attribute(Foo, "collection") assert not attributes.manager_of_class(Foo).is_instrumented("collection") try: attributes.register_attribute(Foo, "collection", uselist=True, typecallable=dict, useobject=True) assert False except sa_exc.ArgumentError, e: assert str(e) == "Type InstrumentedDict must elect an appender method to be a collection class"
def register(self, cls, canary): original_init = cls.__init__ attributes.register_class(cls) ne_(cls.__init__, original_init) manager = attributes.manager_of_class(cls) def on_init(state, instance, args, kwargs): canary.append((cls, 'on_init', type(instance))) manager.events.add_listener('on_init', on_init)
def test_unregister(self, registry): class MyClassState(instrumentation.InstrumentationManager): def manage(self, class_, manager): setattr(class_, "xyz", manager) def unregister(self, class_, manager): delattr(class_, "xyz") def manager_getter(self, class_): def get(cls): return cls.xyz return get class MyClass: __sa_instrumentation_manager__ = MyClassState assert attributes.opt_manager_of_class(MyClass) is None with expect_raises_message( sa.orm.exc.UnmappedClassError, r"Can't locate an instrumentation manager for class .*MyClass", ): attributes.manager_of_class(MyClass) t = Table( "my_table", registry.metadata, Column("id", Integer, primary_key=True), ) registry.map_imperatively(MyClass, t) manager = attributes.opt_manager_of_class(MyClass) is_not(manager, None) is_(manager, MyClass.xyz) registry.configure() registry.dispose() manager = attributes.opt_manager_of_class(MyClass) is_(manager, None) assert not hasattr(MyClass, "xyz")
def test_alternate_finders(self): """Ensure the generic finder front-end deals with edge cases.""" class Unknown(object): pass class Known(MyBaseClass): pass attributes.register_class(Known) k, u = Known(), Unknown() assert attributes.manager_of_class(Unknown) is None assert attributes.manager_of_class(Known) is not None assert attributes.manager_of_class(None) is None assert attributes.instance_state(k) is not None assert_raises((AttributeError, KeyError), attributes.instance_state, u) assert_raises((AttributeError, KeyError), attributes.instance_state, None)
def _mapper_or_none(cls): """Return the :class:`.Mapper` for the given class or None if the class is not mapped.""" manager = attributes.manager_of_class(cls) if manager is not None and _INSTRUMENTOR in manager.info: return manager.info[_INSTRUMENTOR] else: return None
def _is_mapped_class(cls): if isinstance(cls, (AliasedClass, mapperlib.Mapper)): return True if isinstance(cls, expression.ClauseElement): return False if isinstance(cls, type): manager = attributes.manager_of_class(cls) return manager and _INSTRUMENTOR in manager.info return False
def test_deferred(self): for base in (object, MyBaseClass, MyClass): class Foo(base): pass data = {'a': 'this is a', 'b': 12} def loader(state, keys): for k in keys: state.dict[k] = data[k] return attributes.ATTR_WAS_SET attributes.register_class(Foo) manager = attributes.manager_of_class(Foo) manager.deferred_scalar_loader = loader attributes.register_attribute(Foo, 'a', uselist=False, useobject=False) attributes.register_attribute(Foo, 'b', uselist=False, useobject=False) assert Foo in attributes.instrumentation_registry._state_finders f = Foo() attributes.instance_state(f).expire_attributes( attributes.instance_dict(f), None) eq_(f.a, "this is a") eq_(f.b, 12) f.a = "this is some new a" attributes.instance_state(f).expire_attributes( attributes.instance_dict(f), None) eq_(f.a, "this is a") eq_(f.b, 12) attributes.instance_state(f).expire_attributes( attributes.instance_dict(f), None) f.a = "this is another new a" eq_(f.a, "this is another new a") eq_(f.b, 12) attributes.instance_state(f).expire_attributes( attributes.instance_dict(f), None) eq_(f.a, "this is a") eq_(f.b, 12) del f.a eq_(f.a, None) eq_(f.b, 12) attributes.instance_state(f).commit_all( attributes.instance_dict(f)) eq_(f.a, None) eq_(f.b, 12)
def get_state_dict(instance,name="Generic"): cls = type(instance) mgr = manager_of_class(cls) myDict = dict((key, sanitize(getattr(instance, key))) for key, attr in mgr.iteritems() if isinstance(attr.property, ColumnProperty)) # next, we convert the dictionary to a 'namespace', # which allows us to use dot notation # XXX used named tuple instead? nameSpace = ap.Namespace(**myDict) return nameSpace
def _is_mapped_class(cls): """Return True if the given object is a mapped class, :class:`.Mapper`, or :class:`.AliasedClass`.""" if isinstance(cls, (AliasedClass, mapperlib.Mapper)): return True if isinstance(cls, expression.ClauseElement): return False if isinstance(cls, type): manager = attributes.manager_of_class(cls) return manager and _INSTRUMENTOR in manager.info return False
def test_subclassed(self): class MyEvents(attributes.Events): pass class MyClassManager(attributes.ClassManager): event_registry_factory = MyEvents attributes.instrumentation_finders.insert(0, lambda cls: MyClassManager) class A(object): pass attributes.register_class(A) manager = attributes.manager_of_class(A) assert isinstance(manager.events, MyEvents)
def test_unregister(self, registry): class MyClassState(instrumentation.InstrumentationManager): def manage(self, class_, manager): setattr(class_, "xyz", manager) def unregister(self, class_, manager): delattr(class_, "xyz") def manager_getter(self, class_): def get(cls): return cls.xyz return get class MyClass(object): __sa_instrumentation_manager__ = MyClassState assert attributes.manager_of_class(MyClass) is None t = Table( "my_table", registry.metadata, Column("id", Integer, primary_key=True), ) registry.map_imperatively(MyClass, t) manager = attributes.manager_of_class(MyClass) is_not(manager, None) is_(manager, MyClass.xyz) registry.configure() registry.dispose() manager = attributes.manager_of_class(MyClass) is_(manager, None) assert not hasattr(MyClass, "xyz")
def _dive_for_cls_manager(cls): # because the class manager registration is pluggable, # we need to do the search for every class in the hierarchy, # rather than just a simple "cls._sa_class_manager" # python 2 old style class if not hasattr(cls, "__mro__"): return None for base in cls.__mro__: manager = attributes.manager_of_class(base) if manager: return manager return None
def _entity_descriptor(entity, key): """Return attribute/property information given an entity and string name. Returns a 2-tuple representing InstrumentedAttribute/MapperProperty. """ if isinstance(entity, AliasedClass): desc = getattr(entity, key) return desc, desc.property elif isinstance(entity, type): desc = attributes.manager_of_class(entity)[key] return desc, desc.property else: desc = entity.class_manager[key] return desc, desc.property
def copy(self, deep=False, ignores=set(), *args, **kwds): cls = type(self) manager = manager_of_class(cls) if not manager: raise TypeError('No mapper: {}'.format(cls)) def _get_ignore_attributes(): for super_cls in cls.__mro__: yield getattr(super_cls, '__copy_ignores__', []) yield ignores # argument # select ignore properties ignore_attributes = set() for _ignores in _get_ignore_attributes(): ignore_attributes.update(_ignores) # select properties columns = {} relationships = {} for attr in manager.mapper.iterate_properties: if attr.key not in ignore_attributes: if isinstance(attr, ColumnProperty): columns[attr.key] = attr elif isinstance(attr, RelationshipProperty): relationships[attr.key] = attr else: pass # ignore # copy new_obj = type(self)() for key in attr in columns.items(): value = getattr(self, key) setattr(new_obj, key, value) # deep copy if deep: for key in attr in relationships.items(): value = getattr(self, key) setattr(new_obj, key, value) if attr.uselist: objs = [obj for obj in getattr(self, key) if hasattr(obj, 'clone') ] setattr(new_obj, key, objs) else: obj = getattr(self, 'key') setattr(self, key, obj) return new_obj
def test_register_reserved_attribute(self): class T(object): pass attributes.register_class(T) manager = attributes.manager_of_class(T) sa = attributes.ClassManager.STATE_ATTR ma = attributes.ClassManager.MANAGER_ATTR fails = lambda method, attr: assert_raises( KeyError, getattr(manager, method), attr, property()) fails('install_member', sa) fails('install_member', ma) fails('install_descriptor', sa) fails('install_descriptor', ma)
def lookup_mixin_class(managed_class): class_name = "SADatum#%s" % managed_class.__name__ retval = mixin_class_registry.get(managed_class) if retval is None: mapper = manager_of_class(managed_class).mapper dict_ = dict(pair for pair in managed_class.__dict__.items() if not isinstance(pair[1], InstrumentedAttribute) and pair[0] != '__init__' and not pair[0].startswith('_sa_')) dict_['_tableau_managed_class'] = managed_class if mapper.inherits: super_ = lookup_mixin_class(mapper.inherits.class_) else: super_ = SADatum retval = type(class_name, (super_, ), dict_) retval.__mapper__ = clone_mapper(mapper, retval) mixin_class_registry[managed_class] = retval return retval
def class_mapper(class_, compile=True): """Given a class, return the primary Mapper associated with the key. Raises UnmappedClassError if no mapping is configured. """ try: class_manager = attributes.manager_of_class(class_) mapper = class_manager.mapper except exc.NO_STATE: raise exc.UnmappedClassError(class_) if compile: mapper = mapper.compile() return mapper
def _class_to_mapper(class_or_mapper, compile=True): if _is_aliased_class(class_or_mapper): return class_or_mapper._AliasedClass__mapper elif isinstance(class_or_mapper, type): try: class_manager = attributes.manager_of_class(class_or_mapper) mapper = class_manager.mapper except exc.NO_STATE: raise exc.UnmappedClassError(class_or_mapper) elif isinstance(class_or_mapper, mapperlib.Mapper): mapper = class_or_mapper else: raise exc.UnmappedClassError(class_or_mapper) if compile and mapperlib.module._new_mappers: mapperlib.configure_mappers() return mapper
def __populate_project(self, project_path): """ Create and store a Project entity. """ self.logger.debug("Creating project from path: %s" % project_path) project_dict = self.files_helper.read_project_metadata(project_path) project_entity = manager_of_class(model.Project).new_instance() project_entity = project_entity.from_dict(project_dict, self.user_id) try: self.logger.debug("Storing imported project") return dao.store_entity(project_entity) except IntegrityError, excep: self.logger.exception(excep) error_msg = ("Could not import project: %s with gid: %s. There is already a " "project with the same name or gid.") % (project_entity.name, project_entity.gid) raise ProjectImportException(error_msg)
def test_deferred(self): for base in (object, MyBaseClass, MyClass): class Foo(base):pass data = {'a':'this is a', 'b':12} def loader(state, keys): for k in keys: state.dict[k] = data[k] return attributes.ATTR_WAS_SET attributes.register_class(Foo) manager = attributes.manager_of_class(Foo) manager.deferred_scalar_loader = loader attributes.register_attribute(Foo, 'a', uselist=False, useobject=False) attributes.register_attribute(Foo, 'b', uselist=False, useobject=False) assert Foo in attributes.instrumentation_registry._state_finders f = Foo() attributes.instance_state(f).expire_attributes(attributes.instance_dict(f), None) eq_(f.a, "this is a") eq_(f.b, 12) f.a = "this is some new a" attributes.instance_state(f).expire_attributes(attributes.instance_dict(f), None) eq_(f.a, "this is a") eq_(f.b, 12) attributes.instance_state(f).expire_attributes(attributes.instance_dict(f), None) f.a = "this is another new a" eq_(f.a, "this is another new a") eq_(f.b, 12) attributes.instance_state(f).expire_attributes(attributes.instance_dict(f), None) eq_(f.a, "this is a") eq_(f.b, 12) del f.a eq_(f.a, None) eq_(f.b, 12) attributes.instance_state(f).commit_all(attributes.instance_dict(f)) eq_(f.a, None) eq_(f.b, 12)
def test_basic(self): import pickle global A class A(object): pass def canary(instance): assert False try: attributes.register_class(A) manager = attributes.manager_of_class(A) manager.events.add_listener('on_load', canary) a = A() p_a = pickle.dumps(a) re_a = pickle.loads(p_a) finally: del A