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/asgi.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,8 +37,8 @@ from . import util
|
|
|
46
37
|
from . import legacy
|
|
47
38
|
from . import exceptions
|
|
48
39
|
|
|
49
|
-
class ASGIApp(object):
|
|
50
40
|
|
|
41
|
+
class ASGIApp(object):
|
|
51
42
|
@classmethod
|
|
52
43
|
async def asgi_entry(cls, scope, receive, send):
|
|
53
44
|
if hasattr(cls, "_asgi") and cls._asgi:
|
|
@@ -58,24 +49,28 @@ class ASGIApp(object):
|
|
|
58
49
|
def serve_uvicorn(self, host, port, **kwargs):
|
|
59
50
|
util.ensure_pip("uvicorn")
|
|
60
51
|
import uvicorn
|
|
52
|
+
|
|
61
53
|
self.server_version = uvicorn.__version__
|
|
62
54
|
reload = kwargs.get("reload", False)
|
|
63
55
|
forwarded_allow_ips = kwargs.get("forwarded_allow_ips", None)
|
|
64
56
|
app_asgi = build_asgi_i(self)
|
|
65
57
|
config = uvicorn.Config(
|
|
66
58
|
app_asgi,
|
|
67
|
-
host
|
|
68
|
-
port
|
|
69
|
-
reload
|
|
70
|
-
forwarded_allow_ips
|
|
59
|
+
host=host,
|
|
60
|
+
port=port,
|
|
61
|
+
reload=reload,
|
|
62
|
+
forwarded_allow_ips=forwarded_allow_ips,
|
|
71
63
|
)
|
|
72
|
-
self._server = uvicorn.Server(config
|
|
64
|
+
self._server = uvicorn.Server(config=config)
|
|
73
65
|
self._server.run()
|
|
74
66
|
|
|
75
|
-
def serve_hypercorn(
|
|
67
|
+
def serve_hypercorn(
|
|
68
|
+
self, host, port, ssl=False, key_file=None, cer_file=None, **kwargs
|
|
69
|
+
):
|
|
76
70
|
util.ensure_pip("hypercorn")
|
|
77
71
|
import hypercorn.config
|
|
78
72
|
import hypercorn.asyncio
|
|
73
|
+
|
|
79
74
|
self.server_version = hypercorn.__version__
|
|
80
75
|
app_asgi = build_asgi_i(self)
|
|
81
76
|
config = hypercorn.config.Config()
|
|
@@ -89,17 +84,18 @@ class ASGIApp(object):
|
|
|
89
84
|
util.ensure_pip("daphne")
|
|
90
85
|
import daphne.server
|
|
91
86
|
import daphne.cli
|
|
87
|
+
|
|
92
88
|
self.server_version = daphne.__version__
|
|
93
89
|
app_asgi = build_asgi_i(self)
|
|
94
90
|
app_daphne = daphne.cli.ASGI3Middleware(app_asgi)
|
|
95
91
|
self._server = daphne.server.Server(
|
|
96
|
-
app_daphne,
|
|
97
|
-
endpoints = ["tcp:port=%d:interface=%s" % (port, host)]
|
|
92
|
+
app_daphne, endpoints=["tcp:port=%d:interface=%s" % (port, host)]
|
|
98
93
|
)
|
|
99
94
|
self._server.run()
|
|
100
95
|
|
|
101
|
-
async def send(self, data, content_type
|
|
102
|
-
if content_type:
|
|
96
|
+
async def send(self, data, content_type=None):
|
|
97
|
+
if content_type:
|
|
98
|
+
self.response.set_content_type(content_type)
|
|
103
99
|
return await self.response.send(data)
|
|
104
100
|
|
|
105
101
|
async def app_asgi(self, *args, **kwargs):
|
|
@@ -127,7 +123,7 @@ class ASGIApp(object):
|
|
|
127
123
|
scope_method = getattr(self, "asgi_" + scope_type, None)
|
|
128
124
|
if not scope_method:
|
|
129
125
|
raise exceptions.OperationalError(
|
|
130
|
-
message
|
|
126
|
+
message="Unexpected scope type '%s'" % scope_type
|
|
131
127
|
)
|
|
132
128
|
|
|
133
129
|
return await scope_method(scope, receive, send)
|
|
@@ -140,11 +136,11 @@ class ASGIApp(object):
|
|
|
140
136
|
|
|
141
137
|
if event["type"] == "lifespan.startup":
|
|
142
138
|
self.start()
|
|
143
|
-
await send(dict(type
|
|
139
|
+
await send(dict(type="lifespan.startup.complete"))
|
|
144
140
|
|
|
145
141
|
elif event["type"] == "lifespan.shutdown":
|
|
146
142
|
self.stop()
|
|
147
|
-
await send(dict(type
|
|
143
|
+
await send(dict(type="lifespan.shutdown.complete"))
|
|
148
144
|
running = False
|
|
149
145
|
|
|
150
146
|
async def asgi_http(self, scope, receive, send):
|
|
@@ -155,7 +151,7 @@ class ASGIApp(object):
|
|
|
155
151
|
|
|
156
152
|
# creates the context dictionary so that this new "pseudo" request
|
|
157
153
|
# can have its own context for futures placement
|
|
158
|
-
ctx = dict(start_task
|
|
154
|
+
ctx = dict(start_task=None, encoding="utf-8")
|
|
159
155
|
|
|
160
156
|
# runs the asynchronous building of the intermediate structures
|
|
161
157
|
# to get to the final WSGI compliant environment dictionary
|
|
@@ -166,14 +162,15 @@ class ASGIApp(object):
|
|
|
166
162
|
|
|
167
163
|
self.prepare()
|
|
168
164
|
try:
|
|
169
|
-
result = self.application_l(environ, start_response, ensure_gen
|
|
165
|
+
result = self.application_l(environ, start_response, ensure_gen=False)
|
|
170
166
|
self.set_request_ctx()
|
|
171
167
|
finally:
|
|
172
168
|
self.restore()
|
|
173
169
|
|
|
174
170
|
# verifies if the resulting value is an awaitable and if
|
|
175
171
|
# that's the case waits for it's "real" result value (async)
|
|
176
|
-
if inspect.isawaitable(result):
|
|
172
|
+
if inspect.isawaitable(result):
|
|
173
|
+
result = await result # @UndefinedVariable
|
|
177
174
|
|
|
178
175
|
# waits for the start (code and headers) send operation to be
|
|
179
176
|
# completed (async) so that we can proceed with body sending
|
|
@@ -182,7 +179,7 @@ class ASGIApp(object):
|
|
|
182
179
|
|
|
183
180
|
# iterates over the complete set of chunks in the response
|
|
184
181
|
# iterator to send each of them to the client side
|
|
185
|
-
for chunk in
|
|
182
|
+
for chunk in result if result else []:
|
|
186
183
|
if asyncio.iscoroutine(chunk):
|
|
187
184
|
await chunk
|
|
188
185
|
elif asyncio.isfuture(chunk):
|
|
@@ -192,37 +189,33 @@ class ASGIApp(object):
|
|
|
192
189
|
else:
|
|
193
190
|
if legacy.is_string(chunk):
|
|
194
191
|
chunk = chunk.encode(ctx["encoding"])
|
|
195
|
-
await send(
|
|
196
|
-
"type"
|
|
197
|
-
|
|
198
|
-
"more_body" : True
|
|
199
|
-
})
|
|
192
|
+
await send(
|
|
193
|
+
{"type": "http.response.body", "body": chunk, "more_body": True}
|
|
194
|
+
)
|
|
200
195
|
|
|
201
196
|
# sends the final empty chunk indicating the end
|
|
202
197
|
# of the body payload to the "owning" server
|
|
203
|
-
await send({
|
|
204
|
-
"type" : "http.response.body",
|
|
205
|
-
"body" : b""
|
|
206
|
-
})
|
|
198
|
+
await send({"type": "http.response.body", "body": b""})
|
|
207
199
|
finally:
|
|
208
|
-
if body:
|
|
200
|
+
if body:
|
|
201
|
+
body.close()
|
|
209
202
|
self.unset_request_ctx()
|
|
210
203
|
|
|
211
204
|
async def _build_start_response(self, ctx, send):
|
|
212
205
|
def start_response(status, headers):
|
|
213
|
-
if ctx["start_task"]:
|
|
206
|
+
if ctx["start_task"]:
|
|
207
|
+
return
|
|
214
208
|
code = status.split(" ", 1)[0]
|
|
215
209
|
code = int(code)
|
|
216
210
|
headers = [
|
|
217
211
|
(name.lower().encode("ascii"), value.encode("ascii"))
|
|
218
212
|
for name, value in headers
|
|
219
213
|
]
|
|
220
|
-
send_coro = send(
|
|
221
|
-
"type"
|
|
222
|
-
|
|
223
|
-
"headers" : headers
|
|
224
|
-
})
|
|
214
|
+
send_coro = send(
|
|
215
|
+
{"type": "http.response.start", "status": code, "headers": headers}
|
|
216
|
+
)
|
|
225
217
|
ctx["start_task"] = asyncio.create_task(send_coro)
|
|
218
|
+
|
|
226
219
|
return start_response
|
|
227
220
|
|
|
228
221
|
async def _build_sender(self, ctx, send, start_response):
|
|
@@ -231,20 +224,20 @@ class ASGIApp(object):
|
|
|
231
224
|
await ctx["start_task"]
|
|
232
225
|
if legacy.is_string(data):
|
|
233
226
|
data = data.encode(ctx["encoding"])
|
|
234
|
-
return await send(
|
|
235
|
-
"type"
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
})
|
|
227
|
+
return await send(
|
|
228
|
+
{"type": "http.response.body", "body": data, "more_body": True}
|
|
229
|
+
)
|
|
230
|
+
|
|
239
231
|
return sender
|
|
240
232
|
|
|
241
|
-
async def _build_body(self, receive, max_size
|
|
242
|
-
body = tempfile.SpooledTemporaryFile(max_size
|
|
233
|
+
async def _build_body(self, receive, max_size=65536):
|
|
234
|
+
body = tempfile.SpooledTemporaryFile(max_size=max_size)
|
|
243
235
|
while True:
|
|
244
236
|
message = await receive()
|
|
245
237
|
util.verify(message["type"] == "http.request")
|
|
246
238
|
body.write(message.get("body", b""))
|
|
247
|
-
if not message.get("more_body"):
|
|
239
|
+
if not message.get("more_body"):
|
|
240
|
+
break
|
|
248
241
|
body.seek(0)
|
|
249
242
|
return body
|
|
250
243
|
|
|
@@ -308,19 +301,25 @@ class ASGIApp(object):
|
|
|
308
301
|
return environ
|
|
309
302
|
|
|
310
303
|
def _ensure_start(self, ctx, start_response):
|
|
311
|
-
if ctx["start_task"]:
|
|
304
|
+
if ctx["start_task"]:
|
|
305
|
+
return
|
|
312
306
|
self.request_ctx.set_headers_b()
|
|
313
307
|
code_s = self.request_ctx.get_code_s()
|
|
314
308
|
headers = self.request_ctx.get_headers() or []
|
|
315
|
-
if self.sort_headers:
|
|
309
|
+
if self.sort_headers:
|
|
310
|
+
headers.sort()
|
|
316
311
|
start_response(code_s, headers)
|
|
317
312
|
|
|
313
|
+
|
|
318
314
|
def build_asgi(app_cls):
|
|
319
315
|
async def app_asgi(scope, receive, send):
|
|
320
316
|
return await app_cls.asgi_entry(scope, receive, send)
|
|
317
|
+
|
|
321
318
|
return app_asgi
|
|
322
319
|
|
|
320
|
+
|
|
323
321
|
def build_asgi_i(app):
|
|
324
322
|
async def app_asgi(scope, receive, send):
|
|
325
323
|
return await app.app_asgi(scope, receive, send)
|
|
324
|
+
|
|
326
325
|
return app_asgi
|
appier/async_neo.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"
|
|
@@ -42,18 +33,21 @@ import inspect
|
|
|
42
33
|
from . import legacy
|
|
43
34
|
from . import async_old
|
|
44
35
|
|
|
45
|
-
class AwaitWrapper(object):
|
|
46
36
|
|
|
37
|
+
class AwaitWrapper(object):
|
|
47
38
|
_is_generator = True
|
|
48
39
|
|
|
49
|
-
def __init__(self, generator, generate
|
|
50
|
-
if generate:
|
|
40
|
+
def __init__(self, generator, generate=False):
|
|
41
|
+
if generate:
|
|
42
|
+
generator = self.generate(generator)
|
|
51
43
|
self.generator = generator
|
|
52
44
|
self.is_generator = legacy.is_generator(generator)
|
|
53
45
|
|
|
54
46
|
def __await__(self):
|
|
55
|
-
if self.is_generator:
|
|
56
|
-
|
|
47
|
+
if self.is_generator:
|
|
48
|
+
return self._await_generator()
|
|
49
|
+
else:
|
|
50
|
+
return self._await_basic()
|
|
57
51
|
|
|
58
52
|
def __iter__(self):
|
|
59
53
|
return self
|
|
@@ -75,8 +69,8 @@ class AwaitWrapper(object):
|
|
|
75
69
|
return self.generator
|
|
76
70
|
yield
|
|
77
71
|
|
|
78
|
-
class CoroutineWrapper(object):
|
|
79
72
|
|
|
73
|
+
class CoroutineWrapper(object):
|
|
80
74
|
def __init__(self, coroutine):
|
|
81
75
|
self.coroutine = coroutine
|
|
82
76
|
self._buffer = None
|
|
@@ -85,18 +79,20 @@ class CoroutineWrapper(object):
|
|
|
85
79
|
return self
|
|
86
80
|
|
|
87
81
|
def __next__(self):
|
|
88
|
-
if self._buffer:
|
|
82
|
+
if self._buffer:
|
|
83
|
+
return self._buffer.pop(0)
|
|
89
84
|
return self.coroutine.send(None)
|
|
90
85
|
|
|
91
86
|
def next(self):
|
|
92
87
|
return self.__next__()
|
|
93
88
|
|
|
94
89
|
def restore(self, value):
|
|
95
|
-
if self._buffer == None:
|
|
90
|
+
if self._buffer == None:
|
|
91
|
+
self._buffer = []
|
|
96
92
|
self._buffer.append(value)
|
|
97
93
|
|
|
98
|
-
class AyncgenWrapper(object):
|
|
99
94
|
|
|
95
|
+
class AyncgenWrapper(object):
|
|
100
96
|
def __init__(self, async_iter):
|
|
101
97
|
self.async_iter = async_iter
|
|
102
98
|
self.current = None
|
|
@@ -106,7 +102,8 @@ class AyncgenWrapper(object):
|
|
|
106
102
|
return self
|
|
107
103
|
|
|
108
104
|
def __next__(self):
|
|
109
|
-
if self._buffer:
|
|
105
|
+
if self._buffer:
|
|
106
|
+
return self._buffer.pop(0)
|
|
110
107
|
try:
|
|
111
108
|
if self.current == None:
|
|
112
109
|
self.current = self.async_iter.asend(None)
|
|
@@ -114,23 +111,28 @@ class AyncgenWrapper(object):
|
|
|
114
111
|
return next(self.current)
|
|
115
112
|
except StopIteration as exception:
|
|
116
113
|
self.current = None
|
|
117
|
-
if not exception.args:
|
|
114
|
+
if not exception.args:
|
|
115
|
+
return None
|
|
118
116
|
return exception.args[0]
|
|
119
|
-
except StopAsyncIteration:
|
|
117
|
+
except StopAsyncIteration: # @UndefinedVariable
|
|
120
118
|
raise StopIteration()
|
|
121
119
|
|
|
122
120
|
def next(self):
|
|
123
121
|
return self.__next__()
|
|
124
122
|
|
|
125
123
|
def restore(self, value):
|
|
126
|
-
if self._buffer == None:
|
|
124
|
+
if self._buffer == None:
|
|
125
|
+
self._buffer = []
|
|
127
126
|
self._buffer.append(value)
|
|
128
127
|
|
|
128
|
+
|
|
129
129
|
def await_wrap(generator):
|
|
130
130
|
return AwaitWrapper(generator)
|
|
131
131
|
|
|
132
|
+
|
|
132
133
|
def await_yield(value):
|
|
133
|
-
return AwaitWrapper(value, generate
|
|
134
|
+
return AwaitWrapper(value, generate=True)
|
|
135
|
+
|
|
134
136
|
|
|
135
137
|
def ensure_generator(value):
|
|
136
138
|
if legacy.is_generator(value):
|
|
@@ -139,43 +141,52 @@ def ensure_generator(value):
|
|
|
139
141
|
if hasattr(value, "_generator"):
|
|
140
142
|
return True, value
|
|
141
143
|
|
|
142
|
-
if hasattr(inspect, "iscoroutine") and
|
|
143
|
-
|
|
144
|
+
if hasattr(inspect, "iscoroutine") and inspect.iscoroutine(
|
|
145
|
+
value
|
|
146
|
+
): # @UndefinedVariable
|
|
144
147
|
return True, CoroutineWrapper(value)
|
|
145
148
|
|
|
146
|
-
if hasattr(inspect, "isasyncgen") and
|
|
147
|
-
|
|
149
|
+
if hasattr(inspect, "isasyncgen") and inspect.isasyncgen(
|
|
150
|
+
value
|
|
151
|
+
): # @UndefinedVariable
|
|
148
152
|
return True, AyncgenWrapper(value)
|
|
149
153
|
|
|
150
154
|
return False, value
|
|
151
155
|
|
|
156
|
+
|
|
152
157
|
def is_coroutine(callable):
|
|
153
158
|
if hasattr(callable, "_is_coroutine"):
|
|
154
159
|
return True
|
|
155
160
|
|
|
156
|
-
if hasattr(inspect, "iscoroutinefunction") and
|
|
157
|
-
|
|
161
|
+
if hasattr(inspect, "iscoroutinefunction") and inspect.iscoroutinefunction(
|
|
162
|
+
callable
|
|
163
|
+
): # @UndefinedVariable
|
|
158
164
|
return True
|
|
159
165
|
|
|
160
166
|
return False
|
|
161
167
|
|
|
168
|
+
|
|
162
169
|
def is_coroutine_object(generator):
|
|
163
170
|
if legacy.is_generator(generator):
|
|
164
171
|
return True
|
|
165
172
|
|
|
166
|
-
if hasattr(inspect, "iscoroutine") and
|
|
167
|
-
|
|
173
|
+
if hasattr(inspect, "iscoroutine") and inspect.iscoroutine(
|
|
174
|
+
generator
|
|
175
|
+
): # @UndefinedVariable
|
|
168
176
|
return True
|
|
169
177
|
|
|
170
178
|
return False
|
|
171
179
|
|
|
180
|
+
|
|
172
181
|
def is_coroutine_native(generator):
|
|
173
|
-
if hasattr(inspect, "iscoroutine") and
|
|
174
|
-
|
|
182
|
+
if hasattr(inspect, "iscoroutine") and inspect.iscoroutine(
|
|
183
|
+
generator
|
|
184
|
+
): # @UndefinedVariable
|
|
175
185
|
return True
|
|
176
186
|
|
|
177
187
|
return False
|
|
178
188
|
|
|
189
|
+
|
|
179
190
|
def to_coroutine(callable, *args, **kwargs):
|
|
180
191
|
# sets the original reference to the future variable, this
|
|
181
192
|
# should never be the final result, otherwise error occurs
|
appier/async_old.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"
|
|
@@ -47,8 +38,8 @@ from . import exceptions
|
|
|
47
38
|
|
|
48
39
|
ASYNC_HEADER = -1
|
|
49
40
|
|
|
50
|
-
class AsyncManager(object):
|
|
51
41
|
|
|
42
|
+
class AsyncManager(object):
|
|
52
43
|
def __init__(self, owner):
|
|
53
44
|
object.__init__(self)
|
|
54
45
|
self.owner = owner
|
|
@@ -60,16 +51,18 @@ class AsyncManager(object):
|
|
|
60
51
|
pass
|
|
61
52
|
|
|
62
53
|
def restart(self):
|
|
63
|
-
if self.running:
|
|
54
|
+
if self.running:
|
|
55
|
+
self.stop()
|
|
64
56
|
self.start()
|
|
65
57
|
|
|
66
|
-
def add(self, method, args
|
|
58
|
+
def add(self, method, args=[], kwargs={}, request=None, mid=None):
|
|
67
59
|
pass
|
|
68
60
|
|
|
69
61
|
@property
|
|
70
62
|
def running(self):
|
|
71
63
|
return False
|
|
72
64
|
|
|
65
|
+
|
|
73
66
|
class SimpleManager(AsyncManager):
|
|
74
67
|
"""
|
|
75
68
|
Simple (and resource intensive) async manager that
|
|
@@ -79,20 +72,19 @@ class SimpleManager(AsyncManager):
|
|
|
79
72
|
and be avoided in production environments.
|
|
80
73
|
"""
|
|
81
74
|
|
|
82
|
-
def add(self, method, args
|
|
83
|
-
if request:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
kwargs = kwargs
|
|
89
|
-
)
|
|
75
|
+
def add(self, method, args=[], kwargs={}, request=None, mid=None):
|
|
76
|
+
if request:
|
|
77
|
+
kwargs["request"] = request
|
|
78
|
+
if mid:
|
|
79
|
+
kwargs["mid"] = mid
|
|
80
|
+
thread = threading.Thread(target=method, args=args, kwargs=kwargs)
|
|
90
81
|
thread.start()
|
|
91
82
|
|
|
92
83
|
@property
|
|
93
84
|
def running(self):
|
|
94
85
|
return True
|
|
95
86
|
|
|
87
|
+
|
|
96
88
|
class QueueManager(AsyncManager):
|
|
97
89
|
"""
|
|
98
90
|
Queue based async manager that uses a single consumer
|
|
@@ -109,10 +101,7 @@ class QueueManager(AsyncManager):
|
|
|
109
101
|
def start(self):
|
|
110
102
|
util.verify(not self._running)
|
|
111
103
|
self._running = True
|
|
112
|
-
self.thread = threading.Thread(
|
|
113
|
-
target = self.handler,
|
|
114
|
-
name = "QueueManager"
|
|
115
|
-
)
|
|
104
|
+
self.thread = threading.Thread(target=self.handler, name="QueueManager")
|
|
116
105
|
self.thread.daemon = True
|
|
117
106
|
self.condition = threading.Condition()
|
|
118
107
|
self.thread.start()
|
|
@@ -121,14 +110,18 @@ class QueueManager(AsyncManager):
|
|
|
121
110
|
util.verify(self._running)
|
|
122
111
|
self._running = False
|
|
123
112
|
self.condition.acquire()
|
|
124
|
-
try:
|
|
125
|
-
|
|
113
|
+
try:
|
|
114
|
+
self.condition.notify()
|
|
115
|
+
finally:
|
|
116
|
+
self.condition.release()
|
|
126
117
|
self.thread.join()
|
|
127
118
|
|
|
128
|
-
def add(self, method, args
|
|
119
|
+
def add(self, method, args=[], kwargs={}, request=None, mid=None):
|
|
129
120
|
util.verify(self.running)
|
|
130
|
-
if request:
|
|
131
|
-
|
|
121
|
+
if request:
|
|
122
|
+
kwargs["request"] = request
|
|
123
|
+
if mid:
|
|
124
|
+
kwargs["mid"] = mid
|
|
132
125
|
item = (method, args, kwargs)
|
|
133
126
|
self.condition.acquire()
|
|
134
127
|
try:
|
|
@@ -150,7 +143,8 @@ class QueueManager(AsyncManager):
|
|
|
150
143
|
|
|
151
144
|
# in case the thread is meant to be stopped, stops the
|
|
152
145
|
# current loop immediately
|
|
153
|
-
if not self.running:
|
|
146
|
+
if not self.running:
|
|
147
|
+
break
|
|
154
148
|
|
|
155
149
|
try:
|
|
156
150
|
# retrieves the latest item in the queue that is going
|
|
@@ -165,47 +159,60 @@ class QueueManager(AsyncManager):
|
|
|
165
159
|
# the arguments and runs the call handling a possible exception
|
|
166
160
|
# gracefully (prints exception to the logger)
|
|
167
161
|
method, args, kwargs = item
|
|
168
|
-
try:
|
|
162
|
+
try:
|
|
163
|
+
method(*args, **kwargs)
|
|
169
164
|
except Exception as exception:
|
|
170
165
|
self.owner.log_error(
|
|
171
|
-
exception,
|
|
172
|
-
message = "Problem handling async item: %s"
|
|
166
|
+
exception, message="Problem handling async item: %s"
|
|
173
167
|
)
|
|
174
168
|
|
|
175
169
|
@property
|
|
176
170
|
def running(self):
|
|
177
171
|
return self._running
|
|
178
172
|
|
|
173
|
+
|
|
179
174
|
class AwaitWrapper(object):
|
|
180
175
|
pass
|
|
181
176
|
|
|
177
|
+
|
|
182
178
|
class CoroutineWrapper(object):
|
|
183
179
|
pass
|
|
184
180
|
|
|
181
|
+
|
|
185
182
|
class AyncgenWrapper(object):
|
|
186
183
|
pass
|
|
187
184
|
|
|
185
|
+
|
|
188
186
|
def await_wrap(generator):
|
|
189
187
|
return generator
|
|
190
188
|
|
|
189
|
+
|
|
191
190
|
def await_yield(value):
|
|
192
191
|
yield value
|
|
193
192
|
|
|
193
|
+
|
|
194
194
|
def ensure_generator(value):
|
|
195
|
-
if legacy.is_generator(value):
|
|
195
|
+
if legacy.is_generator(value):
|
|
196
|
+
return True, value
|
|
196
197
|
return False, value
|
|
197
198
|
|
|
199
|
+
|
|
198
200
|
def is_coroutine(callable):
|
|
199
|
-
if hasattr(callable, "_is_coroutine"):
|
|
201
|
+
if hasattr(callable, "_is_coroutine"):
|
|
202
|
+
return True
|
|
200
203
|
return False
|
|
201
204
|
|
|
205
|
+
|
|
202
206
|
def is_coroutine_object(generator):
|
|
203
|
-
if legacy.is_generator(generator):
|
|
207
|
+
if legacy.is_generator(generator):
|
|
208
|
+
return True
|
|
204
209
|
return False
|
|
205
210
|
|
|
211
|
+
|
|
206
212
|
def is_coroutine_native(generator):
|
|
207
213
|
return False
|
|
208
214
|
|
|
215
|
+
|
|
209
216
|
def to_coroutine(callable, *args, **kwargs):
|
|
210
217
|
"""
|
|
211
218
|
Converts the provided (callback based) callable into a coroutine
|
|
@@ -235,7 +242,8 @@ def to_coroutine(callable, *args, **kwargs):
|
|
|
235
242
|
# in case the safe flag is set and the future is
|
|
236
243
|
# already done there's nothing remaining to be done
|
|
237
244
|
# returns immediately the control flow
|
|
238
|
-
if safe and future.done():
|
|
245
|
+
if safe and future.done():
|
|
246
|
+
return
|
|
239
247
|
|
|
240
248
|
# sets the final result in the associated future
|
|
241
249
|
# this should contain the contents coming from
|
|
@@ -259,29 +267,34 @@ def to_coroutine(callable, *args, **kwargs):
|
|
|
259
267
|
callable(*args, **kwargs)
|
|
260
268
|
yield future
|
|
261
269
|
|
|
270
|
+
|
|
262
271
|
def wrap_silent(function):
|
|
263
272
|
return function
|
|
264
273
|
|
|
274
|
+
|
|
265
275
|
def unavailable(*args, **kwargs):
|
|
266
|
-
raise exceptions.AppierException(
|
|
267
|
-
|
|
268
|
-
)
|
|
276
|
+
raise exceptions.AppierException(message="No support for async available")
|
|
277
|
+
|
|
269
278
|
|
|
270
279
|
def is_neo():
|
|
271
280
|
return sys.version_info[0] >= 3 and sys.version_info[1] >= 3
|
|
272
281
|
|
|
282
|
+
|
|
273
283
|
def header_a_():
|
|
274
284
|
yield ASYNC_HEADER
|
|
275
285
|
|
|
286
|
+
|
|
276
287
|
def ensure_a_(*args, **kwargs):
|
|
277
288
|
yield ensure_async(*args, **kwargs)
|
|
278
289
|
|
|
290
|
+
|
|
279
291
|
# determines the target service configuration that is
|
|
280
292
|
# going to be used, this is going to be used to create
|
|
281
293
|
# the proper adaptation for the async models
|
|
282
294
|
server = config.conf("SERVER", None)
|
|
283
295
|
if server == "netius":
|
|
284
296
|
import netius
|
|
297
|
+
|
|
285
298
|
Future = netius.Future
|
|
286
299
|
coroutine = netius.coroutine
|
|
287
300
|
wakeup = netius.wakeup
|