~ubuntu-branches/debian/jessie/sqlalchemy/jessie

« back to all changes in this revision

Viewing changes to examples/custom_attributes/custom_management.py

  • Committer: Package Import Robot
  • Author(s): Piotr Ożarowski, Jakub Wilk, Piotr Ożarowski
  • Date: 2013-07-06 20:53:52 UTC
  • mfrom: (1.4.23) (16.1.17 experimental)
  • Revision ID: package-import@ubuntu.com-20130706205352-ryppl1eto3illd79
Tags: 0.8.2-1
[ Jakub Wilk ]
* Use canonical URIs for Vcs-* fields.

[ Piotr Ożarowski ]
* New upstream release
* Upload to unstable
* Build depend on python3-all instead of -dev, extensions are not built for
  Python 3.X 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""this example illustrates how to replace SQLAlchemy's class descriptors with
2
 
a user-defined system.
3
 
 
4
 
This sort of thing is appropriate for integration with frameworks that
5
 
redefine class behaviors in their own way, such that SQLA's default
6
 
instrumentation is not compatible.
7
 
 
8
 
The example illustrates redefinition of instrumentation at the class level as
9
 
well as the collection level, and redefines the storage of the class to store
10
 
state within "instance._goofy_dict" instead of "instance.__dict__". Note that
11
 
the default collection implementations can be used with a custom attribute
12
 
system as well.
 
1
"""Illustrates customized class instrumentation, using
 
2
the :mod:`sqlalchemy.ext.instrumentation` extension package.
 
3
 
 
4
In this example, mapped classes are modified to
 
5
store their state in a dictionary attached to an attribute
 
6
named "_goofy_dict", instead of using __dict__.
 
7
this example illustrates how to replace SQLAlchemy's class
 
8
descriptors with a user-defined system.
 
9
 
13
10
 
14
11
"""
15
12
from sqlalchemy import create_engine, MetaData, Table, Column, Integer, Text,\
16
13
    ForeignKey
17
 
from sqlalchemy.orm import mapper, relationship, Session,\
18
 
    InstrumentationManager
 
14
from sqlalchemy.orm import mapper, relationship, Session
19
15
 
20
16
from sqlalchemy.orm.attributes import set_attribute, get_attribute, \
21
17
    del_attribute
22
18
from sqlalchemy.orm.instrumentation import is_instrumented
23
 
from sqlalchemy.orm.collections import collection_adapter
24
19
 
 
20
from sqlalchemy.ext.instrumentation import InstrumentationManager
25
21
 
26
22
class MyClassState(InstrumentationManager):
27
 
    def __init__(self, cls):
28
 
        self.states = {}
29
 
 
30
 
    def instrument_attribute(self, class_, key, attr):
31
 
        pass
32
 
 
33
 
    def install_descriptor(self, class_, key, attr):
34
 
        pass
35
 
 
36
 
    def uninstall_descriptor(self, class_, key, attr):
37
 
        pass
38
 
 
39
 
    def instrument_collection_class(self, class_, key, collection_class):
40
 
        return MyCollection
41
 
 
42
23
    def get_instance_dict(self, class_, instance):
43
24
        return instance._goofy_dict
44
25
 
45
26
    def initialize_instance_dict(self, class_, instance):
46
27
        instance.__dict__['_goofy_dict'] = {}
47
28
 
48
 
    def initialize_collection(self, key, state, factory):
49
 
        data = factory()
50
 
        return MyCollectionAdapter(key, state, data), data
51
 
 
52
29
    def install_state(self, class_, instance, state):
53
 
        self.states[id(instance)] = state
 
30
        instance.__dict__['_goofy_dict']['state'] = state
54
31
 
55
32
    def state_getter(self, class_):
56
33
        def find(instance):
57
 
            return self.states[id(instance)]
 
34
            return instance.__dict__['_goofy_dict']['state']
58
35
        return find
59
36
 
60
37
class MyClass(object):
85
62
        else:
86
63
            del self._goofy_dict[key]
87
64
 
88
 
class MyCollectionAdapter(object):
89
 
    """An wholly alternative instrumentation implementation."""
90
 
 
91
 
    def __init__(self, key, state, collection):
92
 
        self.key = key
93
 
        self.state = state
