@vercel/python 6.51.0 → 6.52.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.
- package/dist/index.js +1203 -1124
- package/package.json +5 -6
- package/templates/vc_compileall.py +47 -0
- package/templates/vc_fastapi_static.py +116 -0
package/package.json
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vercel/python",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.52.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
|
|
7
7
|
"files": [
|
|
8
8
|
"dist",
|
|
9
|
-
"templates"
|
|
10
|
-
"vc_init.py"
|
|
9
|
+
"templates"
|
|
11
10
|
],
|
|
12
11
|
"repository": {
|
|
13
12
|
"type": "git",
|
|
@@ -36,18 +35,18 @@
|
|
|
36
35
|
"smol-toml": "1.5.2",
|
|
37
36
|
"vitest": "2.1.4",
|
|
38
37
|
"which": "3.0.0",
|
|
38
|
+
"@vercel/build-utils": "13.35.0",
|
|
39
39
|
"@vercel/error-utils": "2.2.0",
|
|
40
|
-
"@vercel/build-utils": "13.34.0",
|
|
41
40
|
"@vercel/python-runtime": "0.16.0"
|
|
42
41
|
},
|
|
43
42
|
"scripts": {
|
|
44
43
|
"build": "node ../../utils/build-builder.mjs",
|
|
45
44
|
"type-check": "tsc --noEmit",
|
|
46
45
|
"test": "cross-env VERCEL_FORCE_PYTHON_STREAMING=1 NODE_OPTIONS=--experimental-vm-modules vitest run --config ../../vitest.config.mts",
|
|
47
|
-
"test-unit": "vitest run --config ../../vitest.config.mts test/unit
|
|
46
|
+
"test-unit": "vitest run --config ../../vitest.config.mts test/unit",
|
|
48
47
|
"test-e2e": "pnpm test test/integration-*",
|
|
49
48
|
"vitest-run": "vitest -c ../../vitest.config.mts",
|
|
50
|
-
"vitest-unit": "glob --absolute 'test/unit
|
|
49
|
+
"vitest-unit": "glob --absolute 'test/unit.*test.ts'",
|
|
51
50
|
"vitest-e2e": "glob --absolute 'test/integration-*'"
|
|
52
51
|
}
|
|
53
52
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import compileall
|
|
2
|
+
import json
|
|
3
|
+
import signal
|
|
4
|
+
import sys
|
|
5
|
+
from multiprocessing import Pool
|
|
6
|
+
from py_compile import PycInvalidationMode
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def compile_source(source_file):
|
|
10
|
+
try:
|
|
11
|
+
return compileall.compile_file(
|
|
12
|
+
source_file,
|
|
13
|
+
force=True,
|
|
14
|
+
quiet=1,
|
|
15
|
+
invalidation_mode=PycInvalidationMode.UNCHECKED_HASH,
|
|
16
|
+
)
|
|
17
|
+
except Exception as error:
|
|
18
|
+
print(f"Failed to compile {source_file}: {error}", file=sys.stderr)
|
|
19
|
+
return False
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def main():
|
|
23
|
+
with open(sys.argv[1], encoding="utf-8") as source_list:
|
|
24
|
+
source_files = json.load(source_list)
|
|
25
|
+
|
|
26
|
+
if not source_files:
|
|
27
|
+
return 0
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
with Pool() as pool:
|
|
31
|
+
def abort_pool(signum, _):
|
|
32
|
+
pool.terminate()
|
|
33
|
+
raise SystemExit(128 + signum)
|
|
34
|
+
|
|
35
|
+
for sig in signal.SIGINT, signal.SIGTERM:
|
|
36
|
+
signal.signal(sig, abort_pool)
|
|
37
|
+
|
|
38
|
+
pool.map(compile_source, source_files)
|
|
39
|
+
except Exception as error:
|
|
40
|
+
print(f"Bytecode compilation unavailable: {error}", file=sys.stderr)
|
|
41
|
+
return 1
|
|
42
|
+
|
|
43
|
+
return 0
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
if __name__ == "__main__":
|
|
47
|
+
sys.exit(main())
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Discover StaticFiles mounts in a FastAPI/Starlette app by importing the user's
|
|
3
|
+
app object and walking its route table. Writes a JSON array of
|
|
4
|
+
{"urlPath": str, "directory": str} objects to the output file.
|
|
5
|
+
|
|
6
|
+
Usage: python <this_script> <entrypoint_abs_path> <variable_name> <output_path>
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import importlib.util
|
|
12
|
+
import json
|
|
13
|
+
import os
|
|
14
|
+
import sys
|
|
15
|
+
from dataclasses import asdict, dataclass
|
|
16
|
+
from typing import TYPE_CHECKING, cast
|
|
17
|
+
|
|
18
|
+
from starlette.routing import BaseRoute, Mount, Router
|
|
19
|
+
from starlette.staticfiles import StaticFiles
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from fastapi.routing import _EffectiveRouteContext, _FrontendRouteGroup
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class StaticMount:
|
|
27
|
+
urlPath: str
|
|
28
|
+
directory: str
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def from_route(cls, route: Mount, prefix: str = "") -> StaticMount | None:
|
|
32
|
+
static_app = route.app
|
|
33
|
+
if not isinstance(static_app, StaticFiles):
|
|
34
|
+
return None
|
|
35
|
+
directory = static_app.directory
|
|
36
|
+
if directory is None:
|
|
37
|
+
return None
|
|
38
|
+
return cls(
|
|
39
|
+
urlPath=prefix + route.path,
|
|
40
|
+
directory=os.path.abspath(str(directory)),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def get_low_priority_routes(router: Router) -> list[_FrontendRouteGroup]:
|
|
45
|
+
return getattr(router, "_low_priority_routes", [])
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def get_effective_low_priority_routes(route: BaseRoute) -> list[_EffectiveRouteContext]:
|
|
49
|
+
if fn := getattr(route, "effective_low_priority_routes", None):
|
|
50
|
+
return fn()
|
|
51
|
+
return []
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def collect_mounts(router: Router, prefix: str = "") -> list[StaticMount]:
|
|
55
|
+
mounts = []
|
|
56
|
+
|
|
57
|
+
for route in router.routes:
|
|
58
|
+
# app.mount("/path", StaticFiles(...))
|
|
59
|
+
if isinstance(route, Mount):
|
|
60
|
+
if m := StaticMount.from_route(route, prefix):
|
|
61
|
+
mounts.append(m)
|
|
62
|
+
if isinstance(route.app, Router):
|
|
63
|
+
sub_prefix = prefix + route.path.rstrip("/")
|
|
64
|
+
mounts.extend(collect_mounts(route.app, sub_prefix))
|
|
65
|
+
|
|
66
|
+
# app.include_router(router, prefix="/path")
|
|
67
|
+
for ctx in get_effective_low_priority_routes(route):
|
|
68
|
+
for r in ctx.original_route.routes:
|
|
69
|
+
if m := StaticMount.from_route(r, ctx.frontend_prefix):
|
|
70
|
+
mounts.append(m)
|
|
71
|
+
|
|
72
|
+
# app.frontend()
|
|
73
|
+
for group in get_low_priority_routes(router):
|
|
74
|
+
for route in group.routes:
|
|
75
|
+
if m := StaticMount.from_route(route, prefix):
|
|
76
|
+
mounts.append(m)
|
|
77
|
+
|
|
78
|
+
return mounts
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def write_output(output_path: str, data: list[object]) -> None:
|
|
82
|
+
with open(output_path, "w") as f:
|
|
83
|
+
json.dump(data, f)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def main() -> None:
|
|
87
|
+
entrypoint_abs = sys.argv[1]
|
|
88
|
+
variable_name = sys.argv[2]
|
|
89
|
+
output_path = sys.argv[3]
|
|
90
|
+
|
|
91
|
+
spec = importlib.util.spec_from_file_location("__vc_app", entrypoint_abs)
|
|
92
|
+
if spec is None or spec.loader is None:
|
|
93
|
+
write_output(output_path, [])
|
|
94
|
+
return
|
|
95
|
+
|
|
96
|
+
mod = importlib.util.module_from_spec(spec)
|
|
97
|
+
try:
|
|
98
|
+
spec.loader.exec_module(mod) # type: ignore[union-attr]
|
|
99
|
+
except Exception as exc:
|
|
100
|
+
print(f"vc_fastapi_static: exec_module failed: {exc}", file=sys.stderr)
|
|
101
|
+
write_output(output_path, [])
|
|
102
|
+
return
|
|
103
|
+
|
|
104
|
+
app = getattr(mod, variable_name, None)
|
|
105
|
+
if app is None:
|
|
106
|
+
write_output(output_path, [])
|
|
107
|
+
return
|
|
108
|
+
|
|
109
|
+
mounts = []
|
|
110
|
+
if router := getattr(app, "router", None):
|
|
111
|
+
mounts = collect_mounts(router)
|
|
112
|
+
|
|
113
|
+
write_output(output_path, [asdict(m) for m in mounts])
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
main()
|