@vercel/python 6.18.1 → 6.19.0

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.
Files changed (2) hide show
  1. package/package.json +3 -3
  2. package/vc_init_dev.py +182 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/python",
3
- "version": "6.18.1",
3
+ "version": "6.19.0",
4
4
  "main": "./dist/index.js",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
@@ -35,9 +35,9 @@
35
35
  "which": "3.0.0",
36
36
  "get-port": "5.1.1",
37
37
  "is-port-reachable": "3.1.0",
38
- "@vercel/python-runtime": "0.5.3",
38
+ "@vercel/build-utils": "13.6.1",
39
39
  "@vercel/error-utils": "2.0.3",
40
- "@vercel/build-utils": "13.6.1"
40
+ "@vercel/python-runtime": "0.5.3"
41
41
  },
42
42
  "scripts": {
43
43
  "build": "node ../../utils/build-builder.mjs",
package/vc_init_dev.py CHANGED
@@ -4,6 +4,8 @@
4
4
  import sys
5
5
  import os
6
6
  import inspect
7
+ import logging
8
+ import logging.config
7
9
  from os import path as _p
8
10
  from importlib import util as _importlib_util
9
11
  import mimetypes
@@ -23,6 +25,175 @@ def _color(text: str, code: str) -> str:
23
25
  return f"{code}{text}{_RESET}"
24
26
 
25
27
 
28
+ # Configure logging to output DEBUG-WARNING to the stdout
29
+ # and ERROR-CRITICAL to the stderr.
30
+
31
+
32
+ # We need a custom filter for the stdout stream
33
+ # so it won't print anything higher than WARNING.
34
+ class _MaxLevelFilter(logging.Filter):
35
+ def __init__(self, max_level):
36
+ super().__init__()
37
+ self.max_level = max_level
38
+
39
+ def filter(self, record):
40
+ return record.levelno <= self.max_level
41
+
42
+
43
+ def _build_log_config(loggers, _filter_ref=None) -> dict:
44
+ if _filter_ref is None:
45
+ _filter_ref = "vc_init_dev._MaxLevelFilter"
46
+
47
+ return {
48
+ "version": 1,
49
+ "disable_existing_loggers": False,
50
+ "filters": {
51
+ "max_warning": {
52
+ "()": _filter_ref,
53
+ "max_level": logging.WARNING,
54
+ }
55
+ },
56
+ "handlers": {
57
+ "stdout": {
58
+ "class": "logging.StreamHandler",
59
+ "stream": "ext://sys.stdout",
60
+ "filters": ["max_warning"],
61
+ },
62
+ "stderr": {
63
+ "class": "logging.StreamHandler",
64
+ "stream": "ext://sys.stderr",
65
+ "level": "ERROR",
66
+ },
67
+ },
68
+ "loggers": loggers,
69
+ "root": {
70
+ "handlers": ["stdout", "stderr"],
71
+ "level": "INFO",
72
+ },
73
+ }
74
+
75
+
76
+ def _setup_server_log_routing(logger_name=None):
77
+ loggers = {}
78
+
79
+ if logger_name:
80
+ loggers[logger_name] = {
81
+ "handlers": ["stdout", "stderr"],
82
+ "level": "INFO",
83
+ "propagate": False,
84
+ }
85
+
86
+ logging.config.dictConfig(
87
+ _build_log_config(
88
+ loggers=loggers,
89
+ _filter_ref=_MaxLevelFilter,
90
+ ),
91
+ )
92
+
93
+
94
+ def _build_uvicorn_log_config(default_fmt=None, access_fmt=None) -> dict:
95
+ try:
96
+ from uvicorn.config import LOGGING_CONFIG # type: ignore
97
+
98
+ uvicorn_fmts = LOGGING_CONFIG["formatters"]
99
+ except ImportError:
100
+ uvicorn_fmts = {
101
+ "default": {
102
+ "()": "uvicorn.logging.DefaultFormatter",
103
+ "fmt": "%(levelprefix)s %(message)s",
104
+ "use_colors": None,
105
+ },
106
+ "access": {
107
+ "()": "uvicorn.logging.AccessFormatter",
108
+ "fmt": '%(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s',
109
+ },
110
+ }
111
+
112
+ cfg = _build_log_config(
113
+ loggers={
114
+ "uvicorn": {
115
+ "handlers": ["stdout", "stderr"],
116
+ "level": "INFO",
117
+ "propagate": False,
118
+ },
119
+ "uvicorn.error": {"level": "INFO"},
120
+ "uvicorn.access": {
121
+ "handlers": ["access"],
122
+ "level": "INFO",
123
+ "propagate": False,
124
+ },
125
+ },
126
+ )
127
+
128
+ if default_fmt is None:
129
+ default_fmt = {**uvicorn_fmts["default"], "use_colors": not _NO_COLOR}
130
+
131
+ if access_fmt is None:
132
+ access_fmt = {**uvicorn_fmts["access"], "use_colors": not _NO_COLOR}
133
+
134
+ cfg["formatters"] = {"default": default_fmt, "access": access_fmt}
135
+ cfg["handlers"]["stdout"]["formatter"] = "default"
136
+ cfg["handlers"]["stderr"]["formatter"] = "default"
137
+ cfg["handlers"]["access"] = {
138
+ "class": "logging.StreamHandler",
139
+ "stream": "ext://sys.stdout",
140
+ "formatter": "access",
141
+ }
142
+
143
+ return cfg
144
+
145
+
146
+ def _build_hypercorn_log_config():
147
+ return _build_log_config(
148
+ loggers={
149
+ "hypercorn.error": {
150
+ "handlers": ["stdout", "stderr"],
151
+ "level": "INFO",
152
+ "propagate": False,
153
+ },
154
+ "hypercorn.access": {
155
+ "handlers": ["stdout"],
156
+ "level": "INFO",
157
+ "propagate": False,
158
+ },
159
+ },
160
+ )
161
+
162
+
163
+ def _patch_fastapi_cli_log_config():
164
+ try:
165
+ import fastapi_cli.utils.cli as _fcli # type: ignore
166
+ import fastapi_cli.cli as _fcli_cli # type: ignore
167
+
168
+ _orig_get_config = _fcli.get_uvicorn_log_config # to ensure it's there
169
+ _fcli_cli.get_uvicorn_log_config # to ensure it's there
170
+ except (ImportError, AttributeError):
171
+ return
172
+
173
+ def _get_routed_config():
174
+ orig = _orig_get_config()
175
+ return _build_uvicorn_log_config(
176
+ default_fmt={
177
+ "()": "fastapi_cli.utils.cli.CustomFormatter",
178
+ "fmt": orig["formatters"]["default"].get(
179
+ "fmt", "%(levelprefix)s %(message)s"
180
+ ),
181
+ "use_colors": orig["formatters"]["default"].get("use_colors"),
182
+ },
183
+ access_fmt={
184
+ "()": "fastapi_cli.utils.cli.CustomFormatter",
185
+ "fmt": orig["formatters"]["access"].get(
186
+ "fmt",
187
+ "%(levelprefix)s %(client_addr)s - '%(request_line)s' %(status_code)s",
188
+ ),
189
+ },
190
+ )
191
+
192
+ _fcli.get_uvicorn_log_config = _get_routed_config
193
+ # we need to patch the local binding as well
194
+ _fcli_cli.get_uvicorn_log_config = _get_routed_config
195
+
196
+
26
197
  def _normalize_service_route_prefix(raw_prefix):
27
198
  if not raw_prefix:
28
199
  return ""
@@ -71,6 +242,11 @@ def _strip_service_route_prefix(path_value):
71
242
  return path_value, ""
72
243
 
73
244
 
245
+ # Pre-configure the root logger before user module import so that any log
246
+ # calls emitted at import time are routed to stdout/stderr correctly.
247
+ _setup_server_log_routing()
248
+
249
+
74
250
  # ASGI/WSGI app detection
75
251
  _MODULE_NAME = "__VC_DEV_MODULE_NAME__"
76
252
  _ENTRY_ABS = "__VC_DEV_ENTRY_ABS__"
@@ -355,7 +531,8 @@ if __name__ == "__main__":
355
531
  try:
356
532
  from werkzeug.serving import run_simple # type: ignore
357
533
 
358
- run_simple(host, port, wsgi_app, use_reloader=True)
534
+ _setup_server_log_routing("werkzeug")
535
+ run_simple(host, port, wsgi_app, use_reloader=True, threaded=True)
359
536
  except Exception:
360
537
  print(
361
538
  _color(
@@ -376,6 +553,7 @@ if __name__ == "__main__":
376
553
  fastapi_dev = None
377
554
 
378
555
  if fastapi_dev is not None:
556
+ _patch_fastapi_cli_log_config()
379
557
  fastapi_dev(
380
558
  entrypoint="vc_init_dev:asgi_app", host=host, port=port, reload=True
381
559
  )
@@ -390,6 +568,7 @@ if __name__ == "__main__":
390
568
  port=port,
391
569
  use_colors=True,
392
570
  reload=True,
571
+ log_config=_build_uvicorn_log_config(),
393
572
  )
394
573
  except Exception:
395
574
  try:
@@ -399,6 +578,8 @@ if __name__ == "__main__":
399
578
 
400
579
  config = Config()
401
580
  config.bind = [f"{host}:{port}"]
581
+ config.use_reloader = True
582
+ config.logconfig_dict = _build_hypercorn_log_config()
402
583
 
403
584
  async def _run():
404
585
  await serve(asgi_app, config)