@vercel/python 3.1.0 → 3.1.3
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.
- package/package.json +3 -3
- package/vc_init.py +7 -171
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vercel/python",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.3",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/execa": "^0.9.0",
|
|
25
25
|
"@types/jest": "27.4.1",
|
|
26
|
-
"@vercel/build-utils": "5.0.
|
|
26
|
+
"@vercel/build-utils": "5.0.7",
|
|
27
27
|
"@vercel/ncc": "0.24.0",
|
|
28
28
|
"execa": "^1.0.0",
|
|
29
29
|
"typescript": "4.3.4"
|
|
30
30
|
},
|
|
31
|
-
"gitHead": "
|
|
31
|
+
"gitHead": "e8c7db59cf2746422f1f7e14cc6b7f901c243d50"
|
|
32
32
|
}
|
package/vc_init.py
CHANGED
|
@@ -167,23 +167,13 @@ elif 'app' in __vc_variables:
|
|
|
167
167
|
else:
|
|
168
168
|
print('using Asynchronous Server Gateway Interface (ASGI)')
|
|
169
169
|
# Originally authored by Jordan Eremieff and included under MIT license:
|
|
170
|
-
# https://github.com/erm/mangum/blob/
|
|
171
|
-
# https://github.com/erm/mangum/blob/
|
|
170
|
+
# https://github.com/erm/mangum/blob/b4d21c8f5e304a3e17b88bc9fa345106acc50ad7/mangum/__init__.py
|
|
171
|
+
# https://github.com/erm/mangum/blob/b4d21c8f5e304a3e17b88bc9fa345106acc50ad7/LICENSE
|
|
172
172
|
import asyncio
|
|
173
173
|
import enum
|
|
174
|
-
import logging
|
|
175
|
-
from contextlib import ExitStack
|
|
176
174
|
from urllib.parse import urlparse
|
|
177
175
|
from werkzeug.datastructures import Headers
|
|
178
176
|
|
|
179
|
-
def get_event_loop():
|
|
180
|
-
try:
|
|
181
|
-
return asyncio.get_running_loop()
|
|
182
|
-
except:
|
|
183
|
-
if sys.version_info < (3, 10):
|
|
184
|
-
return asyncio.get_event_loop()
|
|
185
|
-
else:
|
|
186
|
-
return asyncio.get_event_loop_policy().get_event_loop()
|
|
187
177
|
|
|
188
178
|
class ASGICycleState(enum.Enum):
|
|
189
179
|
REQUEST = enum.auto()
|
|
@@ -204,8 +194,8 @@ elif 'app' in __vc_variables:
|
|
|
204
194
|
ASGI instance using the connection scope.
|
|
205
195
|
Runs until the response is completely read from the application.
|
|
206
196
|
"""
|
|
207
|
-
loop =
|
|
208
|
-
self.app_queue = asyncio.Queue()
|
|
197
|
+
loop = asyncio.new_event_loop()
|
|
198
|
+
self.app_queue = asyncio.Queue(loop=loop)
|
|
209
199
|
self.put_message({'type': 'http.request', 'body': body, 'more_body': False})
|
|
210
200
|
|
|
211
201
|
asgi_instance = app(self.scope, self.receive, self.send)
|
|
@@ -267,156 +257,6 @@ elif 'app' in __vc_variables:
|
|
|
267
257
|
self.response['body'] = base64.b64encode(self.body).decode('utf-8')
|
|
268
258
|
self.response['encoding'] = 'base64'
|
|
269
259
|
|
|
270
|
-
class LifespanFailure(Exception):
|
|
271
|
-
"""Raise when a lifespan failure event is sent by an application."""
|
|
272
|
-
|
|
273
|
-
class LifespanUnsupported(Exception):
|
|
274
|
-
"""Raise when lifespan events are not supported by an application."""
|
|
275
|
-
|
|
276
|
-
class UnexpectedMessage(Exception):
|
|
277
|
-
"""Raise when an unexpected message type is received during an ASGI cycle."""
|
|
278
|
-
|
|
279
|
-
class LifespanCycleState(enum.Enum):
|
|
280
|
-
"""
|
|
281
|
-
The state of the ASGI `lifespan` connection.
|
|
282
|
-
* **CONNECTING** - Initial state. The ASGI application instance will be run with
|
|
283
|
-
the connection scope containing the `lifespan` type.
|
|
284
|
-
* **STARTUP** - The lifespan startup event has been pushed to the queue to be
|
|
285
|
-
received by the application.
|
|
286
|
-
* **SHUTDOWN** - The lifespan shutdown event has been pushed to the queue to be
|
|
287
|
-
received by the application.
|
|
288
|
-
* **FAILED** - A lifespan failure has been detected, and the connection will be
|
|
289
|
-
closed with an error.
|
|
290
|
-
* **UNSUPPORTED** - An application attempted to send a message before receiving
|
|
291
|
-
the lifepan startup event. If the lifespan argument is "on", then the connection
|
|
292
|
-
will be closed with an error.
|
|
293
|
-
"""
|
|
294
|
-
|
|
295
|
-
CONNECTING = enum.auto()
|
|
296
|
-
STARTUP = enum.auto()
|
|
297
|
-
SHUTDOWN = enum.auto()
|
|
298
|
-
FAILED = enum.auto()
|
|
299
|
-
UNSUPPORTED = enum.auto()
|
|
300
|
-
|
|
301
|
-
class Lifespan:
|
|
302
|
-
|
|
303
|
-
def __init__(self, app):
|
|
304
|
-
self.app = app
|
|
305
|
-
self.state = LifespanCycleState.CONNECTING
|
|
306
|
-
self.exception = None
|
|
307
|
-
self.logger = logging.getLogger('lifespan')
|
|
308
|
-
self.loop = get_event_loop()
|
|
309
|
-
self.app_queue = asyncio.Queue()
|
|
310
|
-
self.startup_event = asyncio.Event()
|
|
311
|
-
self.shutdown_event = asyncio.Event()
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
def __enter__(self) -> None:
|
|
315
|
-
"""Runs the event loop for application startup."""
|
|
316
|
-
self.loop.create_task(self.run())
|
|
317
|
-
self.loop.run_until_complete(self.startup())
|
|
318
|
-
|
|
319
|
-
def __exit__(
|
|
320
|
-
self,
|
|
321
|
-
exc_type,
|
|
322
|
-
exc_value,
|
|
323
|
-
traceback,
|
|
324
|
-
) -> None:
|
|
325
|
-
"""Runs the event loop for application shutdown."""
|
|
326
|
-
self.loop.run_until_complete(self.shutdown())
|
|
327
|
-
|
|
328
|
-
async def run(self):
|
|
329
|
-
"""Calls the application with the `lifespan` connection scope."""
|
|
330
|
-
try:
|
|
331
|
-
await self.app(
|
|
332
|
-
{"type": "lifespan", "asgi": {"spec_version": "2.0", "version": "3.0"}},
|
|
333
|
-
self.receive,
|
|
334
|
-
self.send,
|
|
335
|
-
)
|
|
336
|
-
except LifespanUnsupported:
|
|
337
|
-
self.logger.info("ASGI 'lifespan' protocol appears unsupported.")
|
|
338
|
-
except (LifespanFailure, UnexpectedMessage) as exc:
|
|
339
|
-
self.exception = exc
|
|
340
|
-
except BaseException as exc:
|
|
341
|
-
self.logger.error("Exception in 'lifespan' protocol.", exc_info=exc)
|
|
342
|
-
finally:
|
|
343
|
-
self.startup_event.set()
|
|
344
|
-
self.shutdown_event.set()
|
|
345
|
-
|
|
346
|
-
async def send(self, message):
|
|
347
|
-
"""Awaited by the application to send ASGI `lifespan` events."""
|
|
348
|
-
message_type = message["type"]
|
|
349
|
-
|
|
350
|
-
if self.state is LifespanCycleState.CONNECTING:
|
|
351
|
-
# If a message is sent before the startup event is received by the
|
|
352
|
-
# application, then assume that lifespan is unsupported.
|
|
353
|
-
self.state = LifespanCycleState.UNSUPPORTED
|
|
354
|
-
raise LifespanUnsupported("Lifespan protocol appears unsupported.")
|
|
355
|
-
|
|
356
|
-
if message_type not in (
|
|
357
|
-
"lifespan.startup.complete",
|
|
358
|
-
"lifespan.shutdown.complete",
|
|
359
|
-
"lifespan.startup.failed",
|
|
360
|
-
"lifespan.shutdown.failed",
|
|
361
|
-
):
|
|
362
|
-
self.state = LifespanCycleState.FAILED
|
|
363
|
-
raise UnexpectedMessage(f"Unexpected '{message_type}' event received.")
|
|
364
|
-
|
|
365
|
-
if self.state is LifespanCycleState.STARTUP:
|
|
366
|
-
if message_type == "lifespan.startup.complete":
|
|
367
|
-
self.startup_event.set()
|
|
368
|
-
elif message_type == "lifespan.startup.failed":
|
|
369
|
-
self.state = LifespanCycleState.FAILED
|
|
370
|
-
self.startup_event.set()
|
|
371
|
-
message_value = message.get("message", "")
|
|
372
|
-
raise LifespanFailure(f"Lifespan startup failure. {message_value}")
|
|
373
|
-
|
|
374
|
-
elif self.state is LifespanCycleState.SHUTDOWN:
|
|
375
|
-
if message_type == "lifespan.shutdown.complete":
|
|
376
|
-
self.shutdown_event.set()
|
|
377
|
-
elif message_type == "lifespan.shutdown.failed":
|
|
378
|
-
self.state = LifespanCycleState.FAILED
|
|
379
|
-
self.shutdown_event.set()
|
|
380
|
-
message_value = message.get("message", "")
|
|
381
|
-
raise LifespanFailure(f"Lifespan shutdown failure. {message_value}")
|
|
382
|
-
|
|
383
|
-
async def receive(self):
|
|
384
|
-
"""Awaited by the application to receive ASGI `lifespan` events."""
|
|
385
|
-
if self.state is LifespanCycleState.CONNECTING:
|
|
386
|
-
|
|
387
|
-
# Connection established. The next event returned by the queue will be
|
|
388
|
-
# `lifespan.startup` to inform the application that the connection is
|
|
389
|
-
# ready to receive lfiespan messages.
|
|
390
|
-
self.state = LifespanCycleState.STARTUP
|
|
391
|
-
|
|
392
|
-
elif self.state is LifespanCycleState.STARTUP:
|
|
393
|
-
|
|
394
|
-
# Connection shutting down. The next event returned by the queue will be
|
|
395
|
-
# `lifespan.shutdown` to inform the application that the connection is now
|
|
396
|
-
# closing so that it may perform cleanup.
|
|
397
|
-
self.state = LifespanCycleState.SHUTDOWN
|
|
398
|
-
|
|
399
|
-
return await self.app_queue.get()
|
|
400
|
-
|
|
401
|
-
async def startup(self) -> None:
|
|
402
|
-
"""Pushes the `lifespan` startup event to the queue and handles errors."""
|
|
403
|
-
await self.app_queue.put({"type": "lifespan.startup"})
|
|
404
|
-
await self.startup_event.wait()
|
|
405
|
-
if self.state is LifespanCycleState.FAILED:
|
|
406
|
-
raise LifespanFailure(self.exception)
|
|
407
|
-
|
|
408
|
-
if not self.exception:
|
|
409
|
-
self.logger.info("Application startup complete.")
|
|
410
|
-
else:
|
|
411
|
-
self.logger.info("Application startup failed.")
|
|
412
|
-
|
|
413
|
-
async def shutdown(self) -> None:
|
|
414
|
-
"""Pushes the `lifespan` shutdown event to the queue and handles errors."""
|
|
415
|
-
await self.app_queue.put({"type": "lifespan.shutdown"})
|
|
416
|
-
await self.shutdown_event.wait()
|
|
417
|
-
if self.state is LifespanCycleState.FAILED:
|
|
418
|
-
raise LifespanFailure(self.exception)
|
|
419
|
-
|
|
420
260
|
def vc_handler(event, context):
|
|
421
261
|
payload = json.loads(event['body'])
|
|
422
262
|
|
|
@@ -449,13 +289,9 @@ elif 'app' in __vc_variables:
|
|
|
449
289
|
'raw_path': path.encode(),
|
|
450
290
|
}
|
|
451
291
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
asgi_cycle = ASGICycle(scope)
|
|
457
|
-
response = asgi_cycle(__vc_module.app, body)
|
|
458
|
-
return response
|
|
292
|
+
asgi_cycle = ASGICycle(scope)
|
|
293
|
+
response = asgi_cycle(__vc_module.app, body)
|
|
294
|
+
return response
|
|
459
295
|
|
|
460
296
|
else:
|
|
461
297
|
print('Missing variable `handler` or `app` in file "__VC_HANDLER_ENTRYPOINT".')
|