appier 1.31.4__py2.py3-none-any.whl → 1.32.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- appier/__init__.py +333 -52
- appier/amqp.py +29 -30
- appier/api.py +214 -212
- appier/asgi.py +54 -55
- appier/async_neo.py +46 -35
- appier/async_old.py +55 -42
- appier/asynchronous.py +7 -13
- appier/base.py +1762 -1429
- appier/bus.py +51 -52
- appier/cache.py +99 -84
- appier/common.py +9 -11
- appier/component.py +17 -19
- appier/compress.py +25 -28
- appier/config.py +96 -73
- appier/controller.py +9 -15
- appier/crypt.py +25 -21
- appier/data.py +73 -57
- appier/defines.py +191 -226
- appier/exceptions.py +103 -63
- appier/execution.py +94 -88
- appier/export.py +90 -88
- appier/extra.py +6 -13
- appier/extra_neo.py +8 -11
- appier/extra_old.py +18 -16
- appier/geo.py +57 -47
- appier/git.py +101 -90
- appier/graph.py +23 -24
- appier/http.py +520 -398
- appier/legacy.py +373 -180
- appier/log.py +90 -97
- appier/meta.py +42 -42
- appier/mock.py +32 -34
- appier/model.py +793 -681
- appier/model_a.py +208 -183
- appier/mongo.py +183 -107
- appier/observer.py +39 -31
- appier/part.py +23 -24
- appier/preferences.py +44 -47
- appier/queuing.py +78 -96
- appier/redisdb.py +40 -35
- appier/request.py +227 -175
- appier/scheduler.py +13 -18
- appier/serialize.py +37 -31
- appier/session.py +161 -147
- appier/settings.py +2 -11
- appier/smtp.py +53 -49
- appier/storage.py +39 -33
- appier/structures.py +50 -45
- appier/test/__init__.py +2 -11
- appier/test/base.py +111 -108
- appier/test/cache.py +28 -35
- appier/test/config.py +10 -19
- appier/test/crypt.py +3 -12
- appier/test/data.py +3 -12
- appier/test/exceptions.py +8 -17
- appier/test/export.py +16 -33
- appier/test/graph.py +27 -60
- appier/test/http.py +42 -54
- appier/test/legacy.py +20 -30
- appier/test/log.py +14 -35
- appier/test/mock.py +27 -123
- appier/test/model.py +79 -91
- appier/test/part.py +5 -14
- appier/test/preferences.py +5 -13
- appier/test/queuing.py +29 -37
- appier/test/request.py +61 -73
- appier/test/serialize.py +12 -23
- appier/test/session.py +10 -19
- appier/test/smtp.py +8 -14
- appier/test/structures.py +20 -24
- appier/test/typesf.py +14 -28
- appier/test/util.py +480 -438
- appier/typesf.py +251 -171
- appier/util.py +578 -407
- appier/validation.py +280 -143
- {appier-1.31.4.dist-info → appier-1.32.0.dist-info}/METADATA +6 -1
- appier-1.32.0.dist-info/RECORD +86 -0
- appier-1.31.4.dist-info/RECORD +0 -86
- {appier-1.31.4.dist-info → appier-1.32.0.dist-info}/LICENSE +0 -0
- {appier-1.31.4.dist-info → appier-1.32.0.dist-info}/WHEEL +0 -0
- {appier-1.31.4.dist-info → appier-1.32.0.dist-info}/top_level.txt +0 -0
appier/mongo.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
|
|
4
4
|
# Hive Appier Framework
|
|
5
|
-
# Copyright (c) 2008-
|
|
5
|
+
# Copyright (c) 2008-2024 Hive Solutions Lda.
|
|
6
6
|
#
|
|
7
7
|
# This file is part of Hive Appier Framework.
|
|
8
8
|
#
|
|
@@ -22,16 +22,7 @@
|
|
|
22
22
|
__author__ = "João Magalhães <joamag@hive.pt>"
|
|
23
23
|
""" The author(s) of the module """
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
""" The version of the module """
|
|
27
|
-
|
|
28
|
-
__revision__ = "$LastChangedRevision$"
|
|
29
|
-
""" The revision number of the module """
|
|
30
|
-
|
|
31
|
-
__date__ = "$LastChangedDate$"
|
|
32
|
-
""" The last change date of the module """
|
|
33
|
-
|
|
34
|
-
__copyright__ = "Copyright (c) 2008-2022 Hive Solutions Lda."
|
|
25
|
+
__copyright__ = "Copyright (c) 2008-2024 Hive Solutions Lda."
|
|
35
26
|
""" The copyright for the module """
|
|
36
27
|
|
|
37
28
|
__license__ = "Apache License, Version 2.0"
|
|
@@ -46,14 +37,20 @@ from . import config
|
|
|
46
37
|
from . import common
|
|
47
38
|
from . import exceptions
|
|
48
39
|
|
|
49
|
-
try:
|
|
50
|
-
|
|
40
|
+
try:
|
|
41
|
+
import pymongo
|
|
42
|
+
except ImportError:
|
|
43
|
+
pymongo = None
|
|
51
44
|
|
|
52
|
-
try:
|
|
53
|
-
|
|
45
|
+
try:
|
|
46
|
+
import bson.json_util
|
|
47
|
+
except ImportError:
|
|
48
|
+
bson = None
|
|
54
49
|
|
|
55
|
-
try:
|
|
56
|
-
|
|
50
|
+
try:
|
|
51
|
+
import motor.motor_asyncio
|
|
52
|
+
except ImportError:
|
|
53
|
+
motor = None
|
|
57
54
|
|
|
58
55
|
URL = "mongodb://localhost"
|
|
59
56
|
""" The default URL to be used for the connection when
|
|
@@ -67,44 +64,52 @@ connection_a = None
|
|
|
67
64
|
""" The global connection reference for the async version
|
|
68
65
|
of the Mongo client """
|
|
69
66
|
|
|
70
|
-
class Mongo(object):
|
|
71
67
|
|
|
72
|
-
|
|
68
|
+
class Mongo(object):
|
|
69
|
+
def __init__(self, url=None):
|
|
73
70
|
self.url = url
|
|
74
71
|
self._connection = None
|
|
75
72
|
self._db = None
|
|
76
73
|
|
|
77
|
-
def get_connection(self, url
|
|
78
|
-
if self._connection:
|
|
74
|
+
def get_connection(self, url=None, connect=False):
|
|
75
|
+
if self._connection:
|
|
76
|
+
return self._connection
|
|
79
77
|
url_c = config.conf("MONGOHQ_URL", None)
|
|
80
78
|
url_c = config.conf("MONGOLAB_URI", url_c)
|
|
81
79
|
url_c = config.conf("MONGO_URL", url_c)
|
|
82
80
|
url = url or self.url or url_c or URL
|
|
83
|
-
if is_new():
|
|
84
|
-
|
|
81
|
+
if is_new():
|
|
82
|
+
self._connection = _pymongo().MongoClient(url, connect=connect)
|
|
83
|
+
else:
|
|
84
|
+
self._connection = _pymongo().Connection(url)
|
|
85
85
|
return self._connection
|
|
86
86
|
|
|
87
87
|
def reset_connection(self):
|
|
88
|
-
if not self._connection:
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
if not self._connection:
|
|
89
|
+
return
|
|
90
|
+
if is_new():
|
|
91
|
+
self._connection.close()
|
|
92
|
+
else:
|
|
93
|
+
self._connection.disconnect()
|
|
91
94
|
self._connection = None
|
|
92
95
|
|
|
93
96
|
def get_db(self, name):
|
|
94
|
-
if self._db:
|
|
97
|
+
if self._db:
|
|
98
|
+
return self._db
|
|
95
99
|
connection = self.get_connection()
|
|
96
100
|
self._db = connection[name]
|
|
97
101
|
return self._db
|
|
98
102
|
|
|
99
|
-
class MongoAsync(object):
|
|
100
103
|
|
|
101
|
-
|
|
104
|
+
class MongoAsync(object):
|
|
105
|
+
def __init__(self, url=None):
|
|
102
106
|
self.url = url
|
|
103
107
|
self._connection = None
|
|
104
108
|
self._db = None
|
|
105
109
|
|
|
106
|
-
def get_connection(self, url
|
|
107
|
-
if self._connection:
|
|
110
|
+
def get_connection(self, url=None, connect=False):
|
|
111
|
+
if self._connection:
|
|
112
|
+
return self._connection
|
|
108
113
|
url_c = config.conf("MONGOHQ_URL", None)
|
|
109
114
|
url_c = config.conf("MONGOLAB_URI", url_c)
|
|
110
115
|
url_c = config.conf("MONGO_URL", url_c)
|
|
@@ -113,57 +118,76 @@ class MongoAsync(object):
|
|
|
113
118
|
return self._connection
|
|
114
119
|
|
|
115
120
|
def reset_connection(self):
|
|
116
|
-
if not self._connection:
|
|
121
|
+
if not self._connection:
|
|
122
|
+
return
|
|
117
123
|
self._connection.disconnect()
|
|
118
124
|
self._connection = None
|
|
119
125
|
|
|
120
126
|
def get_db(self, name):
|
|
121
|
-
if self._db:
|
|
127
|
+
if self._db:
|
|
128
|
+
return self._db
|
|
122
129
|
connection = self.get_connection()
|
|
123
130
|
self._db = connection[name]
|
|
124
131
|
return self._db
|
|
125
132
|
|
|
126
|
-
class MongoEncoder(json.JSONEncoder):
|
|
127
133
|
|
|
134
|
+
class MongoEncoder(json.JSONEncoder):
|
|
128
135
|
def default(self, obj, **kwargs):
|
|
129
|
-
if not bson:
|
|
130
|
-
|
|
131
|
-
if isinstance(obj,
|
|
132
|
-
|
|
136
|
+
if not bson:
|
|
137
|
+
return json.JSONEncoder.default(self, obj, **kwargs)
|
|
138
|
+
if isinstance(obj, bson.objectid.ObjectId):
|
|
139
|
+
return str(obj)
|
|
140
|
+
if isinstance(obj, legacy.BYTES):
|
|
141
|
+
return legacy.str(obj, encoding="utf-8")
|
|
142
|
+
else:
|
|
143
|
+
return json.JSONEncoder.default(self, obj, **kwargs)
|
|
144
|
+
|
|
133
145
|
|
|
134
|
-
def get_connection(url
|
|
146
|
+
def get_connection(url=URL, connect=False):
|
|
135
147
|
global connection
|
|
136
|
-
if connection:
|
|
148
|
+
if connection:
|
|
149
|
+
return connection
|
|
137
150
|
url = config.conf("MONGOHQ_URL", url)
|
|
138
151
|
url = config.conf("MONGOLAB_URI", url)
|
|
139
152
|
url = config.conf("MONGO_URL", url)
|
|
140
|
-
if is_new():
|
|
141
|
-
|
|
153
|
+
if is_new():
|
|
154
|
+
connection = _pymongo().MongoClient(url, connect=connect)
|
|
155
|
+
else:
|
|
156
|
+
connection = _pymongo().Connection(url)
|
|
142
157
|
return connection
|
|
143
158
|
|
|
144
|
-
|
|
159
|
+
|
|
160
|
+
def get_connection_a(url=URL, connect=False):
|
|
145
161
|
global connection_a
|
|
146
|
-
if connection_a:
|
|
162
|
+
if connection_a:
|
|
163
|
+
return connection_a
|
|
147
164
|
url = config.conf("MONGOHQ_URL", url)
|
|
148
165
|
url = config.conf("MONGOLAB_URI", url)
|
|
149
166
|
url = config.conf("MONGO_URL", url)
|
|
150
167
|
connection_a = _motor().AsyncIOMotorClient(url)
|
|
151
168
|
return connection_a
|
|
152
169
|
|
|
170
|
+
|
|
153
171
|
def reset_connection():
|
|
154
172
|
global connection
|
|
155
|
-
if not connection:
|
|
156
|
-
|
|
157
|
-
|
|
173
|
+
if not connection:
|
|
174
|
+
return
|
|
175
|
+
if is_new():
|
|
176
|
+
connection.close()
|
|
177
|
+
else:
|
|
178
|
+
connection.disconnect()
|
|
158
179
|
connection = None
|
|
159
180
|
|
|
181
|
+
|
|
160
182
|
def reset_connection_a():
|
|
161
183
|
global connection_a
|
|
162
|
-
if not connection_a:
|
|
184
|
+
if not connection_a:
|
|
185
|
+
return
|
|
163
186
|
connection_a.close()
|
|
164
187
|
connection_a = None
|
|
165
188
|
|
|
166
|
-
|
|
189
|
+
|
|
190
|
+
def get_db(name=None, get_connection=get_connection):
|
|
167
191
|
url = config.conf("MONGOHQ_URL", None)
|
|
168
192
|
url = config.conf("MONGOLAB_URI", url)
|
|
169
193
|
url = config.conf("MONGO_URL", url)
|
|
@@ -175,7 +199,8 @@ def get_db(name = None, get_connection = get_connection):
|
|
|
175
199
|
db = connection[name]
|
|
176
200
|
return db
|
|
177
201
|
|
|
178
|
-
|
|
202
|
+
|
|
203
|
+
def get_db_a(name=None, get_connection=get_connection):
|
|
179
204
|
url = config.conf("MONGOHQ_URL", None)
|
|
180
205
|
url = config.conf("MONGOLAB_URI", url)
|
|
181
206
|
url = config.conf("MONGO_URL", url)
|
|
@@ -187,125 +212,176 @@ def get_db_a(name = None, get_connection = get_connection):
|
|
|
187
212
|
db = connection[name]
|
|
188
213
|
return db
|
|
189
214
|
|
|
190
|
-
|
|
191
|
-
|
|
215
|
+
|
|
216
|
+
def drop_db(name=None, get_connection=get_connection):
|
|
217
|
+
db = get_db(name=name)
|
|
192
218
|
names = _list_names(db)
|
|
193
219
|
for name in names:
|
|
194
|
-
if name.startswith("system."):
|
|
220
|
+
if name.startswith("system."):
|
|
221
|
+
continue
|
|
195
222
|
db.drop_collection(name)
|
|
196
223
|
connection = get_connection()
|
|
197
224
|
connection.drop_database(db.name)
|
|
198
225
|
|
|
199
|
-
|
|
200
|
-
|
|
226
|
+
|
|
227
|
+
def drop_db_a(name=None, get_connection=get_connection):
|
|
228
|
+
db = get_db_a(name=name)
|
|
201
229
|
names = _list_names(db)
|
|
202
230
|
for name in names:
|
|
203
|
-
if name.startswith("system."):
|
|
231
|
+
if name.startswith("system."):
|
|
232
|
+
continue
|
|
204
233
|
db.drop_collection(name)
|
|
205
234
|
connection = get_connection_a()
|
|
206
235
|
connection.drop_database(db.name)
|
|
207
236
|
|
|
237
|
+
|
|
208
238
|
def object_id(value):
|
|
209
239
|
return bson.ObjectId(value)
|
|
210
240
|
|
|
241
|
+
|
|
211
242
|
def dumps(*args):
|
|
212
|
-
return json.dumps(default
|
|
243
|
+
return json.dumps(default=serialize, *args)
|
|
244
|
+
|
|
213
245
|
|
|
214
246
|
def serialize(obj):
|
|
215
|
-
if isinstance(obj, common.model().Model):
|
|
216
|
-
|
|
247
|
+
if isinstance(obj, common.model().Model):
|
|
248
|
+
return obj.model
|
|
249
|
+
if isinstance(obj, typesf.AbstractType):
|
|
250
|
+
return obj.json_v()
|
|
217
251
|
return bson.json_util.default(obj)
|
|
218
252
|
|
|
219
|
-
|
|
253
|
+
|
|
254
|
+
def directions(all=False):
|
|
220
255
|
return (
|
|
221
|
-
_pymongo().ASCENDING,
|
|
222
|
-
|
|
223
|
-
_pymongo().
|
|
224
|
-
) if all else (
|
|
225
|
-
_pymongo().ASCENDING,
|
|
226
|
-
_pymongo().DESCENDING
|
|
256
|
+
(_pymongo().ASCENDING, _pymongo().DESCENDING, _pymongo().HASHED)
|
|
257
|
+
if all
|
|
258
|
+
else (_pymongo().ASCENDING, _pymongo().DESCENDING)
|
|
227
259
|
)
|
|
228
260
|
|
|
261
|
+
|
|
229
262
|
def is_mongo(obj):
|
|
230
|
-
if bson and isinstance(obj, bson.ObjectId):
|
|
231
|
-
|
|
263
|
+
if bson and isinstance(obj, bson.ObjectId):
|
|
264
|
+
return True
|
|
265
|
+
if bson and isinstance(obj, bson.DBRef):
|
|
266
|
+
return True
|
|
232
267
|
return False
|
|
233
268
|
|
|
234
|
-
|
|
269
|
+
|
|
270
|
+
def is_new(major=3, minor=0, patch=0):
|
|
235
271
|
_major, _minor, _patch = _version_t()
|
|
236
|
-
if _major > major:
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
if
|
|
241
|
-
|
|
272
|
+
if _major > major:
|
|
273
|
+
return True
|
|
274
|
+
elif _major < major:
|
|
275
|
+
return False
|
|
276
|
+
if _minor > minor:
|
|
277
|
+
return True
|
|
278
|
+
elif _minor < minor:
|
|
279
|
+
return False
|
|
280
|
+
if _patch >= patch:
|
|
281
|
+
return True
|
|
282
|
+
else:
|
|
283
|
+
return False
|
|
284
|
+
|
|
242
285
|
|
|
243
286
|
def _list_names(db, *args, **kwargs):
|
|
244
|
-
if is_new(3, 7):
|
|
245
|
-
|
|
287
|
+
if is_new(3, 7):
|
|
288
|
+
return db.list_collection_names()
|
|
289
|
+
else:
|
|
290
|
+
return db.collection_names()
|
|
291
|
+
|
|
246
292
|
|
|
247
293
|
def _count(store, *args, **kwargs):
|
|
248
|
-
if len(args) == 0:
|
|
249
|
-
|
|
294
|
+
if len(args) == 0:
|
|
295
|
+
args = [{}]
|
|
296
|
+
if is_new(3, 7):
|
|
297
|
+
return store.count_documents(*args, **kwargs)
|
|
250
298
|
return store.count(*args, **kwargs)
|
|
251
299
|
|
|
300
|
+
|
|
252
301
|
def _count_documents(store, *args, **kwargs):
|
|
253
|
-
if len(args) == 0:
|
|
254
|
-
|
|
302
|
+
if len(args) == 0:
|
|
303
|
+
args = [{}]
|
|
304
|
+
if is_new(3, 7):
|
|
305
|
+
return store.count_documents(*args, **kwargs)
|
|
255
306
|
result = store.find(*args, **kwargs)
|
|
256
307
|
return result.count()
|
|
257
308
|
|
|
309
|
+
|
|
258
310
|
def _store_find_and_modify(store, *args, **kwargs):
|
|
259
|
-
if is_new():
|
|
260
|
-
|
|
311
|
+
if is_new():
|
|
312
|
+
return store.find_one_and_update(*args, **kwargs)
|
|
313
|
+
else:
|
|
314
|
+
return store.find_and_modify(*args, **kwargs)
|
|
315
|
+
|
|
261
316
|
|
|
262
317
|
def _store_insert(store, *args, **kwargs):
|
|
263
|
-
if is_new():
|
|
264
|
-
|
|
318
|
+
if is_new():
|
|
319
|
+
return store.insert_one(*args, **kwargs)
|
|
320
|
+
else:
|
|
321
|
+
return store.insert(*args, **kwargs)
|
|
322
|
+
|
|
265
323
|
|
|
266
324
|
def _store_update(store, *args, **kwargs):
|
|
267
|
-
if is_new():
|
|
268
|
-
|
|
325
|
+
if is_new():
|
|
326
|
+
return store.update_one(*args, **kwargs)
|
|
327
|
+
else:
|
|
328
|
+
return store.update(*args, **kwargs)
|
|
329
|
+
|
|
269
330
|
|
|
270
331
|
def _store_remove(store, *args, **kwargs):
|
|
271
|
-
if is_new():
|
|
272
|
-
|
|
332
|
+
if is_new():
|
|
333
|
+
return store.delete_many(*args, **kwargs)
|
|
334
|
+
else:
|
|
335
|
+
return store.remove(*args, **kwargs)
|
|
336
|
+
|
|
273
337
|
|
|
274
338
|
def _store_ensure_index(store, *args, **kwargs):
|
|
275
339
|
kwargs["background"] = kwargs.get("background", True)
|
|
276
|
-
if is_new():
|
|
277
|
-
|
|
340
|
+
if is_new():
|
|
341
|
+
return store.create_index(*args, **kwargs)
|
|
342
|
+
else:
|
|
343
|
+
return store.ensure_index(*args, **kwargs)
|
|
344
|
+
|
|
278
345
|
|
|
279
346
|
def _store_ensure_index_many(store, *args, **kwargs):
|
|
280
347
|
directions_l = kwargs.pop("directions", None)
|
|
281
|
-
if directions_l == "all":
|
|
282
|
-
|
|
348
|
+
if directions_l == "all":
|
|
349
|
+
directions_l = directions(all=True)
|
|
350
|
+
elif directions_l == None:
|
|
351
|
+
directions_l = directions()
|
|
283
352
|
for direction in directions_l:
|
|
284
353
|
_args = list(args)
|
|
285
354
|
_args[0] = [(_args[0], direction)]
|
|
286
355
|
_store_ensure_index(store, *_args, **kwargs)
|
|
287
356
|
|
|
357
|
+
|
|
288
358
|
def _version_t():
|
|
289
359
|
pymongo_l = _pymongo()
|
|
290
|
-
if hasattr(pymongo_l, "_version_t"):
|
|
360
|
+
if hasattr(pymongo_l, "_version_t"):
|
|
361
|
+
return pymongo_l._version_t
|
|
291
362
|
version_l = pymongo.version.split(".", 2)
|
|
292
|
-
if len(version_l) == 2:
|
|
363
|
+
if len(version_l) == 2:
|
|
364
|
+
version_l.append("0")
|
|
293
365
|
major_s, minor_s, patch_s = version_l
|
|
294
366
|
pymongo_l._version_t = (int(major_s), int(minor_s), int(patch_s))
|
|
295
367
|
return pymongo_l._version_t
|
|
296
368
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
369
|
+
|
|
370
|
+
def _pymongo(verify=True):
|
|
371
|
+
if verify:
|
|
372
|
+
util.verify(
|
|
373
|
+
not pymongo == None,
|
|
374
|
+
message="PyMongo library not available",
|
|
375
|
+
exception=exceptions.OperationalError,
|
|
376
|
+
)
|
|
303
377
|
return pymongo
|
|
304
378
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
379
|
+
|
|
380
|
+
def _motor(verify=True):
|
|
381
|
+
if verify:
|
|
382
|
+
util.verify(
|
|
383
|
+
not motor == None,
|
|
384
|
+
message="Motor library not available",
|
|
385
|
+
exception=exceptions.OperationalError,
|
|
386
|
+
)
|
|
311
387
|
return motor.motor_asyncio
|
appier/observer.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
|
|
4
4
|
# Hive Appier Framework
|
|
5
|
-
# Copyright (c) 2008-
|
|
5
|
+
# Copyright (c) 2008-2024 Hive Solutions Lda.
|
|
6
6
|
#
|
|
7
7
|
# This file is part of Hive Appier Framework.
|
|
8
8
|
#
|
|
@@ -22,16 +22,7 @@
|
|
|
22
22
|
__author__ = "João Magalhães <joamag@hive.pt>"
|
|
23
23
|
""" The author(s) of the module """
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
""" The version of the module """
|
|
27
|
-
|
|
28
|
-
__revision__ = "$LastChangedRevision$"
|
|
29
|
-
""" The revision number of the module """
|
|
30
|
-
|
|
31
|
-
__date__ = "$LastChangedDate$"
|
|
32
|
-
""" The last change date of the module """
|
|
33
|
-
|
|
34
|
-
__copyright__ = "Copyright (c) 2008-2022 Hive Solutions Lda."
|
|
25
|
+
__copyright__ = "Copyright (c) 2008-2024 Hive Solutions Lda."
|
|
35
26
|
""" The copyright for the module """
|
|
36
27
|
|
|
37
28
|
__license__ = "Apache License, Version 2.0"
|
|
@@ -39,6 +30,7 @@ __license__ = "Apache License, Version 2.0"
|
|
|
39
30
|
|
|
40
31
|
from . import util
|
|
41
32
|
|
|
33
|
+
|
|
42
34
|
class Observable(object):
|
|
43
35
|
"""
|
|
44
36
|
The base class that implements the observable
|
|
@@ -68,19 +60,22 @@ class Observable(object):
|
|
|
68
60
|
return name_f
|
|
69
61
|
|
|
70
62
|
@classmethod
|
|
71
|
-
def bind_g(cls, name, method, oneshot
|
|
72
|
-
if oneshot:
|
|
63
|
+
def bind_g(cls, name, method, oneshot=False):
|
|
64
|
+
if oneshot:
|
|
65
|
+
method.oneshot = oneshot
|
|
73
66
|
name_f = cls.name_f(name)
|
|
74
67
|
methods = cls._events_g.get(name_f, [])
|
|
75
68
|
methods.append(method)
|
|
76
69
|
cls._events_g[name_f] = methods
|
|
77
70
|
|
|
78
71
|
@classmethod
|
|
79
|
-
def unbind_g(cls, name, method
|
|
72
|
+
def unbind_g(cls, name, method=None):
|
|
80
73
|
name_f = cls.name_f(name)
|
|
81
74
|
methods = cls._events_g.get(name_f, [])
|
|
82
|
-
if method:
|
|
83
|
-
|
|
75
|
+
if method:
|
|
76
|
+
methods.remove(method)
|
|
77
|
+
else:
|
|
78
|
+
del methods[:]
|
|
84
79
|
|
|
85
80
|
@classmethod
|
|
86
81
|
def trigger_g(cls, name, *args, **kwargs):
|
|
@@ -89,12 +84,16 @@ class Observable(object):
|
|
|
89
84
|
methods = cls._events_g.get(name_f, [])
|
|
90
85
|
for method in methods:
|
|
91
86
|
method(*args, **kwargs)
|
|
92
|
-
if not hasattr(method, "oneshot"):
|
|
93
|
-
|
|
87
|
+
if not hasattr(method, "oneshot"):
|
|
88
|
+
continue
|
|
89
|
+
if not method.oneshot:
|
|
90
|
+
continue
|
|
94
91
|
oneshots = [] if oneshots == None else oneshots
|
|
95
92
|
oneshots.append(method)
|
|
96
|
-
if not oneshots:
|
|
97
|
-
|
|
93
|
+
if not oneshots:
|
|
94
|
+
return
|
|
95
|
+
for oneshot in oneshots:
|
|
96
|
+
cls.unbind_g(name, oneshot)
|
|
98
97
|
|
|
99
98
|
def build(self):
|
|
100
99
|
pass
|
|
@@ -102,20 +101,25 @@ class Observable(object):
|
|
|
102
101
|
def destroy(self):
|
|
103
102
|
self.unbind_all()
|
|
104
103
|
|
|
105
|
-
def bind(self, name, method, oneshot
|
|
106
|
-
if oneshot:
|
|
104
|
+
def bind(self, name, method, oneshot=False):
|
|
105
|
+
if oneshot:
|
|
106
|
+
method.oneshot = oneshot
|
|
107
107
|
methods = self._events.get(name, [])
|
|
108
108
|
methods.append(method)
|
|
109
109
|
self._events[name] = methods
|
|
110
110
|
|
|
111
|
-
def unbind(self, name, method
|
|
111
|
+
def unbind(self, name, method=None):
|
|
112
112
|
methods = self._events.get(name, [])
|
|
113
|
-
if method:
|
|
114
|
-
|
|
113
|
+
if method:
|
|
114
|
+
methods.remove(method)
|
|
115
|
+
else:
|
|
116
|
+
del methods[:]
|
|
115
117
|
|
|
116
118
|
def unbind_all(self):
|
|
117
|
-
if not hasattr(self, "_events"):
|
|
118
|
-
|
|
119
|
+
if not hasattr(self, "_events"):
|
|
120
|
+
return
|
|
121
|
+
for methods in self._events.values():
|
|
122
|
+
del methods[:]
|
|
119
123
|
self._events.clear()
|
|
120
124
|
|
|
121
125
|
def trigger(self, name, *args, **kwargs):
|
|
@@ -127,10 +131,14 @@ class Observable(object):
|
|
|
127
131
|
methods = self._events.get(name, [])
|
|
128
132
|
for method in methods:
|
|
129
133
|
method(*args, **kwargs)
|
|
130
|
-
if not hasattr(method, "oneshot"):
|
|
131
|
-
|
|
134
|
+
if not hasattr(method, "oneshot"):
|
|
135
|
+
continue
|
|
136
|
+
if not method.oneshot:
|
|
137
|
+
continue
|
|
132
138
|
oneshots = [] if oneshots == None else oneshots
|
|
133
139
|
oneshots.append(method)
|
|
134
140
|
level.trigger_g(name, self, *args, **kwargs)
|
|
135
|
-
if not oneshots:
|
|
136
|
-
|
|
141
|
+
if not oneshots:
|
|
142
|
+
return
|
|
143
|
+
for oneshot in oneshots:
|
|
144
|
+
self.unbind(name, oneshot)
|