94
 
        self.collection = collection
95
 
        setattr(collection, '_sa_adapter', self)
96
 
 
97
 
    def unlink(self, data):
98
 
        setattr(data, '_sa_adapter', None)
99
 
 
100
 
    def adapt_like_to_iterable(self, obj):
101
 
        return iter(obj)
102
 
 
103
 
    def append_with_event(self, item, initiator=None):
104
 
        self.collection.add(item, emit=initiator)
105
 
 
106
 
    def append_multiple_without_event(self, items):
107
 
        self.collection.members.extend(items)
108
 
 
109
 
    def append_without_event(self, item):
110
 
        self.collection.add(item, emit=False)
111
 
 
112
 
    def remove_with_event(self, item, initiator=None):
113
 
        self.collection.remove(item, emit=initiator)
114
 
 
115
 
    def remove_without_event(self, item):
116
 
        self.collection.remove(item, emit=False)
117
 
 
118
 
    def clear_with_event(self, initiator=None):
119
 
        for item in list(self):
120
 
            self.remove_with_event(item, initiator)
121
 
    def clear_without_event(self):
122
 
        for item in list(self):
123
 
            self.remove_without_event(item)
124
 
    def __iter__(self):
125
 
        return iter(self.collection)
126
 
 
127
 
    def fire_append_event(self, item, initiator=None):
128
 
        if initiator is not False and item is not None:
129
 
            self.state.get_impl(self.key).\
130
 
                        fire_append_event(self.state, self.state.dict, item,
131
 
                                                        initiator)
132
 
 
133
 
    def fire_remove_event(self, item, initiator=None):
134
 
        if initiator is not False and item is not None:
135
 
            self.state.get_impl(self.key).\
136
 
                        fire_remove_event(self.state, self.state.dict, item,
137
 
                                                        initiator)
138
 
 
139
 
    def fire_pre_remove_event(self, initiator=None):
140
 
        self.state.get_impl(self.key).\
141
 
                        fire_pre_remove_event(self.state, self.state.dict,
142
 
                                                        initiator)
143
 
 
144
 
class MyCollection(object):
145
 
    def __init__(self):
146
 
        self.members = list()
147
 
    def add(self, object, emit=None):
148
 
        self.members.append(object)
149
 
        collection_adapter(self).fire_append_event(object, emit)
150
 
    def remove(self, object, emit=None):
151
 
        collection_adapter(self).fire_pre_remove_event(object)
152
 
        self.members.remove(object)
153
 
        collection_adapter(self).fire_remove_event(object, emit)
154
 
    def __getitem__(self, index):
155
 
        return self.members[index]
156
 
    def __iter__(self):
157
 
        return iter(self.members)
158
 
    def __len__(self):
159
 
        return len(self.members)
160
65
 
161
66
if __name__ == '__main__':
162
 
    meta = MetaData(create_engine('sqlite://'))
 
67
    engine = create_engine('sqlite://')
 
68
    meta = MetaData()
163
69
 
164
70
    table1 = Table('table1', meta,
165
71
                    Column('id', Integer, primary_key=True),
168
74
                    Column('id', Integer, primary_key=True),
169
75
                    Column('name', Text),
170
76
                    Column('t1id', Integer, ForeignKey('table1.id')))
171
 
    meta.create_all()
 
77
    meta.create_all(engine)
172
78
 
173
79
    class A(MyClass):
174
80
        pass
177
83
        pass
178
84
 
179
85
    mapper(A, table1, properties={
180
 
        'bs':relationship(B)
 
86
        'bs': relationship(B)
181
87
    })
182
88
 
183
89
    mapper(B, table2)
186
92
 
187
93
    assert a1.name == 'a1'
188
94
    assert a1.bs[0].name == 'b1'
189
 
    assert isinstance(a1.bs, MyCollection)
190
95
 
191
 
    sess = Session()
 
96
    sess = Session(engine)
192
97
    sess.add(a1)
193
98
 
194
99
    sess.commit()
197
102
 
198
103
    assert a1.name == 'a1'
199
104
    assert a1.bs[0].name == 'b1'
200
 
    assert isinstance(a1.bs, MyCollection)
201
105
 
202
106
    a1.bs.remove(a1.bs[0])
203
107