~canonical-livepatch-dependencies/canonical-livepatch-service-dependencies/sqlalchemy

« back to all changes in this revision

Viewing changes to lib/sqlalchemy/event/registry.py

  • Committer: Free Ekanayaka
  • Author(s): Piotr Ożarowski
  • Date: 2016-06-05 20:53:44 UTC
  • Revision ID: free.ekanayaka@canonical.com-20160605205344-y5n5bo3sf9oc1irq
Tags: upstream-1.0.13+ds1
Import upstream version 1.0.13+ds1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# event/registry.py
 
2
# Copyright (C) 2005-2016 the SQLAlchemy authors and contributors
 
3
# <see AUTHORS file>
 
4
#
 
5
# This module is part of SQLAlchemy and is released under
 
6
# the MIT License: http://www.opensource.org/licenses/mit-license.php
 
7
 
 
8
"""Provides managed registration services on behalf of :func:`.listen`
 
9
arguments.
 
10
 
 
11
By "managed registration", we mean that event listening functions and
 
12
other objects can be added to various collections in such a way that their
 
13
membership in all those collections can be revoked at once, based on
 
14
an equivalent :class:`._EventKey`.
 
15
 
 
16
"""
 
17
 
 
18
from __future__ import absolute_import
 
19
 
 
20
import weakref
 
21
import collections
 
22
import types
 
23
from .. import exc, util
 
24
 
 
25
 
 
26
_key_to_collection = collections.defaultdict(dict)
 
27
"""
 
28
Given an original listen() argument, can locate all
 
29
listener collections and the listener fn contained
 
30
 
 
31
(target, identifier, fn) -> {
 
32
                            ref(listenercollection) -> ref(listener_fn)
 
33
                            ref(listenercollection) -> ref(listener_fn)
 
34
                            ref(listenercollection) -> ref(listener_fn)
 
35
                        }
 
36
"""
 
37
 
 
38
_collection_to_key = collections.defaultdict(dict)
 
39
"""
 
40
Given a _ListenerCollection or _ClsLevelListener, can locate
 
41
all the original listen() arguments and the listener fn contained
 
42
 
 
43
ref(listenercollection) -> {
 
44
                            ref(listener_fn) -> (target, identifier, fn),
 
45
                            ref(listener_fn) -> (target, identifier, fn),
 
46
                            ref(listener_fn) -> (target, identifier, fn),
 
47
                        }
 
48
"""
 
49
 
 
50
 
 
51
def _collection_gced(ref):
 
52
    # defaultdict, so can't get a KeyError
 
53
    if not _collection_to_key or ref not in _collection_to_key:
 
54
        return
 
55
    listener_to_key = _collection_to_key.pop(ref)
 
56
    for key in listener_to_key.values():
 
57
        if key in _key_to_collection:
 
58
            # defaultdict, so can't get a KeyError
 
59
            dispatch_reg = _key_to_collection[key]
 
60
            dispatch_reg.pop(ref)
 
61
            if not dispatch_reg:
 
62
                _key_to_collection.pop(key)
 
63
 
 
64
 
 
65
def _stored_in_collection(event_key, owner):
 
66
    key = event_key._key
 
67
 
 
68
    dispatch_reg = _key_to_collection[key]
 
69
 
 
70
    owner_ref = owner.ref
 
71
    listen_ref = weakref.ref(event_key._listen_fn)
 
72
 
 
73
    if owner_ref in dispatch_reg:
 
74
        return False
 
75
 
 
76
    dispatch_reg[owner_ref] = listen_ref
 
77
 
 
78
    listener_to_key = _collection_to_key[owner_ref]
 
79
    listener_to_key[listen_ref] = key
 
80
 
 
81
    return True
 
82
 
 
83
 
 
84
def _removed_from_collection(event_key, owner):
 
85
    key = event_key._key
 
86
 
 
87
    dispatch_reg = _key_to_collection[key]
 
88
 
 
89
    listen_ref = weakref.ref(event_key._listen_fn)
 
90
 
 
91
    owner_ref = owner.ref
 
92
    dispatch_reg.pop(owner_ref, None)
 
93
    if not dispatch_reg:
 
94
        del _key_to_collection[key]
 
95
 
 
96
    if owner_ref in _collection_to_key:
 
97
        listener_to_key = _collection_to_key[owner_ref]
 
98
        listener_to_key.pop(listen_ref)
 
99
 
 
100
 
 
101
def _stored_in_collection_multi(newowner, oldowner, elements):
 
102
    if not elements:
 
103
        return
 
104
 
 
105
    oldowner = oldowner.ref
 
106
    newowner = newowner.ref
 
107
 
 
108
    old_listener_to_key = _collection_to_key[oldowner]
 
109
    new_listener_to_key = _collection_to_key[newowner]
 
110
 
 
111
    for listen_fn in elements:
 
112
        listen_ref = weakref.ref(listen_fn)
 
113
        key = old_listener_to_key[listen_ref]
 
114
        dispatch_reg = _key_to_collection[key]
 
115
        if newowner in dispatch_reg:
 
116
            assert dispatch_reg[newowner] == listen_ref
 
117
        else:
 
118
            dispatch_reg[newowner] = listen_ref
 
119
 
 
120
        new_listener_to_key[listen_ref] = key
 
121
 
 
122
 
 
123
def _clear(owner, elements):
 
124
    if not elements:
 
125
        return
 
126
 
 
127
    owner = owner.ref
 
128
    listener_to_key = _collection_to_key[owner]
 
129
    for listen_fn in elements:
 
130
        listen_ref = weakref.ref(listen_fn)
 
131
        key = listener_to_key[listen_ref]
 
132
        dispatch_reg = _key_to_collection[key]
 
133
        dispatch_reg.pop(owner, None)
 
134
 
 
135
        if not dispatch_reg:
 
136
            del _key_to_collection[key]
 
137
 
 
138
 
 
139
class _EventKey(object):
 
140
    """Represent :func:`.listen` arguments.
 
141
    """
 
142
 
 
143
    __slots__ = (
 
144
        'target', 'identifier', 'fn', 'fn_key', 'fn_wrap', 'dispatch_target'
 
145
    )
 
146
 
 
147
    def __init__(self, target, identifier,
 
148
                 fn, dispatch_target, _fn_wrap=None):
 
149
        self.target = target
 
150
        self.identifier = identifier
 
151
        self.fn = fn
 
152
        if isinstance(fn, types.MethodType):
 
153
            self.fn_key = id(fn.__func__), id(fn.__self__)
 
154
        else:
 
155
            self.fn_key = id(fn)
 
156
        self.fn_wrap = _fn_wrap
 
157
        self.dispatch_target = dispatch_target
 
158
 
 
159
    @property
 
160
    def _key(self):
 
161
        return (id(self.target), self.identifier, self.fn_key)
 
162
 
 
163
    def with_wrapper(self, fn_wrap):
 
164
        if fn_wrap is self._listen_fn:
 
165
            return self
 
166
        else:
 
167
            return _EventKey(
 
168
                self.target,
 
169
                self.identifier,
 
170
                self.fn,
 
171
                self.dispatch_target,
 
172
                _fn_wrap=fn_wrap
 
173
            )
 
174
 
 
175
    def with_dispatch_target(self, dispatch_target):
 
176
        if dispatch_target is self.dispatch_target:
 
177
            return self
 
178
        else:
 
179
            return _EventKey(
 
180
                self.target,
 
181
                self.identifier,
 
182
                self.fn,
 
183
                dispatch_target,
 
184
                _fn_wrap=self.fn_wrap
 
185
            )
 
186
 
 
187
    def listen(self, *args, **kw):
 
188
        once = kw.pop("once", False)
 
189
        named = kw.pop("named", False)
 
190
 
 
191
        target, identifier, fn = \
 
192
            self.dispatch_target, self.identifier, self._listen_fn
 
193
 
 
194
        dispatch_collection = getattr(target.dispatch, identifier)
 
195
 
 
196
        adjusted_fn = dispatch_collection._adjust_fn_spec(fn, named)
 
197
 
 
198
        self = self.with_wrapper(adjusted_fn)
 
199
 
 
200
        if once:
 
201
            self.with_wrapper(
 
202
                util.only_once(self._listen_fn)).listen(*args, **kw)
 
203
        else:
 
204
            self.dispatch_target.dispatch._listen(self, *args, **kw)
 
205
 
 
206
    def remove(self):
 
207
        key = self._key
 
208
 
 
209
        if key not in _key_to_collection:
 
210
            raise exc.InvalidRequestError(
 
211
                "No listeners found for event %s / %r / %s " %
 
212
                (self.target, self.identifier, self.fn)
 
213
            )
 
214
        dispatch_reg = _key_to_collection.pop(key)
 
215
 
 
216
        for collection_ref, listener_ref in dispatch_reg.items():
 
217
            collection = collection_ref()
 
218
            listener_fn = listener_ref()
 
219
            if collection is not None and listener_fn is not None:
 
220
                collection.remove(self.with_wrapper(listener_fn))
 
221
 
 
222
    def contains(self):
 
223
        """Return True if this event key is registered to listen.
 
224
        """
 
225
        return self._key in _key_to_collection
 
226
 
 
227
    def base_listen(self, propagate=False, insert=False,
 
228
                    named=False):
 
229
 
 
230
        target, identifier, fn = \
 
231
            self.dispatch_target, self.identifier, self._listen_fn
 
232
 
 
233
        dispatch_collection = getattr(target.dispatch, identifier)
 
234
 
 
235
        if insert:
 
236
            dispatch_collection.\
 
237
                for_modify(target.dispatch).insert(self, propagate)
 
238
        else:
 
239
            dispatch_collection.\
 
240
                for_modify(target.dispatch).append(self, propagate)
 
241
 
 
242
    @property
 
243
    def _listen_fn(self):
 
244
        return self.fn_wrap or self.fn
 
245
 
 
246
    def append_to_list(self, owner, list_):
 
247
        if _stored_in_collection(self, owner):
 
248
            list_.append(self._listen_fn)
 
249
            return True
 
250
        else:
 
251
            return False
 
252
 
 
253
    def remove_from_list(self, owner, list_):
 
254
        _removed_from_collection(self, owner)
 
255
        list_.remove(self._listen_fn)
 
256
 
 
257
    def prepend_to_list(self, owner, list_):
 
258
        if _stored_in_collection(self, owner):
 
259
            list_.appendleft(self._listen_fn)
 
260
            return True
 
261
        else:
 
262
            return False