@vercel/python 6.48.0 → 6.50.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 +1021 -323
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -48,7 +48,7 @@ var require_windows = __commonJS({
|
|
|
48
48
|
"../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/windows.js"(exports, module2) {
|
|
49
49
|
module2.exports = isexe;
|
|
50
50
|
isexe.sync = sync;
|
|
51
|
-
var
|
|
51
|
+
var fs16 = require("fs");
|
|
52
52
|
function checkPathExt(path, options) {
|
|
53
53
|
var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
|
|
54
54
|
if (!pathext) {
|
|
@@ -73,12 +73,12 @@ var require_windows = __commonJS({
|
|
|
73
73
|
return checkPathExt(path, options);
|
|
74
74
|
}
|
|
75
75
|
function isexe(path, options, cb) {
|
|
76
|
-
|
|
76
|
+
fs16.stat(path, function(er, stat) {
|
|
77
77
|
cb(er, er ? false : checkStat(stat, path, options));
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
80
|
function sync(path, options) {
|
|
81
|
-
return checkStat(
|
|
81
|
+
return checkStat(fs16.statSync(path), path, options);
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
});
|
|
@@ -88,14 +88,14 @@ var require_mode = __commonJS({
|
|
|
88
88
|
"../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/mode.js"(exports, module2) {
|
|
89
89
|
module2.exports = isexe;
|
|
90
90
|
isexe.sync = sync;
|
|
91
|
-
var
|
|
91
|
+
var fs16 = require("fs");
|
|
92
92
|
function isexe(path, options, cb) {
|
|
93
|
-
|
|
93
|
+
fs16.stat(path, function(er, stat) {
|
|
94
94
|
cb(er, er ? false : checkStat(stat, options));
|
|
95
95
|
});
|
|
96
96
|
}
|
|
97
97
|
function sync(path, options) {
|
|
98
|
-
return checkStat(
|
|
98
|
+
return checkStat(fs16.statSync(path), options);
|
|
99
99
|
}
|
|
100
100
|
function checkStat(stat, options) {
|
|
101
101
|
return stat.isFile() && checkMode(stat, options);
|
|
@@ -119,7 +119,7 @@ var require_mode = __commonJS({
|
|
|
119
119
|
// ../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.js
|
|
120
120
|
var require_isexe = __commonJS({
|
|
121
121
|
"../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.js"(exports, module2) {
|
|
122
|
-
var
|
|
122
|
+
var fs16 = require("fs");
|
|
123
123
|
var core;
|
|
124
124
|
if (process.platform === "win32" || global.TESTING_WINDOWS) {
|
|
125
125
|
core = require_windows();
|
|
@@ -395,7 +395,7 @@ var require_shebang_command = __commonJS({
|
|
|
395
395
|
var require_readShebang = __commonJS({
|
|
396
396
|
"../../node_modules/.pnpm/cross-spawn@6.0.5/node_modules/cross-spawn/lib/util/readShebang.js"(exports, module2) {
|
|
397
397
|
"use strict";
|
|
398
|
-
var
|
|
398
|
+
var fs16 = require("fs");
|
|
399
399
|
var shebangCommand = require_shebang_command();
|
|
400
400
|
function readShebang(command) {
|
|
401
401
|
const size = 150;
|
|
@@ -408,9 +408,9 @@ var require_readShebang = __commonJS({
|
|
|
408
408
|
}
|
|
409
409
|
let fd;
|
|
410
410
|
try {
|
|
411
|
-
fd =
|
|
412
|
-
|
|
413
|
-
|
|
411
|
+
fd = fs16.openSync(command, "r");
|
|
412
|
+
fs16.readSync(fd, buffer, 0, size, 0);
|
|
413
|
+
fs16.closeSync(fd);
|
|
414
414
|
} catch (e) {
|
|
415
415
|
}
|
|
416
416
|
return shebangCommand(buffer.toString());
|
|
@@ -1895,9 +1895,9 @@ var require_pump = __commonJS({
|
|
|
1895
1895
|
"../../node_modules/.pnpm/pump@3.0.4/node_modules/pump/index.js"(exports, module2) {
|
|
1896
1896
|
var once = require_once();
|
|
1897
1897
|
var eos = require_end_of_stream();
|
|
1898
|
-
var
|
|
1898
|
+
var fs16;
|
|
1899
1899
|
try {
|
|
1900
|
-
|
|
1900
|
+
fs16 = require("fs");
|
|
1901
1901
|
} catch (e) {
|
|
1902
1902
|
}
|
|
1903
1903
|
var noop = function() {
|
|
@@ -1909,9 +1909,9 @@ var require_pump = __commonJS({
|
|
|
1909
1909
|
var isFS = function(stream) {
|
|
1910
1910
|
if (!ancient)
|
|
1911
1911
|
return false;
|
|
1912
|
-
if (!
|
|
1912
|
+
if (!fs16)
|
|
1913
1913
|
return false;
|
|
1914
|
-
return (stream instanceof (
|
|
1914
|
+
return (stream instanceof (fs16.ReadStream || noop) || stream instanceof (fs16.WriteStream || noop)) && isFn(stream.close);
|
|
1915
1915
|
};
|
|
1916
1916
|
var isRequest = function(stream) {
|
|
1917
1917
|
return stream.setHeader && isFn(stream.abort);
|
|
@@ -2651,7 +2651,7 @@ ${stderr}${stdout}`;
|
|
|
2651
2651
|
var require_lib = __commonJS({
|
|
2652
2652
|
"../../node_modules/.pnpm/which@3.0.0/node_modules/which/lib/index.js"(exports, module2) {
|
|
2653
2653
|
var isexe = require_isexe();
|
|
2654
|
-
var { join:
|
|
2654
|
+
var { join: join17, delimiter: delimiter2, sep: sep3, posix } = require("path");
|
|
2655
2655
|
var isWindows = process.platform === "win32";
|
|
2656
2656
|
var rSlash = new RegExp(`[${posix.sep}${sep3 === posix.sep ? "" : sep3}]`.replace(/(\\)/g, "\\$1"));
|
|
2657
2657
|
var rRel = new RegExp(`^\\.${rSlash.source}`);
|
|
@@ -2680,7 +2680,7 @@ var require_lib = __commonJS({
|
|
|
2680
2680
|
var getPathPart = (raw, cmd) => {
|
|
2681
2681
|
const pathPart = /^".*"$/.test(raw) ? raw.slice(1, -1) : raw;
|
|
2682
2682
|
const prefix = !pathPart && rRel.test(cmd) ? cmd.slice(0, 2) : "";
|
|
2683
|
-
return prefix +
|
|
2683
|
+
return prefix + join17(pathPart, cmd);
|
|
2684
2684
|
};
|
|
2685
2685
|
var which2 = async (cmd, opt = {}) => {
|
|
2686
2686
|
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
|
|
@@ -3912,27 +3912,27 @@ var require_process = __commonJS({
|
|
|
3912
3912
|
var require_filesystem = __commonJS({
|
|
3913
3913
|
"../../node_modules/.pnpm/detect-libc@2.1.2/node_modules/detect-libc/lib/filesystem.js"(exports, module2) {
|
|
3914
3914
|
"use strict";
|
|
3915
|
-
var
|
|
3915
|
+
var fs16 = require("fs");
|
|
3916
3916
|
var LDD_PATH = "/usr/bin/ldd";
|
|
3917
3917
|
var SELF_PATH = "/proc/self/exe";
|
|
3918
3918
|
var MAX_LENGTH = 2048;
|
|
3919
3919
|
var readFileSync2 = (path) => {
|
|
3920
|
-
const fd =
|
|
3920
|
+
const fd = fs16.openSync(path, "r");
|
|
3921
3921
|
const buffer = Buffer.alloc(MAX_LENGTH);
|
|
3922
|
-
const bytesRead =
|
|
3923
|
-
|
|
3922
|
+
const bytesRead = fs16.readSync(fd, buffer, 0, MAX_LENGTH, 0);
|
|
3923
|
+
fs16.close(fd, () => {
|
|
3924
3924
|
});
|
|
3925
3925
|
return buffer.subarray(0, bytesRead);
|
|
3926
3926
|
};
|
|
3927
3927
|
var readFile2 = (path) => new Promise((resolve3, reject) => {
|
|
3928
|
-
|
|
3928
|
+
fs16.open(path, "r", (err, fd) => {
|
|
3929
3929
|
if (err) {
|
|
3930
3930
|
reject(err);
|
|
3931
3931
|
} else {
|
|
3932
3932
|
const buffer = Buffer.alloc(MAX_LENGTH);
|
|
3933
|
-
|
|
3933
|
+
fs16.read(fd, buffer, 0, MAX_LENGTH, 0, (_, bytesRead) => {
|
|
3934
3934
|
resolve3(buffer.subarray(0, bytesRead));
|
|
3935
|
-
|
|
3935
|
+
fs16.close(fd, () => {
|
|
3936
3936
|
});
|
|
3937
3937
|
});
|
|
3938
3938
|
}
|
|
@@ -4361,11 +4361,14 @@ var require_is_port_reachable = __commonJS({
|
|
|
4361
4361
|
// src/index.ts
|
|
4362
4362
|
var src_exports = {};
|
|
4363
4363
|
__export(src_exports, {
|
|
4364
|
+
addCollectedVendorBytecode: () => addCollectedVendorBytecode,
|
|
4365
|
+
addVendorBytecodeInTiers: () => addVendorBytecodeInTiers,
|
|
4364
4366
|
build: () => build,
|
|
4365
4367
|
defaultShouldServe: () => defaultShouldServe,
|
|
4366
4368
|
detectEntrypoint: () => detectEntrypoint,
|
|
4367
4369
|
diagnostics: () => diagnostics,
|
|
4368
4370
|
downloadFilesInWorkPath: () => downloadFilesInWorkPath,
|
|
4371
|
+
getDevSidecars: () => getDevSidecars,
|
|
4369
4372
|
installRequirement: () => installRequirement,
|
|
4370
4373
|
installRequirementsFile: () => installRequirementsFile,
|
|
4371
4374
|
prepareCache: () => prepareCache,
|
|
@@ -4376,15 +4379,15 @@ __export(src_exports, {
|
|
|
4376
4379
|
});
|
|
4377
4380
|
module.exports = __toCommonJS(src_exports);
|
|
4378
4381
|
var import_assert = __toESM(require("assert"));
|
|
4379
|
-
var
|
|
4380
|
-
var
|
|
4382
|
+
var import_fs17 = __toESM(require("fs"));
|
|
4383
|
+
var import_path17 = require("path");
|
|
4381
4384
|
|
|
4382
4385
|
// src/package-versions.ts
|
|
4383
4386
|
var VERCEL_RUNTIME_VERSION = "0.16.0";
|
|
4384
4387
|
var VERCEL_WORKERS_VERSION = "0.0.25";
|
|
4385
4388
|
|
|
4386
4389
|
// src/index.ts
|
|
4387
|
-
var
|
|
4390
|
+
var import_build_utils20 = require("@vercel/build-utils");
|
|
4388
4391
|
|
|
4389
4392
|
// src/install.ts
|
|
4390
4393
|
var import_execa3 = __toESM(require_execa());
|
|
@@ -5649,39 +5652,35 @@ var import_execa4 = __toESM(require_execa());
|
|
|
5649
5652
|
var import_build_utils6 = require("@vercel/build-utils");
|
|
5650
5653
|
var import_fs5 = __toESM(require("fs"));
|
|
5651
5654
|
var import_path6 = require("path");
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
return value === "1" || value === "true";
|
|
5657
|
-
}
|
|
5658
|
-
|
|
5659
|
-
// src/compileall.ts
|
|
5660
|
-
function isCompileAllEnabled() {
|
|
5661
|
-
if (!isLargeFunctionsEnabled())
|
|
5662
|
-
return false;
|
|
5655
|
+
var COMPILEALL_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
5656
|
+
var PYCACHE_PREFIX_DIR = "_vc_pycache";
|
|
5657
|
+
var RUNTIME_PYCACHE_PREFIX = `/var/task/${PYCACHE_PREFIX_DIR}`;
|
|
5658
|
+
function isCompileAllFlagEnabled() {
|
|
5663
5659
|
const val = process.env.VERCEL_PYTHON_COMPILEALL;
|
|
5664
5660
|
if (val === void 0 || val === "")
|
|
5665
5661
|
return false;
|
|
5666
5662
|
const lower = val.toLowerCase();
|
|
5667
5663
|
return lower === "1" || lower === "true";
|
|
5668
5664
|
}
|
|
5669
|
-
function
|
|
5665
|
+
function shouldCompileAll({
|
|
5670
5666
|
isDev,
|
|
5671
5667
|
hasCustomCommand,
|
|
5672
|
-
|
|
5668
|
+
hasPreDeployCommand
|
|
5673
5669
|
}) {
|
|
5674
5670
|
if (isDev)
|
|
5675
5671
|
return false;
|
|
5676
|
-
if (hasCustomCommand
|
|
5672
|
+
if (hasCustomCommand)
|
|
5677
5673
|
return false;
|
|
5678
|
-
|
|
5674
|
+
if (hasPreDeployCommand)
|
|
5675
|
+
return false;
|
|
5676
|
+
return isCompileAllFlagEnabled();
|
|
5679
5677
|
}
|
|
5680
5678
|
async function runCompileAll({
|
|
5681
5679
|
pythonBin,
|
|
5682
5680
|
filesOrDirectories,
|
|
5683
5681
|
env,
|
|
5684
|
-
excludeRegex
|
|
5682
|
+
excludeRegex,
|
|
5683
|
+
pycachePrefix
|
|
5685
5684
|
}) {
|
|
5686
5685
|
if (filesOrDirectories.length === 0)
|
|
5687
5686
|
return;
|
|
@@ -5697,8 +5696,13 @@ async function runCompileAll({
|
|
|
5697
5696
|
...excludeRegex ? ["-x", excludeRegex] : [],
|
|
5698
5697
|
...filesOrDirectories
|
|
5699
5698
|
];
|
|
5699
|
+
const baseEnv = env || process.env;
|
|
5700
|
+
const subprocessEnv = pycachePrefix ? { ...baseEnv, PYTHONPYCACHEPREFIX: pycachePrefix } : baseEnv;
|
|
5700
5701
|
try {
|
|
5701
|
-
await (0, import_execa4.default)(pythonBin, args, {
|
|
5702
|
+
await (0, import_execa4.default)(pythonBin, args, {
|
|
5703
|
+
env: subprocessEnv,
|
|
5704
|
+
timeout: COMPILEALL_TIMEOUT_MS
|
|
5705
|
+
});
|
|
5702
5706
|
} catch (err) {
|
|
5703
5707
|
(0, import_build_utils6.debug)(`compileall error details: ${JSON.stringify(err)}`);
|
|
5704
5708
|
}
|
|
@@ -5711,6 +5715,42 @@ function derivePycPath(pyRelPath, pythonMajor, pythonMinor) {
|
|
|
5711
5715
|
const baseName = pyRelPath.slice(lastSlash + 1, -3);
|
|
5712
5716
|
return `${dir}__pycache__/${baseName}.cpython-${pythonMajor}${pythonMinor}.pyc`;
|
|
5713
5717
|
}
|
|
5718
|
+
function derivePrefixPycRelPath(pyRelPath, pythonMajor, pythonMinor) {
|
|
5719
|
+
if (!pyRelPath.endsWith(".py"))
|
|
5720
|
+
return null;
|
|
5721
|
+
return `${pyRelPath.slice(0, -3)}.cpython-${pythonMajor}${pythonMinor}.pyc`;
|
|
5722
|
+
}
|
|
5723
|
+
function stripPycachePrefixRoot(head) {
|
|
5724
|
+
const pycachePathSeparators = /* @__PURE__ */ new Set(["/", "\\"]);
|
|
5725
|
+
if (head.length > 1 && head[1] === ":" && !pycachePathSeparators.has(head[0])) {
|
|
5726
|
+
head = head.slice(2);
|
|
5727
|
+
}
|
|
5728
|
+
let start = 0;
|
|
5729
|
+
while (start < head.length && pycachePathSeparators.has(head[start])) {
|
|
5730
|
+
start++;
|
|
5731
|
+
}
|
|
5732
|
+
return head.slice(start);
|
|
5733
|
+
}
|
|
5734
|
+
function deriveStagedPycFsPath(stagingDir, srcAbsPath, pythonMajor, pythonMinor) {
|
|
5735
|
+
const rel = derivePrefixPycRelPath(
|
|
5736
|
+
stripPycachePrefixRoot(srcAbsPath),
|
|
5737
|
+
pythonMajor,
|
|
5738
|
+
pythonMinor
|
|
5739
|
+
);
|
|
5740
|
+
if (!rel)
|
|
5741
|
+
return null;
|
|
5742
|
+
return (0, import_path6.join)(stagingDir, rel.replaceAll("/", import_path6.sep));
|
|
5743
|
+
}
|
|
5744
|
+
function derivePrefixPycBundlePath(runtimeAbsPath, pythonMajor, pythonMinor) {
|
|
5745
|
+
const rel = derivePrefixPycRelPath(
|
|
5746
|
+
stripPycachePrefixRoot(runtimeAbsPath),
|
|
5747
|
+
pythonMajor,
|
|
5748
|
+
pythonMinor
|
|
5749
|
+
);
|
|
5750
|
+
if (!rel)
|
|
5751
|
+
return null;
|
|
5752
|
+
return `${PYCACHE_PREFIX_DIR}/${rel}`;
|
|
5753
|
+
}
|
|
5714
5754
|
var COMPILEALL_APP_EXCLUDED_DIRS = [
|
|
5715
5755
|
".git",
|
|
5716
5756
|
".vercel",
|
|
@@ -5732,6 +5772,58 @@ function getCompileAllAppExcludeRegex(workPath) {
|
|
|
5732
5772
|
const excludedDirs = COMPILEALL_APP_EXCLUDED_DIRS.map(escapePythonRegex).join("|");
|
|
5733
5773
|
return `${escapePythonRegex(workPath)}[/\\\\](?:${excludedDirs})(?:[/\\\\]|$)`;
|
|
5734
5774
|
}
|
|
5775
|
+
async function collectAppPrefixBytecodeFiles({
|
|
5776
|
+
stagingDir,
|
|
5777
|
+
workPath,
|
|
5778
|
+
files: appFiles,
|
|
5779
|
+
runtimeTaskRoot,
|
|
5780
|
+
pythonMajor,
|
|
5781
|
+
pythonMinor
|
|
5782
|
+
}) {
|
|
5783
|
+
const pending = [];
|
|
5784
|
+
for (const bundlePath of Object.keys(appFiles)) {
|
|
5785
|
+
if (!bundlePath.endsWith(".py"))
|
|
5786
|
+
continue;
|
|
5787
|
+
const stagedFsPath = deriveStagedPycFsPath(
|
|
5788
|
+
stagingDir,
|
|
5789
|
+
(0, import_path6.join)(workPath, bundlePath.replaceAll("/", import_path6.sep)),
|
|
5790
|
+
pythonMajor,
|
|
5791
|
+
pythonMinor
|
|
5792
|
+
);
|
|
5793
|
+
const pycBundlePath = derivePrefixPycBundlePath(
|
|
5794
|
+
`${runtimeTaskRoot}/${bundlePath}`,
|
|
5795
|
+
pythonMajor,
|
|
5796
|
+
pythonMinor
|
|
5797
|
+
);
|
|
5798
|
+
if (!stagedFsPath || !pycBundlePath)
|
|
5799
|
+
continue;
|
|
5800
|
+
pending.push({ bundlePath: pycBundlePath, srcFsPath: stagedFsPath });
|
|
5801
|
+
}
|
|
5802
|
+
const results = await Promise.all(
|
|
5803
|
+
pending.map(async ({ bundlePath, srcFsPath }) => {
|
|
5804
|
+
try {
|
|
5805
|
+
const stats = await import_fs5.default.promises.stat(srcFsPath);
|
|
5806
|
+
return { bundlePath, srcFsPath, size: stats.size };
|
|
5807
|
+
} catch {
|
|
5808
|
+
return null;
|
|
5809
|
+
}
|
|
5810
|
+
})
|
|
5811
|
+
);
|
|
5812
|
+
const files = {};
|
|
5813
|
+
const perItemSizes = /* @__PURE__ */ new Map();
|
|
5814
|
+
let totalSize = 0;
|
|
5815
|
+
for (const result of results) {
|
|
5816
|
+
if (!result)
|
|
5817
|
+
continue;
|
|
5818
|
+
files[result.bundlePath] = new import_build_utils6.FileFsRef({
|
|
5819
|
+
fsPath: result.srcFsPath,
|
|
5820
|
+
size: result.size
|
|
5821
|
+
});
|
|
5822
|
+
perItemSizes.set(result.bundlePath, result.size);
|
|
5823
|
+
totalSize += result.size;
|
|
5824
|
+
}
|
|
5825
|
+
return { files, totalSize, perItemSizes };
|
|
5826
|
+
}
|
|
5735
5827
|
async function collectAppBytecodeFiles({
|
|
5736
5828
|
workPath,
|
|
5737
5829
|
files: appFiles,
|
|
@@ -5774,6 +5866,12 @@ async function collectAppBytecodeFiles({
|
|
|
5774
5866
|
return { files, totalSize, perItemSizes };
|
|
5775
5867
|
}
|
|
5776
5868
|
|
|
5869
|
+
// src/large-functions.ts
|
|
5870
|
+
function isLargeFunctionsEnabled() {
|
|
5871
|
+
const value = process.env.VERCEL_SUPPORT_LARGE_FUNCTIONS;
|
|
5872
|
+
return value === "1" || value === "true";
|
|
5873
|
+
}
|
|
5874
|
+
|
|
5777
5875
|
// src/dependency-externalizer.ts
|
|
5778
5876
|
var readFile = (0, import_util.promisify)(import_fs6.default.readFile);
|
|
5779
5877
|
var STRIP_BASENAMES = /* @__PURE__ */ new Set([
|
|
@@ -5794,7 +5892,11 @@ function shouldStripVendorFile(filePath) {
|
|
|
5794
5892
|
return false;
|
|
5795
5893
|
}
|
|
5796
5894
|
var LAMBDA_SIZE_THRESHOLD_BYTES = 225 * 1024 * 1024;
|
|
5895
|
+
var BYTECODE_FILL_MARGIN_BYTES = 5 * 1024 * 1024;
|
|
5896
|
+
var BYTECODE_FILL_CEILING_BYTES = LAMBDA_SIZE_THRESHOLD_BYTES - BYTECODE_FILL_MARGIN_BYTES;
|
|
5797
5897
|
var LAMBDA_EPHEMERAL_STORAGE_BYTES = 500 * 1024 * 1024;
|
|
5898
|
+
var EPHEMERAL_INSTALL_BUDGET_BYTES = LAMBDA_EPHEMERAL_STORAGE_BYTES - 50 * 1024 * 1024;
|
|
5899
|
+
var RUNTIME_DEPS_DIR = "/tmp/_vc_deps";
|
|
5798
5900
|
var MAX_LARGE_FUNCTION_UNCOMPRESSED_SIZE = 5 * 1024 * 1024 * 1024;
|
|
5799
5901
|
var BUNDLING_DOCS_LINK = "https://vercel.com/docs/functions/runtimes/python#controlling-what-gets-bundled";
|
|
5800
5902
|
var PythonDependencyExternalizer = class {
|
|
@@ -5905,7 +6007,7 @@ application into smaller functions.`,
|
|
|
5905
6007
|
* back to bundling everything for Hive and returns `fellBackToFullBundle:
|
|
5906
6008
|
* true` so the caller can apply the same compileall handling.
|
|
5907
6009
|
*/
|
|
5908
|
-
async generateBundle(files) {
|
|
6010
|
+
async generateBundle(files, options = {}) {
|
|
5909
6011
|
if (!this.analyzed) {
|
|
5910
6012
|
throw new Error(
|
|
5911
6013
|
"PythonDependencyExternalizer.analyze() must be called before generateBundle()"
|
|
@@ -6066,7 +6168,20 @@ To fix this, either:
|
|
|
6066
6168
|
([name]) => externalizableSet.has((0, import_python_analysis3.normalizePackageName)(name))
|
|
6067
6169
|
)
|
|
6068
6170
|
);
|
|
6069
|
-
const bundledPublic =
|
|
6171
|
+
const { packingMode, bundledPublic } = planPublicPackagePacking({
|
|
6172
|
+
publicPackageSizes,
|
|
6173
|
+
zipCapacity: remainingCapacity,
|
|
6174
|
+
bytecodeFirst: options.bytecodeFirst ?? false
|
|
6175
|
+
});
|
|
6176
|
+
if (options.bytecodeFirst && packingMode === "knapsack") {
|
|
6177
|
+
(0, import_build_utils7.debug)(
|
|
6178
|
+
`bytecode-first packing disabled: the public package set exceeds the ephemeral install budget (${(EPHEMERAL_INSTALL_BUDGET_BYTES / (1024 * 1024)).toFixed(2)} MB); falling back to knapsack packing`
|
|
6179
|
+
);
|
|
6180
|
+
}
|
|
6181
|
+
const bundledPublicSet = new Set(bundledPublic.map(import_python_analysis3.normalizePackageName));
|
|
6182
|
+
const externalizedPublic = externalizablePublic.filter(
|
|
6183
|
+
(name) => !bundledPublicSet.has((0, import_python_analysis3.normalizePackageName)(name))
|
|
6184
|
+
);
|
|
6070
6185
|
const allBundledPackages = [...alwaysBundled, ...bundledPublic];
|
|
6071
6186
|
const selectedVendorFiles = await this.mirrorPackagesIntoVendor({
|
|
6072
6187
|
vendorDirName: this.vendorDir,
|
|
@@ -6138,7 +6253,13 @@ functions.`,
|
|
|
6138
6253
|
action: "Learn More"
|
|
6139
6254
|
});
|
|
6140
6255
|
}
|
|
6141
|
-
return {
|
|
6256
|
+
return {
|
|
6257
|
+
fellBackToFullBundle: false,
|
|
6258
|
+
packingMode,
|
|
6259
|
+
alwaysBundledPackages: alwaysBundled,
|
|
6260
|
+
bundledPublicPackages: bundledPublic,
|
|
6261
|
+
externalizedPublicPackages: externalizedPublic
|
|
6262
|
+
};
|
|
6142
6263
|
}
|
|
6143
6264
|
/**
|
|
6144
6265
|
* Discard any runtime-install artifacts added so far and bundle every
|
|
@@ -6451,6 +6572,92 @@ functions.`,
|
|
|
6451
6572
|
);
|
|
6452
6573
|
return { files, totalSize, perItemSizes };
|
|
6453
6574
|
}
|
|
6575
|
+
/**
|
|
6576
|
+
* Collect staged prefix `.pyc` files for vendor packages, keyed under
|
|
6577
|
+
* `_vc_pycache/<runtimeRoot>/...` (`runtimeRoot` = `/var/task/_vendor`
|
|
6578
|
+
* for bundled packages, the /tmp site-packages dir for externalized
|
|
6579
|
+
* ones). Missing staged files are silently skipped. Must be called after
|
|
6580
|
+
* `analyze()`.
|
|
6581
|
+
*/
|
|
6582
|
+
async collectPrefixBytecodeFiles({
|
|
6583
|
+
stagingDir,
|
|
6584
|
+
runtimeRoot,
|
|
6585
|
+
includePackages
|
|
6586
|
+
}) {
|
|
6587
|
+
if (!this.sitePackageDirs || !this.distributions) {
|
|
6588
|
+
throw new Error(
|
|
6589
|
+
"collectPrefixBytecodeFiles() must be called after analyze()"
|
|
6590
|
+
);
|
|
6591
|
+
}
|
|
6592
|
+
if (this.pythonMajor == null || this.pythonMinor == null) {
|
|
6593
|
+
return { files: {}, totalSize: 0, perItemSizes: /* @__PURE__ */ new Map() };
|
|
6594
|
+
}
|
|
6595
|
+
const includeSet = includePackages ? new Set(includePackages.map(import_python_analysis3.normalizePackageName)) : null;
|
|
6596
|
+
const pending = [];
|
|
6597
|
+
for (const dir of this.sitePackageDirs) {
|
|
6598
|
+
const dirDistributions = this.distributions.get(dir);
|
|
6599
|
+
if (!dirDistributions)
|
|
6600
|
+
continue;
|
|
6601
|
+
const resolvedDir = (0, import_path7.resolve)(dir);
|
|
6602
|
+
const dirPrefix = resolvedDir + import_path7.sep;
|
|
6603
|
+
for (const [name, dist] of dirDistributions) {
|
|
6604
|
+
if (includeSet && !includeSet.has(name))
|
|
6605
|
+
continue;
|
|
6606
|
+
for (const { path: rawPath } of dist.files) {
|
|
6607
|
+
if (!rawPath.endsWith(".py"))
|
|
6608
|
+
continue;
|
|
6609
|
+
const filePath = rawPath.replaceAll("/", import_path7.sep);
|
|
6610
|
+
if (!(0, import_path7.resolve)(resolvedDir, filePath).startsWith(dirPrefix)) {
|
|
6611
|
+
continue;
|
|
6612
|
+
}
|
|
6613
|
+
const srcFsPath = deriveStagedPycFsPath(
|
|
6614
|
+
stagingDir,
|
|
6615
|
+
(0, import_path7.join)(dir, filePath),
|
|
6616
|
+
this.pythonMajor,
|
|
6617
|
+
this.pythonMinor
|
|
6618
|
+
);
|
|
6619
|
+
const bundlePath = derivePrefixPycBundlePath(
|
|
6620
|
+
`${runtimeRoot}/${rawPath}`,
|
|
6621
|
+
this.pythonMajor,
|
|
6622
|
+
this.pythonMinor
|
|
6623
|
+
);
|
|
6624
|
+
if (!srcFsPath || !bundlePath)
|
|
6625
|
+
continue;
|
|
6626
|
+
pending.push({ bundlePath, srcFsPath, packageName: name });
|
|
6627
|
+
}
|
|
6628
|
+
}
|
|
6629
|
+
}
|
|
6630
|
+
const results = await Promise.all(
|
|
6631
|
+
pending.map(async ({ bundlePath, srcFsPath, packageName }) => {
|
|
6632
|
+
try {
|
|
6633
|
+
const stats = await import_fs6.default.promises.stat(srcFsPath);
|
|
6634
|
+
return { bundlePath, srcFsPath, size: stats.size, packageName };
|
|
6635
|
+
} catch {
|
|
6636
|
+
return null;
|
|
6637
|
+
}
|
|
6638
|
+
})
|
|
6639
|
+
);
|
|
6640
|
+
const files = {};
|
|
6641
|
+
let totalSize = 0;
|
|
6642
|
+
const perItemSizes = /* @__PURE__ */ new Map();
|
|
6643
|
+
for (const result of results) {
|
|
6644
|
+
if (!result)
|
|
6645
|
+
continue;
|
|
6646
|
+
files[result.bundlePath] = new import_build_utils7.FileFsRef({
|
|
6647
|
+
fsPath: result.srcFsPath,
|
|
6648
|
+
size: result.size
|
|
6649
|
+
});
|
|
6650
|
+
totalSize += result.size;
|
|
6651
|
+
perItemSizes.set(
|
|
6652
|
+
result.packageName,
|
|
6653
|
+
(perItemSizes.get(result.packageName) ?? 0) + result.size
|
|
6654
|
+
);
|
|
6655
|
+
}
|
|
6656
|
+
(0, import_build_utils7.debug)(
|
|
6657
|
+
`Collected ${Object.keys(files).length} prefix bytecode files (${(totalSize / (1024 * 1024)).toFixed(2)} MB) for runtime root ${runtimeRoot}` + (includePackages ? ` from ${includePackages.length} packages` : "")
|
|
6658
|
+
);
|
|
6659
|
+
return { files, totalSize, perItemSizes };
|
|
6660
|
+
}
|
|
6454
6661
|
};
|
|
6455
6662
|
async function getPackagesReachableOnPlatform(lockFile, projectName, pythonMajor, pythonMinor, sysPlatform, platformMachine) {
|
|
6456
6663
|
if (!projectName)
|
|
@@ -6510,10 +6717,12 @@ async function getPackagesReachableOnPlatform(lockFile, projectName, pythonMajor
|
|
|
6510
6717
|
}
|
|
6511
6718
|
return visited;
|
|
6512
6719
|
}
|
|
6513
|
-
async function calculateBundleSize(files) {
|
|
6720
|
+
async function calculateBundleSize(files, filter) {
|
|
6514
6721
|
let knownSize = 0;
|
|
6515
6722
|
const statPromises = [];
|
|
6516
6723
|
for (const filePath of Object.keys(files)) {
|
|
6724
|
+
if (filter && !filter(filePath))
|
|
6725
|
+
continue;
|
|
6517
6726
|
const file = files[filePath];
|
|
6518
6727
|
if ("fsPath" in file && file.fsPath) {
|
|
6519
6728
|
const fsRef = file;
|
|
@@ -6521,7 +6730,10 @@ async function calculateBundleSize(files) {
|
|
|
6521
6730
|
knownSize += fsRef.size;
|
|
6522
6731
|
} else {
|
|
6523
6732
|
statPromises.push(
|
|
6524
|
-
import_fs6.default.promises.stat(fsRef.fsPath).then((stats) =>
|
|
6733
|
+
import_fs6.default.promises.stat(fsRef.fsPath).then((stats) => {
|
|
6734
|
+
fsRef.size = stats.size;
|
|
6735
|
+
return stats.size;
|
|
6736
|
+
}).catch((err) => {
|
|
6525
6737
|
console.warn(
|
|
6526
6738
|
`Warning: Failed to stat file ${fsRef.fsPath}, size will not be included in bundle calculation: ${err}`
|
|
6527
6739
|
);
|
|
@@ -6541,6 +6753,12 @@ async function calculateBundleSize(files) {
|
|
|
6541
6753
|
}
|
|
6542
6754
|
return totalSize;
|
|
6543
6755
|
}
|
|
6756
|
+
var PYC_TO_PY_RATIO = 1.2;
|
|
6757
|
+
var BYTECODE_COVERAGE_FLOOR = 0.5;
|
|
6758
|
+
async function estimateBytecodeSize(files) {
|
|
6759
|
+
const pyBytes = await calculateBundleSize(files, (p) => p.endsWith(".py"));
|
|
6760
|
+
return PYC_TO_PY_RATIO * pyBytes;
|
|
6761
|
+
}
|
|
6544
6762
|
function lambdaKnapsack(packages, capacity) {
|
|
6545
6763
|
if (capacity <= 0) {
|
|
6546
6764
|
return [];
|
|
@@ -6556,6 +6774,23 @@ function lambdaKnapsack(packages, capacity) {
|
|
|
6556
6774
|
}
|
|
6557
6775
|
return bundled;
|
|
6558
6776
|
}
|
|
6777
|
+
function planPublicPackagePacking({
|
|
6778
|
+
publicPackageSizes,
|
|
6779
|
+
zipCapacity,
|
|
6780
|
+
bytecodeFirst
|
|
6781
|
+
}) {
|
|
6782
|
+
let totalPublicSize = 0;
|
|
6783
|
+
for (const size of publicPackageSizes.values()) {
|
|
6784
|
+
totalPublicSize += size;
|
|
6785
|
+
}
|
|
6786
|
+
if (bytecodeFirst && totalPublicSize <= EPHEMERAL_INSTALL_BUDGET_BYTES) {
|
|
6787
|
+
return { packingMode: "bytecode-first", bundledPublic: [] };
|
|
6788
|
+
}
|
|
6789
|
+
return {
|
|
6790
|
+
packingMode: "knapsack",
|
|
6791
|
+
bundledPublic: lambdaKnapsack(publicPackageSizes, zipCapacity)
|
|
6792
|
+
};
|
|
6793
|
+
}
|
|
6559
6794
|
|
|
6560
6795
|
// src/diagnostics.ts
|
|
6561
6796
|
var import_fs7 = __toESM(require("fs"));
|
|
@@ -6870,7 +7105,7 @@ function getMissingExportMessage(framework, entrypoints) {
|
|
|
6870
7105
|
}
|
|
6871
7106
|
}
|
|
6872
7107
|
function entrypointToModule(entrypoint) {
|
|
6873
|
-
return entrypoint.replace(/\\/g, "/").replace(/\.py$/i, "").replace(/\//g, ".");
|
|
7108
|
+
return entrypoint.replace(/\\/g, "/").replace(/\.py$/i, "").replace(/\/__init__$/i, "").replace(/\//g, ".");
|
|
6874
7109
|
}
|
|
6875
7110
|
async function checkEntrypoint(workPath, relPath) {
|
|
6876
7111
|
const absPath = (0, import_path8.join)(workPath, relPath);
|
|
@@ -6946,14 +7181,37 @@ async function resolveModuleAttrEntrypoint(workPath, value) {
|
|
|
6946
7181
|
}
|
|
6947
7182
|
return null;
|
|
6948
7183
|
}
|
|
6949
|
-
async function getVercelToolsEntrypoint(workPath) {
|
|
6950
|
-
const
|
|
7184
|
+
async function getVercelToolsEntrypoint(workPath, repoRootPath) {
|
|
7185
|
+
const pyprojectPath = (0, import_path8.join)(workPath, "pyproject.toml");
|
|
7186
|
+
const pyprojectData = await (0, import_build_utils11.readConfigFile)(pyprojectPath);
|
|
6951
7187
|
if (!pyprojectData)
|
|
6952
7188
|
return null;
|
|
6953
7189
|
const vercelEntrypoint = pyprojectData.tool?.vercel?.entrypoint;
|
|
6954
|
-
if (
|
|
7190
|
+
if (vercelEntrypoint === void 0)
|
|
6955
7191
|
return null;
|
|
6956
|
-
|
|
7192
|
+
const relPyprojectPath = (0, import_path8.relative)(repoRootPath ?? workPath, pyprojectPath);
|
|
7193
|
+
const displayPath = !relPyprojectPath || relPyprojectPath.startsWith("..") ? pyprojectPath : relPyprojectPath;
|
|
7194
|
+
if (typeof vercelEntrypoint !== "string") {
|
|
7195
|
+
throw new import_build_utils9.NowBuildError({
|
|
7196
|
+
code: "PYTHON_INVALID_ENTRYPOINT",
|
|
7197
|
+
message: `"tool.vercel.entrypoint" in "${displayPath}" must be a string in "module:object" format (e.g. "main:app").`,
|
|
7198
|
+
link: PYTHON_ENTRYPOINT_DOCS_URL,
|
|
7199
|
+
action: "Learn More"
|
|
7200
|
+
});
|
|
7201
|
+
}
|
|
7202
|
+
const resolved = await resolveModuleAttrEntrypoint(
|
|
7203
|
+
workPath,
|
|
7204
|
+
vercelEntrypoint
|
|
7205
|
+
);
|
|
7206
|
+
if (!resolved) {
|
|
7207
|
+
throw new import_build_utils9.NowBuildError({
|
|
7208
|
+
code: "PYTHON_ENTRYPOINT_NOT_FOUND",
|
|
7209
|
+
message: `"tool.vercel.entrypoint" in "${displayPath}" is "${vercelEntrypoint}" but no matching module file was found. Use "module:object" format (e.g. "main:app") and ensure the module file exists, or remove the setting to use automatic entrypoint detection.`,
|
|
7210
|
+
link: PYTHON_ENTRYPOINT_DOCS_URL,
|
|
7211
|
+
action: "Learn More"
|
|
7212
|
+
});
|
|
7213
|
+
}
|
|
7214
|
+
return resolved;
|
|
6957
7215
|
}
|
|
6958
7216
|
async function getPyprojectEntrypointWithDiagnostics(workPath) {
|
|
6959
7217
|
const pyprojectData = await (0, import_build_utils11.readConfigFile)((0, import_path8.join)(workPath, "pyproject.toml"));
|
|
@@ -7107,7 +7365,7 @@ async function detectDjangoPythonEntrypoint(workPath) {
|
|
|
7107
7365
|
return emptyResult;
|
|
7108
7366
|
}
|
|
7109
7367
|
}
|
|
7110
|
-
async function detectPythonEntrypoint(framework, workPath, configuredEntrypoint, service) {
|
|
7368
|
+
async function detectPythonEntrypoint(framework, workPath, configuredEntrypoint, service, repoRootPath) {
|
|
7111
7369
|
if (configuredEntrypoint) {
|
|
7112
7370
|
const { filePath: configEntryFile, varName: configEntryVar } = configuredEntrypoint;
|
|
7113
7371
|
const entrypoint = configEntryFile.endsWith(".py") ? configEntryFile : `${configEntryFile}.py`;
|
|
@@ -7146,7 +7404,7 @@ async function detectPythonEntrypoint(framework, workPath, configuredEntrypoint,
|
|
|
7146
7404
|
if (!framework) {
|
|
7147
7405
|
return null;
|
|
7148
7406
|
}
|
|
7149
|
-
const vercelEntry = await getVercelToolsEntrypoint(workPath);
|
|
7407
|
+
const vercelEntry = await getVercelToolsEntrypoint(workPath, repoRootPath);
|
|
7150
7408
|
if (vercelEntry)
|
|
7151
7409
|
return { entrypoint: vercelEntry };
|
|
7152
7410
|
let findDiagnostics;
|
|
@@ -7186,10 +7444,18 @@ var detectEntrypoint = async ({
|
|
|
7186
7444
|
}) => {
|
|
7187
7445
|
if (!(0, import_build_utils9.isPythonFramework)(framework))
|
|
7188
7446
|
return null;
|
|
7189
|
-
|
|
7190
|
-
|
|
7191
|
-
|
|
7192
|
-
|
|
7447
|
+
let detected;
|
|
7448
|
+
try {
|
|
7449
|
+
detected = await detectPythonEntrypoint(
|
|
7450
|
+
framework,
|
|
7451
|
+
workPath
|
|
7452
|
+
);
|
|
7453
|
+
} catch (err) {
|
|
7454
|
+
(0, import_build_utils10.debug)(
|
|
7455
|
+
`Python entrypoint detection failed for ${workPath}: ${err instanceof Error ? err.message : String(err)}`
|
|
7456
|
+
);
|
|
7457
|
+
return null;
|
|
7458
|
+
}
|
|
7193
7459
|
if (!detected?.entrypoint)
|
|
7194
7460
|
return null;
|
|
7195
7461
|
const { entrypoint, variableName } = detected.entrypoint;
|
|
@@ -7415,6 +7681,23 @@ async function getReachableHost(port) {
|
|
|
7415
7681
|
]);
|
|
7416
7682
|
return results.find(Boolean) || false;
|
|
7417
7683
|
}
|
|
7684
|
+
async function dedupePendingOperation(operations, key, operation) {
|
|
7685
|
+
const existing = operations.get(key);
|
|
7686
|
+
if (existing) {
|
|
7687
|
+
return existing;
|
|
7688
|
+
}
|
|
7689
|
+
const pending = operation();
|
|
7690
|
+
operations.set(key, pending);
|
|
7691
|
+
try {
|
|
7692
|
+
return await pending;
|
|
7693
|
+
} finally {
|
|
7694
|
+
if (operations.get(key) === pending) {
|
|
7695
|
+
operations.delete(key);
|
|
7696
|
+
}
|
|
7697
|
+
}
|
|
7698
|
+
}
|
|
7699
|
+
var PENDING_MANAGED_VENV_CREATIONS = /* @__PURE__ */ new Map();
|
|
7700
|
+
var PENDING_DEPENDENCY_SYNCS = /* @__PURE__ */ new Map();
|
|
7418
7701
|
async function syncDependencies({
|
|
7419
7702
|
workPath,
|
|
7420
7703
|
uvPath,
|
|
@@ -7558,16 +7841,29 @@ async function runSync({
|
|
|
7558
7841
|
});
|
|
7559
7842
|
}
|
|
7560
7843
|
var PENDING_INSTALLS = /* @__PURE__ */ new Map();
|
|
7844
|
+
var COMPLETED_INSTALLS = /* @__PURE__ */ new Set();
|
|
7845
|
+
function hasInstalledDistribution(targetDir, packageName) {
|
|
7846
|
+
const prefix = `${packageName.replace("-", "_")}-`;
|
|
7847
|
+
try {
|
|
7848
|
+
return (0, import_fs10.readdirSync)(targetDir).some(
|
|
7849
|
+
(entry) => entry.startsWith(prefix) && entry.endsWith(".dist-info")
|
|
7850
|
+
);
|
|
7851
|
+
} catch {
|
|
7852
|
+
return false;
|
|
7853
|
+
}
|
|
7854
|
+
}
|
|
7561
7855
|
async function installInjectedDevPackage(pkg, opts) {
|
|
7562
7856
|
const targetDir = (0, import_path10.join)(opts.workPath, ".vercel", "python");
|
|
7563
|
-
const
|
|
7564
|
-
|
|
7565
|
-
if (
|
|
7566
|
-
|
|
7567
|
-
PENDING_INSTALLS.set(key, pending);
|
|
7568
|
-
pending.finally(() => PENDING_INSTALLS.delete(key));
|
|
7857
|
+
const source = pkg.envOverride || pkg.pinnedVersion;
|
|
7858
|
+
const key = `${targetDir}:${pkg.name}:${source}`;
|
|
7859
|
+
if (COMPLETED_INSTALLS.has(key) && hasInstalledDistribution(targetDir, pkg.name)) {
|
|
7860
|
+
return;
|
|
7569
7861
|
}
|
|
7570
|
-
|
|
7862
|
+
COMPLETED_INSTALLS.delete(key);
|
|
7863
|
+
await dedupePendingOperation(PENDING_INSTALLS, key, async () => {
|
|
7864
|
+
await doInstallInjectedDevPackage(pkg, { ...opts, targetDir });
|
|
7865
|
+
COMPLETED_INSTALLS.add(key);
|
|
7866
|
+
});
|
|
7571
7867
|
}
|
|
7572
7868
|
async function doInstallInjectedDevPackage(pkg, opts) {
|
|
7573
7869
|
const { targetDir, workPath, uvPath, pythonBin, env, onStdout, onStderr } = opts;
|
|
@@ -7707,18 +8003,26 @@ function createDevShim(workPath, entry, modulePath, serviceName, framework, vari
|
|
|
7707
8003
|
}
|
|
7708
8004
|
}
|
|
7709
8005
|
async function getMultiServicePythonRunner(workPath, env, systemPython, uvPath) {
|
|
8006
|
+
const venvPath = (0, import_path10.join)(workPath, ".venv");
|
|
8007
|
+
const pendingCreation = PENDING_MANAGED_VENV_CREATIONS.get(venvPath);
|
|
8008
|
+
if (pendingCreation) {
|
|
8009
|
+
await pendingCreation;
|
|
8010
|
+
}
|
|
7710
8011
|
const { pythonCmd, venvRoot } = useVirtualEnv(workPath, env, systemPython);
|
|
7711
8012
|
if (venvRoot) {
|
|
7712
8013
|
(0, import_build_utils13.debug)(`Using existing virtualenv at ${venvRoot} for multi-service dev`);
|
|
7713
8014
|
return { command: pythonCmd, args: [] };
|
|
7714
8015
|
}
|
|
7715
|
-
|
|
7716
|
-
|
|
7717
|
-
pythonVersion: { pythonPath: systemPython },
|
|
8016
|
+
await dedupePendingOperation(
|
|
8017
|
+
PENDING_MANAGED_VENV_CREATIONS,
|
|
7718
8018
|
venvPath,
|
|
7719
|
-
|
|
7720
|
-
|
|
7721
|
-
|
|
8019
|
+
() => ensureVenv({
|
|
8020
|
+
pythonVersion: { pythonPath: systemPython },
|
|
8021
|
+
venvPath,
|
|
8022
|
+
uvPath,
|
|
8023
|
+
quiet: true
|
|
8024
|
+
})
|
|
8025
|
+
);
|
|
7722
8026
|
(0, import_build_utils13.debug)(`Created virtualenv at ${venvPath} for multi-service dev`);
|
|
7723
8027
|
const pythonBin = getVenvPythonBin(venvPath);
|
|
7724
8028
|
const binDir = getVenvBinDir(venvPath);
|
|
@@ -7779,7 +8083,8 @@ var startDevServer = async (opts) => {
|
|
|
7779
8083
|
// Other services use handlerFunction as the entrypoint variable name.
|
|
7780
8084
|
varName: service && (0, import_build_utils13.isScheduleTriggeredService)(service) ? void 0 : handlerFunction
|
|
7781
8085
|
} : void 0,
|
|
7782
|
-
service
|
|
8086
|
+
service,
|
|
8087
|
+
opts.repoRootPath
|
|
7783
8088
|
);
|
|
7784
8089
|
let hookResult;
|
|
7785
8090
|
if (detected?.entrypoint) {
|
|
@@ -7893,7 +8198,11 @@ If you are using a virtual environment, activate it before running "vercel dev",
|
|
|
7893
8198
|
} else {
|
|
7894
8199
|
console.log(syncMessage);
|
|
7895
8200
|
}
|
|
7896
|
-
await
|
|
8201
|
+
await dedupePendingOperation(
|
|
8202
|
+
PENDING_DEPENDENCY_SYNCS,
|
|
8203
|
+
workPath,
|
|
8204
|
+
() => syncDependencies(devOpts)
|
|
8205
|
+
);
|
|
7897
8206
|
}
|
|
7898
8207
|
await installInjectedDevPackage(
|
|
7899
8208
|
{
|
|
@@ -8584,11 +8893,55 @@ async function runDjangoCollectStatic(venvPath, workPath, djangoPath, env, outpu
|
|
|
8584
8893
|
var import_python_analysis9 = require("@vercel/python-analysis");
|
|
8585
8894
|
|
|
8586
8895
|
// src/subscribers.ts
|
|
8896
|
+
var import_path15 = require("path");
|
|
8897
|
+
var import_fs15 = __toESM(require("fs"));
|
|
8898
|
+
var import_build_utils18 = require("@vercel/build-utils");
|
|
8899
|
+
|
|
8900
|
+
// src/module-entrypoint.ts
|
|
8587
8901
|
var import_path14 = require("path");
|
|
8588
8902
|
var import_fs14 = __toESM(require("fs"));
|
|
8589
|
-
var import_build_utils18 = require("@vercel/build-utils");
|
|
8590
|
-
var SUBSCRIBER_NAME_RE = /^[A-Za-z]([A-Za-z0-9_-]*[A-Za-z0-9])?$/;
|
|
8591
8903
|
var MODULE_ATTR_RE = /^([A-Za-z_][\w]*(?:\.[A-Za-z_][\w]*)*):([A-Za-z_][\w]*)$/;
|
|
8904
|
+
function parseModuleEntrypoint(value) {
|
|
8905
|
+
const match = MODULE_ATTR_RE.exec(value);
|
|
8906
|
+
if (!match) {
|
|
8907
|
+
return null;
|
|
8908
|
+
}
|
|
8909
|
+
return {
|
|
8910
|
+
moduleName: match[1],
|
|
8911
|
+
variableName: match[2],
|
|
8912
|
+
filePath: `${match[1].replace(/\./g, "/")}.py`
|
|
8913
|
+
};
|
|
8914
|
+
}
|
|
8915
|
+
function getModuleEntrypointName({
|
|
8916
|
+
moduleName,
|
|
8917
|
+
variableName
|
|
8918
|
+
}) {
|
|
8919
|
+
return `${moduleName.replace(/\./g, "-")}_${variableName}`;
|
|
8920
|
+
}
|
|
8921
|
+
function safePathSegment(value) {
|
|
8922
|
+
return [...value].map((char) => {
|
|
8923
|
+
if (char === "_") {
|
|
8924
|
+
return "__";
|
|
8925
|
+
}
|
|
8926
|
+
return /[A-Za-z0-9-]/.test(char) ? char : `_${char.charCodeAt(0).toString(16).toUpperCase().padStart(2, "0")}`;
|
|
8927
|
+
}).join("");
|
|
8928
|
+
}
|
|
8929
|
+
async function resolveExistingEntrypoint(workPath, filePath) {
|
|
8930
|
+
const candidates = [filePath, filePath.replace(/\.py$/i, "/__init__.py")];
|
|
8931
|
+
for (const candidate of candidates) {
|
|
8932
|
+
try {
|
|
8933
|
+
const stat = await import_fs14.default.promises.stat((0, import_path14.join)(workPath, candidate));
|
|
8934
|
+
if (stat.isFile()) {
|
|
8935
|
+
return candidate;
|
|
8936
|
+
}
|
|
8937
|
+
} catch {
|
|
8938
|
+
}
|
|
8939
|
+
}
|
|
8940
|
+
return null;
|
|
8941
|
+
}
|
|
8942
|
+
|
|
8943
|
+
// src/subscribers.ts
|
|
8944
|
+
var SUBSCRIBER_OUTPUT_DIR = "_py_subscribers";
|
|
8592
8945
|
var TRIGGER_NUMBER_FIELDS = [
|
|
8593
8946
|
{
|
|
8594
8947
|
field: "max_deliveries",
|
|
@@ -8620,17 +8973,15 @@ var SUBSCRIBER_FIELD_NAMES = /* @__PURE__ */ new Set([
|
|
|
8620
8973
|
"topics",
|
|
8621
8974
|
...TRIGGER_NUMBER_FIELDS.map(({ field }) => field)
|
|
8622
8975
|
]);
|
|
8623
|
-
function
|
|
8624
|
-
return
|
|
8625
|
-
|
|
8626
|
-
|
|
8627
|
-
|
|
8628
|
-
return /[A-Za-z0-9-]/.test(char) ? char : `_${char.charCodeAt(0).toString(16).toUpperCase().padStart(2, "0")}`;
|
|
8629
|
-
}).join("");
|
|
8976
|
+
function getSubscriberOutputPath(subscriberName) {
|
|
8977
|
+
return `${SUBSCRIBER_OUTPUT_DIR}/${safePathSegment(subscriberName)}`;
|
|
8978
|
+
}
|
|
8979
|
+
function getSubscriberConsumerName(subscriberName) {
|
|
8980
|
+
return (0, import_build_utils18.sanitizeConsumerName)(getSubscriberOutputPath(subscriberName));
|
|
8630
8981
|
}
|
|
8631
8982
|
async function getPyprojectSubscribers(workPath) {
|
|
8632
|
-
const pyprojectPath = (0,
|
|
8633
|
-
if (!
|
|
8983
|
+
const pyprojectPath = (0, import_path15.join)(workPath, "pyproject.toml");
|
|
8984
|
+
if (!import_fs15.default.existsSync(pyprojectPath)) {
|
|
8634
8985
|
return [];
|
|
8635
8986
|
}
|
|
8636
8987
|
const pyproject = await (0, import_build_utils18.readConfigFile)(pyprojectPath);
|
|
@@ -8638,37 +8989,43 @@ async function getPyprojectSubscribers(workPath) {
|
|
|
8638
8989
|
if (!subscribers) {
|
|
8639
8990
|
return [];
|
|
8640
8991
|
}
|
|
8641
|
-
if (
|
|
8642
|
-
throw subscriberError('"tool.vercel.subscribers" must be an
|
|
8992
|
+
if (!Array.isArray(subscribers)) {
|
|
8993
|
+
throw subscriberError('"tool.vercel.subscribers" must be an array');
|
|
8643
8994
|
}
|
|
8644
|
-
|
|
8645
|
-
|
|
8646
|
-
([name, config]) => parseSubscriber(workPath, name, config)
|
|
8647
|
-
)
|
|
8995
|
+
const parsedSubscribers = await Promise.all(
|
|
8996
|
+
subscribers.map((config, index) => parseSubscriber(workPath, index, config))
|
|
8648
8997
|
);
|
|
8649
|
-
|
|
8650
|
-
|
|
8651
|
-
|
|
8652
|
-
|
|
8653
|
-
|
|
8654
|
-
|
|
8998
|
+
const seenNames = /* @__PURE__ */ new Set();
|
|
8999
|
+
for (const subscriber of parsedSubscribers) {
|
|
9000
|
+
if (seenNames.has(subscriber.name)) {
|
|
9001
|
+
throw subscriberError(
|
|
9002
|
+
`subscriber "${subscriber.name}" is declared more than once`
|
|
9003
|
+
);
|
|
9004
|
+
}
|
|
9005
|
+
seenNames.add(subscriber.name);
|
|
8655
9006
|
}
|
|
9007
|
+
return parsedSubscribers;
|
|
9008
|
+
}
|
|
9009
|
+
async function parseSubscriber(workPath, index, config) {
|
|
9010
|
+
const label = `subscriber #${index + 1}`;
|
|
8656
9011
|
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
8657
|
-
throw subscriberError(
|
|
9012
|
+
throw subscriberError(`${label} must be an object`);
|
|
8658
9013
|
}
|
|
8659
9014
|
for (const key of Object.keys(config)) {
|
|
8660
9015
|
if (!SUBSCRIBER_FIELD_NAMES.has(key)) {
|
|
8661
|
-
throw subscriberError(
|
|
8662
|
-
`subscriber "${name}" has unrecognized field "${key}"`
|
|
8663
|
-
);
|
|
9016
|
+
throw subscriberError(`${label} has unrecognized field "${key}"`);
|
|
8664
9017
|
}
|
|
8665
9018
|
}
|
|
8666
9019
|
if (typeof config.entrypoint !== "string") {
|
|
9020
|
+
throw subscriberError(`${label} must define string field "entrypoint"`);
|
|
9021
|
+
}
|
|
9022
|
+
const entrypoint = parseModuleEntrypoint(config.entrypoint);
|
|
9023
|
+
if (!entrypoint) {
|
|
8667
9024
|
throw subscriberError(
|
|
8668
|
-
|
|
9025
|
+
`${label} has invalid entrypoint "${config.entrypoint}". Use "module:object"`
|
|
8669
9026
|
);
|
|
8670
9027
|
}
|
|
8671
|
-
const
|
|
9028
|
+
const name = getModuleEntrypointName(entrypoint);
|
|
8672
9029
|
const existingEntrypoint = await resolveExistingEntrypoint(
|
|
8673
9030
|
workPath,
|
|
8674
9031
|
entrypoint.filePath
|
|
@@ -8687,32 +9044,6 @@ async function parseSubscriber(workPath, name, config) {
|
|
|
8687
9044
|
triggerDefaults: parseTriggerDefaults(name, config)
|
|
8688
9045
|
};
|
|
8689
9046
|
}
|
|
8690
|
-
function parseEntrypoint(name, value) {
|
|
8691
|
-
const match = MODULE_ATTR_RE.exec(value);
|
|
8692
|
-
if (!match) {
|
|
8693
|
-
throw subscriberError(
|
|
8694
|
-
`subscriber "${name}" has invalid entrypoint "${value}". Use "module:object"`
|
|
8695
|
-
);
|
|
8696
|
-
}
|
|
8697
|
-
return {
|
|
8698
|
-
moduleName: match[1],
|
|
8699
|
-
variableName: match[2],
|
|
8700
|
-
filePath: `${match[1].replace(/\./g, "/")}.py`
|
|
8701
|
-
};
|
|
8702
|
-
}
|
|
8703
|
-
async function resolveExistingEntrypoint(workPath, filePath) {
|
|
8704
|
-
const candidates = [filePath, filePath.replace(/\.py$/i, "/__init__.py")];
|
|
8705
|
-
for (const candidate of candidates) {
|
|
8706
|
-
try {
|
|
8707
|
-
const stat = await import_fs14.default.promises.stat((0, import_path14.join)(workPath, candidate));
|
|
8708
|
-
if (stat.isFile()) {
|
|
8709
|
-
return candidate;
|
|
8710
|
-
}
|
|
8711
|
-
} catch {
|
|
8712
|
-
}
|
|
8713
|
-
}
|
|
8714
|
-
return null;
|
|
8715
|
-
}
|
|
8716
9047
|
function parseTopics(name, value) {
|
|
8717
9048
|
if (!Array.isArray(value) || value.length === 0) {
|
|
8718
9049
|
throw subscriberError(
|
|
@@ -8751,10 +9082,145 @@ function subscriberError(message) {
|
|
|
8751
9082
|
});
|
|
8752
9083
|
}
|
|
8753
9084
|
|
|
9085
|
+
// src/workflows.ts
|
|
9086
|
+
var import_path16 = require("path");
|
|
9087
|
+
var import_fs16 = __toESM(require("fs"));
|
|
9088
|
+
var import_build_utils19 = require("@vercel/build-utils");
|
|
9089
|
+
var WORKFLOW_OUTPUT_DIR = "_py_workflows";
|
|
9090
|
+
var WORKFLOW_TOPIC_PATTERN = "__wkf_*";
|
|
9091
|
+
var WORKFLOW_FIELD_NAMES = /* @__PURE__ */ new Set(["entrypoint"]);
|
|
9092
|
+
function getWorkflowOutputPath(workflowName) {
|
|
9093
|
+
return `${WORKFLOW_OUTPUT_DIR}/${safePathSegment(workflowName)}`;
|
|
9094
|
+
}
|
|
9095
|
+
function getWorkflowConsumerName(workflowName) {
|
|
9096
|
+
return (0, import_build_utils19.sanitizeConsumerName)(getWorkflowOutputPath(workflowName));
|
|
9097
|
+
}
|
|
9098
|
+
async function getPyprojectWorkflows(workPath) {
|
|
9099
|
+
const pyprojectPath = (0, import_path16.join)(workPath, "pyproject.toml");
|
|
9100
|
+
if (!import_fs16.default.existsSync(pyprojectPath)) {
|
|
9101
|
+
return [];
|
|
9102
|
+
}
|
|
9103
|
+
const pyproject = await (0, import_build_utils19.readConfigFile)(pyprojectPath);
|
|
9104
|
+
const workflows = pyproject?.tool?.vercel?.workflows;
|
|
9105
|
+
if (!workflows) {
|
|
9106
|
+
return [];
|
|
9107
|
+
}
|
|
9108
|
+
if (!Array.isArray(workflows)) {
|
|
9109
|
+
throw workflowError('"tool.vercel.workflows" must be an array');
|
|
9110
|
+
}
|
|
9111
|
+
if (workflows.length > 1) {
|
|
9112
|
+
throw workflowError(
|
|
9113
|
+
'"tool.vercel.workflows" must declare a single entrypoint that registers every workflow'
|
|
9114
|
+
);
|
|
9115
|
+
}
|
|
9116
|
+
return Promise.all(
|
|
9117
|
+
workflows.map((config, index) => parseWorkflow(workPath, index, config))
|
|
9118
|
+
);
|
|
9119
|
+
}
|
|
9120
|
+
async function parseWorkflow(workPath, index, config) {
|
|
9121
|
+
const label = `workflow #${index + 1}`;
|
|
9122
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
9123
|
+
throw workflowError(`${label} must be an object`);
|
|
9124
|
+
}
|
|
9125
|
+
for (const key of Object.keys(config)) {
|
|
9126
|
+
if (!WORKFLOW_FIELD_NAMES.has(key)) {
|
|
9127
|
+
throw workflowError(`${label} has unrecognized field "${key}"`);
|
|
9128
|
+
}
|
|
9129
|
+
}
|
|
9130
|
+
if (typeof config.entrypoint !== "string") {
|
|
9131
|
+
throw workflowError(`${label} must define string field "entrypoint"`);
|
|
9132
|
+
}
|
|
9133
|
+
const entrypoint = parseModuleEntrypoint(config.entrypoint);
|
|
9134
|
+
if (!entrypoint) {
|
|
9135
|
+
throw workflowError(
|
|
9136
|
+
`${label} has invalid entrypoint "${config.entrypoint}". Use "module:object"`
|
|
9137
|
+
);
|
|
9138
|
+
}
|
|
9139
|
+
const name = getModuleEntrypointName(entrypoint);
|
|
9140
|
+
const existingEntrypoint = await resolveExistingEntrypoint(
|
|
9141
|
+
workPath,
|
|
9142
|
+
entrypoint.filePath
|
|
9143
|
+
);
|
|
9144
|
+
if (!existingEntrypoint) {
|
|
9145
|
+
throw workflowError(
|
|
9146
|
+
`workflow "${name}" has entrypoint "${config.entrypoint}" but file "${entrypoint.filePath}" does not exist`
|
|
9147
|
+
);
|
|
9148
|
+
}
|
|
9149
|
+
return {
|
|
9150
|
+
name,
|
|
9151
|
+
entrypoint: existingEntrypoint,
|
|
9152
|
+
moduleName: entrypoint.moduleName,
|
|
9153
|
+
variableName: entrypoint.variableName
|
|
9154
|
+
};
|
|
9155
|
+
}
|
|
9156
|
+
function workflowError(message) {
|
|
9157
|
+
return new import_build_utils19.NowBuildError({
|
|
9158
|
+
code: "PYTHON_INVALID_WORKFLOW_CONFIG",
|
|
9159
|
+
message
|
|
9160
|
+
});
|
|
9161
|
+
}
|
|
9162
|
+
|
|
8754
9163
|
// src/index.ts
|
|
8755
|
-
var writeFile =
|
|
9164
|
+
var writeFile = import_fs17.default.promises.writeFile;
|
|
8756
9165
|
var PYTHON_ENTRYPOINT_DOCS_URL2 = "https://vercel.com/docs/functions/runtimes/python#python-entrypoints";
|
|
8757
9166
|
var version = -1;
|
|
9167
|
+
function getDevSubscriberTopics(subscriber) {
|
|
9168
|
+
const { retryAfterSeconds, initialDelaySeconds } = subscriber.triggerDefaults;
|
|
9169
|
+
return subscriber.topics.map((topic) => ({
|
|
9170
|
+
topic,
|
|
9171
|
+
...retryAfterSeconds === void 0 ? {} : { retryAfterSeconds },
|
|
9172
|
+
...initialDelaySeconds === void 0 ? {} : { initialDelaySeconds }
|
|
9173
|
+
}));
|
|
9174
|
+
}
|
|
9175
|
+
async function getDevSidecars({
|
|
9176
|
+
workPath,
|
|
9177
|
+
build: build2
|
|
9178
|
+
}) {
|
|
9179
|
+
const framework = build2.config?.framework;
|
|
9180
|
+
if (build2.config?.middleware === true || typeof framework !== "string" || !(0, import_build_utils20.isPythonFramework)(framework)) {
|
|
9181
|
+
return [];
|
|
9182
|
+
}
|
|
9183
|
+
const subscribers = await getPyprojectSubscribers(workPath);
|
|
9184
|
+
const workflows = await getPyprojectWorkflows(workPath);
|
|
9185
|
+
return [
|
|
9186
|
+
...subscribers.map(
|
|
9187
|
+
(subscriber) => ({
|
|
9188
|
+
type: "subscriber",
|
|
9189
|
+
name: subscriber.name,
|
|
9190
|
+
consumer: getSubscriberConsumerName(subscriber.name),
|
|
9191
|
+
workspace: ".",
|
|
9192
|
+
framework,
|
|
9193
|
+
runtime: "python",
|
|
9194
|
+
builder: {
|
|
9195
|
+
use: build2.use,
|
|
9196
|
+
src: subscriber.entrypoint,
|
|
9197
|
+
config: {
|
|
9198
|
+
handlerFunction: subscriber.variableName
|
|
9199
|
+
}
|
|
9200
|
+
},
|
|
9201
|
+
topics: getDevSubscriberTopics(subscriber)
|
|
9202
|
+
})
|
|
9203
|
+
),
|
|
9204
|
+
...workflows.map(
|
|
9205
|
+
(workflow) => ({
|
|
9206
|
+
type: "subscriber",
|
|
9207
|
+
name: workflow.name,
|
|
9208
|
+
consumer: getWorkflowConsumerName(workflow.name),
|
|
9209
|
+
workspace: ".",
|
|
9210
|
+
framework,
|
|
9211
|
+
runtime: "python",
|
|
9212
|
+
builder: {
|
|
9213
|
+
use: build2.use,
|
|
9214
|
+
src: workflow.entrypoint,
|
|
9215
|
+
config: {
|
|
9216
|
+
handlerFunction: workflow.variableName
|
|
9217
|
+
}
|
|
9218
|
+
},
|
|
9219
|
+
topics: [{ topic: WORKFLOW_TOPIC_PATTERN }]
|
|
9220
|
+
})
|
|
9221
|
+
)
|
|
9222
|
+
];
|
|
9223
|
+
}
|
|
8758
9224
|
function addFiles(target, source) {
|
|
8759
9225
|
for (const [p, f] of Object.entries(source)) {
|
|
8760
9226
|
target[p] = f;
|
|
@@ -8803,6 +9269,54 @@ async function addVendorBytecodeWithinCapacity({
|
|
|
8803
9269
|
addFiles(files, selectedBytecode.files);
|
|
8804
9270
|
return capacity - selectedBytecode.totalSize;
|
|
8805
9271
|
}
|
|
9272
|
+
async function addVendorBytecodeInTiers({
|
|
9273
|
+
files,
|
|
9274
|
+
depExternalizer,
|
|
9275
|
+
vendorDir,
|
|
9276
|
+
capacity,
|
|
9277
|
+
vendorPackageTiers
|
|
9278
|
+
}) {
|
|
9279
|
+
let remainingCapacity = capacity;
|
|
9280
|
+
for (const tier of vendorPackageTiers) {
|
|
9281
|
+
if (remainingCapacity <= 0)
|
|
9282
|
+
break;
|
|
9283
|
+
if (tier && tier.length === 0)
|
|
9284
|
+
continue;
|
|
9285
|
+
const bytecodeInfo = await depExternalizer.collectBytecodeFiles({
|
|
9286
|
+
vendorDirName: vendorDir,
|
|
9287
|
+
includePackages: tier
|
|
9288
|
+
});
|
|
9289
|
+
remainingCapacity = await addVendorBytecodeWithinCapacity({
|
|
9290
|
+
files,
|
|
9291
|
+
depExternalizer,
|
|
9292
|
+
vendorDir,
|
|
9293
|
+
bytecodeInfo,
|
|
9294
|
+
capacity: remainingCapacity
|
|
9295
|
+
});
|
|
9296
|
+
}
|
|
9297
|
+
return remainingCapacity;
|
|
9298
|
+
}
|
|
9299
|
+
async function addCollectedVendorBytecode({
|
|
9300
|
+
files,
|
|
9301
|
+
capacity,
|
|
9302
|
+
collect
|
|
9303
|
+
}) {
|
|
9304
|
+
if (capacity <= 0)
|
|
9305
|
+
return capacity;
|
|
9306
|
+
const info = await collect(void 0);
|
|
9307
|
+
if (!info || info.totalSize <= 0)
|
|
9308
|
+
return capacity;
|
|
9309
|
+
if (info.totalSize <= capacity) {
|
|
9310
|
+
addFiles(files, info.files);
|
|
9311
|
+
return capacity - info.totalSize;
|
|
9312
|
+
}
|
|
9313
|
+
const selected = lambdaKnapsack(info.perItemSizes, capacity);
|
|
9314
|
+
if (selected.length === 0)
|
|
9315
|
+
return capacity;
|
|
9316
|
+
const selectedInfo = await collect(selected);
|
|
9317
|
+
addFiles(files, selectedInfo.files);
|
|
9318
|
+
return capacity - selectedInfo.totalSize;
|
|
9319
|
+
}
|
|
8806
9320
|
async function runFrameworkHook(framework, ctx) {
|
|
8807
9321
|
const hook = framework ? frameworkHooks[framework] : void 0;
|
|
8808
9322
|
return hook?.(ctx);
|
|
@@ -8816,13 +9330,13 @@ var frameworkHooks = {
|
|
|
8816
9330
|
}) => {
|
|
8817
9331
|
let baseDir = detected?.baseDir;
|
|
8818
9332
|
if (baseDir === void 0) {
|
|
8819
|
-
if (!
|
|
8820
|
-
(0,
|
|
9333
|
+
if (!import_fs17.default.existsSync((0, import_path17.join)(workPath, "manage.py"))) {
|
|
9334
|
+
(0, import_build_utils20.debug)("Django hook: no manage.py detected, skipping");
|
|
8821
9335
|
return;
|
|
8822
9336
|
}
|
|
8823
9337
|
baseDir = "";
|
|
8824
9338
|
}
|
|
8825
|
-
const djangoPath = (0,
|
|
9339
|
+
const djangoPath = (0, import_path17.join)(workPath, baseDir);
|
|
8826
9340
|
let settingsResult;
|
|
8827
9341
|
try {
|
|
8828
9342
|
settingsResult = await getDjangoSettings(djangoPath, pythonEnv);
|
|
@@ -8834,13 +9348,13 @@ Hint: activate a venv or run with \`uv run vercel dev\``;
|
|
|
8834
9348
|
} else {
|
|
8835
9349
|
detail = err?.stderr || err?.message || String(err);
|
|
8836
9350
|
}
|
|
8837
|
-
throw new
|
|
9351
|
+
throw new import_build_utils20.NowBuildError({
|
|
8838
9352
|
code: "DJANGO_SETTINGS_FAILED",
|
|
8839
9353
|
message: `Failed to read Django application settings from ${djangoPath}/manage.py:
|
|
8840
9354
|
${detail}`
|
|
8841
9355
|
});
|
|
8842
9356
|
}
|
|
8843
|
-
(0,
|
|
9357
|
+
(0, import_build_utils20.debug)(`Django settings: ${JSON.stringify(settingsResult)}`);
|
|
8844
9358
|
const { djangoSettings, settingsModule, djangoVersion } = settingsResult;
|
|
8845
9359
|
if (djangoVersion) {
|
|
8846
9360
|
console.log(`Django ${djangoVersion.join(".")} detected`);
|
|
@@ -8852,7 +9366,7 @@ ${detail}`
|
|
|
8852
9366
|
const variableName = parts.at(-1);
|
|
8853
9367
|
const rel = `${parts.slice(0, -1).join("/")}.py`;
|
|
8854
9368
|
const ep = baseDir ? `${baseDir}/${rel}` : rel;
|
|
8855
|
-
(0,
|
|
9369
|
+
(0, import_build_utils20.debug)(`Django hook: ASGI entrypoint: ${ep} (variable: ${variableName})`);
|
|
8856
9370
|
resolvedEntrypoint = { entrypoint: ep, variableName };
|
|
8857
9371
|
} else {
|
|
8858
9372
|
const wsgiApp = djangoSettings["WSGI_APPLICATION"];
|
|
@@ -8861,7 +9375,7 @@ ${detail}`
|
|
|
8861
9375
|
const variableName = parts.at(-1);
|
|
8862
9376
|
const rel = `${parts.slice(0, -1).join("/")}.py`;
|
|
8863
9377
|
const ep = baseDir ? `${baseDir}/${rel}` : rel;
|
|
8864
|
-
(0,
|
|
9378
|
+
(0, import_build_utils20.debug)(
|
|
8865
9379
|
`Django hook: WSGI entrypoint: ${ep} (variable: ${variableName})`
|
|
8866
9380
|
);
|
|
8867
9381
|
resolvedEntrypoint = { entrypoint: ep, variableName };
|
|
@@ -8869,7 +9383,7 @@ ${detail}`
|
|
|
8869
9383
|
}
|
|
8870
9384
|
let djangoStatic = null;
|
|
8871
9385
|
if (workPath && venvPath) {
|
|
8872
|
-
const outputStaticDir = (0,
|
|
9386
|
+
const outputStaticDir = (0, import_path17.join)(workPath, ".vercel", "output", "static");
|
|
8873
9387
|
djangoStatic = await runDjangoCollectStatic(
|
|
8874
9388
|
venvPath,
|
|
8875
9389
|
workPath,
|
|
@@ -8884,7 +9398,7 @@ ${detail}`
|
|
|
8884
9398
|
return {
|
|
8885
9399
|
entrypoint: resolvedEntrypoint,
|
|
8886
9400
|
djangoStatic,
|
|
8887
|
-
extraPythonPath: baseDir ? (0,
|
|
9401
|
+
extraPythonPath: baseDir ? (0, import_path17.join)(workPath, baseDir) : void 0
|
|
8888
9402
|
};
|
|
8889
9403
|
}
|
|
8890
9404
|
};
|
|
@@ -8943,23 +9457,23 @@ async function downloadFilesInWorkPath({
|
|
|
8943
9457
|
files,
|
|
8944
9458
|
meta = {}
|
|
8945
9459
|
}) {
|
|
8946
|
-
(0,
|
|
8947
|
-
let downloadedFiles = await (0,
|
|
9460
|
+
(0, import_build_utils20.debug)("Downloading user files...");
|
|
9461
|
+
let downloadedFiles = await (0, import_build_utils20.download)(files, workPath, meta);
|
|
8948
9462
|
if (meta.isDev && entrypoint) {
|
|
8949
9463
|
const normalizedEntrypoint = entrypoint.endsWith(".py") ? entrypoint : `${entrypoint}.py`;
|
|
8950
9464
|
if (!hasProp(downloadedFiles, entrypoint) && !hasProp(downloadedFiles, normalizedEntrypoint)) {
|
|
8951
|
-
throw new
|
|
9465
|
+
throw new import_build_utils20.NowBuildError({
|
|
8952
9466
|
code: "PYTHON_ENTRYPOINT_NOT_FOUND",
|
|
8953
9467
|
message: `Configured Python entrypoint "${normalizedEntrypoint}" was not found.`,
|
|
8954
9468
|
link: PYTHON_ENTRYPOINT_DOCS_URL2,
|
|
8955
9469
|
action: "Learn More"
|
|
8956
9470
|
});
|
|
8957
9471
|
}
|
|
8958
|
-
const { devCacheDir = (0,
|
|
8959
|
-
const cacheKey = (0,
|
|
8960
|
-
const destCache = (0,
|
|
8961
|
-
await (0,
|
|
8962
|
-
downloadedFiles = await (0,
|
|
9472
|
+
const { devCacheDir = (0, import_path17.join)(workPath, ".now", "cache") } = meta;
|
|
9473
|
+
const cacheKey = (0, import_path17.basename)(entrypoint).replace(/\./g, "_");
|
|
9474
|
+
const destCache = (0, import_path17.join)(devCacheDir, cacheKey);
|
|
9475
|
+
await (0, import_build_utils20.download)(downloadedFiles, destCache);
|
|
9476
|
+
downloadedFiles = await (0, import_build_utils20.glob)("**", destCache);
|
|
8963
9477
|
workPath = destCache;
|
|
8964
9478
|
}
|
|
8965
9479
|
return workPath;
|
|
@@ -8995,7 +9509,7 @@ async function getPythonLambdaOptions({
|
|
|
8995
9509
|
sources.add(entrypoint.slice(0, -".py".length));
|
|
8996
9510
|
}
|
|
8997
9511
|
for (const sourceFile of sources) {
|
|
8998
|
-
const lambdaOptions = await (0,
|
|
9512
|
+
const lambdaOptions = await (0, import_build_utils20.getLambdaOptionsFromFunction)({
|
|
8999
9513
|
sourceFile,
|
|
9000
9514
|
config
|
|
9001
9515
|
});
|
|
@@ -9015,11 +9529,11 @@ async function installInjectedPackage({
|
|
|
9015
9529
|
projectDir,
|
|
9016
9530
|
pipPlatformArgs
|
|
9017
9531
|
}) {
|
|
9018
|
-
const localDir = (0,
|
|
9019
|
-
const isLocalDev =
|
|
9532
|
+
const localDir = (0, import_path17.join)(__dirname, "..", "..", "..", "python", name);
|
|
9533
|
+
const isLocalDev = import_fs17.default.existsSync((0, import_path17.join)(localDir, "pyproject.toml"));
|
|
9020
9534
|
const dep = envOverride || (isLocalDev ? localDir : pinned);
|
|
9021
9535
|
const noExclude = ["--exclude-newer-package", `${name}=false`];
|
|
9022
|
-
(0,
|
|
9536
|
+
(0, import_build_utils20.debug)(`Installing ${dep}`);
|
|
9023
9537
|
await uv.pip({
|
|
9024
9538
|
venvPath,
|
|
9025
9539
|
projectDir,
|
|
@@ -9045,29 +9559,37 @@ var build = async ({
|
|
|
9045
9559
|
registerPreDeploy
|
|
9046
9560
|
}) => {
|
|
9047
9561
|
let entrypoint = rawEntrypoint === "<detect>" ? void 0 : rawEntrypoint;
|
|
9048
|
-
const
|
|
9562
|
+
const isPyprojectEntrypoint = entrypoint !== void 0 && (0, import_path17.basename)(entrypoint) === "pyproject.toml";
|
|
9563
|
+
if (isPyprojectEntrypoint && entrypoint !== "pyproject.toml") {
|
|
9564
|
+
throw new import_build_utils20.NowBuildError({
|
|
9565
|
+
code: "PYTHON_INVALID_PYPROJECT_ENTRYPOINT",
|
|
9566
|
+
message: `A "pyproject.toml" entrypoint must sit at the service root. Set the service "root" to "${(0, import_path17.dirname)(entrypoint)}" and use entrypoint "pyproject.toml".`
|
|
9567
|
+
});
|
|
9568
|
+
}
|
|
9569
|
+
const builderSpan = parentSpan ?? new import_build_utils20.Span({ name: "vc.builder" });
|
|
9049
9570
|
const framework = config?.framework;
|
|
9050
9571
|
let shouldInstallVercelWorkers = config?.hasWorkerServices === true;
|
|
9051
9572
|
let subscribers = [];
|
|
9573
|
+
let workflows = [];
|
|
9052
9574
|
let spawnEnv;
|
|
9053
9575
|
let projectInstallCommand;
|
|
9054
9576
|
let hasCustomCommand = false;
|
|
9055
|
-
let hasCustomBuildCommand = false;
|
|
9056
9577
|
const target = getTargetPlatform(meta.isDev ?? false);
|
|
9057
|
-
(0,
|
|
9578
|
+
(0, import_build_utils20.debug)(`workPath: ${workPath}`);
|
|
9058
9579
|
workPath = await downloadFilesInWorkPath({
|
|
9059
9580
|
workPath,
|
|
9060
9581
|
files: originalFiles,
|
|
9061
9582
|
entrypoint,
|
|
9062
9583
|
meta
|
|
9063
9584
|
});
|
|
9064
|
-
if (!service && (0,
|
|
9585
|
+
if (isPyprojectEntrypoint || !service && (0, import_build_utils20.isPythonFramework)(framework)) {
|
|
9065
9586
|
subscribers = await getPyprojectSubscribers(workPath);
|
|
9066
|
-
|
|
9587
|
+
workflows = await getPyprojectWorkflows(workPath);
|
|
9588
|
+
shouldInstallVercelWorkers ||= subscribers.length > 0 || workflows.length > 0;
|
|
9067
9589
|
}
|
|
9068
9590
|
try {
|
|
9069
9591
|
if (meta.isDev) {
|
|
9070
|
-
const setupCfg = (0,
|
|
9592
|
+
const setupCfg = (0, import_path17.join)(workPath, "setup.cfg");
|
|
9071
9593
|
await writeFile(setupCfg, "[install]\nprefix=\n");
|
|
9072
9594
|
}
|
|
9073
9595
|
} catch (err) {
|
|
@@ -9076,22 +9598,36 @@ var build = async ({
|
|
|
9076
9598
|
}
|
|
9077
9599
|
let detected;
|
|
9078
9600
|
const handlerFunction = typeof config?.handlerFunction === "string" ? config.handlerFunction : void 0;
|
|
9079
|
-
|
|
9080
|
-
|
|
9081
|
-
|
|
9082
|
-
|
|
9083
|
-
|
|
9084
|
-
|
|
9085
|
-
|
|
9086
|
-
|
|
9087
|
-
|
|
9088
|
-
|
|
9089
|
-
|
|
9601
|
+
if (isPyprojectEntrypoint) {
|
|
9602
|
+
const declared = await getVercelToolsEntrypoint(workPath, repoRootPath);
|
|
9603
|
+
if (declared) {
|
|
9604
|
+
detected = { entrypoint: declared };
|
|
9605
|
+
} else if (subscribers.length === 0 && workflows.length === 0) {
|
|
9606
|
+
throw new import_build_utils20.NowBuildError({
|
|
9607
|
+
code: "PYTHON_PYPROJECT_NOTHING_TO_BUILD",
|
|
9608
|
+
message: 'Entrypoint "pyproject.toml" declares nothing to build. Set "tool.vercel.entrypoint" for a web app and/or declare "[[tool.vercel.subscribers]]" or "[[tool.vercel.workflows]]" entries in pyproject.toml.'
|
|
9609
|
+
});
|
|
9610
|
+
}
|
|
9611
|
+
entrypoint = void 0;
|
|
9612
|
+
} else {
|
|
9613
|
+
detected = await detectPythonEntrypoint(
|
|
9614
|
+
config.framework,
|
|
9615
|
+
workPath,
|
|
9616
|
+
entrypoint ? {
|
|
9617
|
+
filePath: entrypoint,
|
|
9618
|
+
// For schedule-triggered jobs, the WSGI variable is always 'app' (created dynamically).
|
|
9619
|
+
// For other services, handlerFunction is used as the entrypoint variable name.
|
|
9620
|
+
varName: service && (0, import_build_utils20.isScheduleTriggeredService)(service) ? void 0 : handlerFunction
|
|
9621
|
+
} : void 0,
|
|
9622
|
+
service,
|
|
9623
|
+
repoRootPath
|
|
9624
|
+
) ?? void 0;
|
|
9625
|
+
}
|
|
9090
9626
|
if (detected?.error && detected?.baseDir === void 0) {
|
|
9091
9627
|
throw detected?.error;
|
|
9092
9628
|
}
|
|
9093
|
-
const entryDirectory = detected?.baseDir ?? (entrypoint ? (0,
|
|
9094
|
-
const entrypointAbsDir = (0,
|
|
9629
|
+
const entryDirectory = detected?.baseDir ?? (entrypoint ? (0, import_path17.dirname)(entrypoint) : ".");
|
|
9630
|
+
const entrypointAbsDir = (0, import_path17.join)(workPath, entryDirectory);
|
|
9095
9631
|
const rootDir = repoRootPath ?? workPath;
|
|
9096
9632
|
const pythonPackage = await builderSpan.child("vc.builder.python.discover").trace(
|
|
9097
9633
|
() => discoverPackage({
|
|
@@ -9132,12 +9668,12 @@ var build = async ({
|
|
|
9132
9668
|
}
|
|
9133
9669
|
const uvVersion = checkUvBinaryVersion(uv.getPath());
|
|
9134
9670
|
console.log(`Using ${uvVersion}`);
|
|
9135
|
-
const venvPath = service?.name ? (0,
|
|
9136
|
-
const hasCachedVenv =
|
|
9137
|
-
const hasCachedUv =
|
|
9671
|
+
const venvPath = service?.name ? (0, import_path17.join)(workPath, ".vercel", "python", "services", service.name, ".venv") : (0, import_path17.join)(workPath, ".vercel", "python", ".venv");
|
|
9672
|
+
const hasCachedVenv = import_fs17.default.existsSync((0, import_path17.join)(venvPath, "pyvenv.cfg"));
|
|
9673
|
+
const hasCachedUv = import_fs17.default.existsSync(uvCacheDir);
|
|
9138
9674
|
const restoredCache = hasCachedVenv && hasCachedUv ? "both" : hasCachedVenv ? "venv" : hasCachedUv ? "uv" : "none";
|
|
9139
9675
|
if (hasCachedVenv || hasCachedUv) {
|
|
9140
|
-
(0,
|
|
9676
|
+
(0, import_build_utils20.debug)(
|
|
9141
9677
|
`Build cache detected: venv=${hasCachedVenv}, uv-cache=${hasCachedUv}`
|
|
9142
9678
|
);
|
|
9143
9679
|
}
|
|
@@ -9149,14 +9685,14 @@ var build = async ({
|
|
|
9149
9685
|
uvCacheDir
|
|
9150
9686
|
});
|
|
9151
9687
|
});
|
|
9152
|
-
if ((0,
|
|
9688
|
+
if ((0, import_build_utils20.isPythonFramework)(framework)) {
|
|
9153
9689
|
const {
|
|
9154
9690
|
cliType,
|
|
9155
9691
|
lockfileVersion,
|
|
9156
9692
|
packageJsonPackageManager,
|
|
9157
9693
|
turboSupportsCorepackHome
|
|
9158
|
-
} = await (0,
|
|
9159
|
-
spawnEnv = (0,
|
|
9694
|
+
} = await (0, import_build_utils20.scanParentDirs)(workPath, true);
|
|
9695
|
+
spawnEnv = (0, import_build_utils20.getEnvForPackageManager)({
|
|
9160
9696
|
cliType,
|
|
9161
9697
|
lockfileVersion,
|
|
9162
9698
|
packageJsonPackageManager,
|
|
@@ -9181,13 +9717,13 @@ var build = async ({
|
|
|
9181
9717
|
let uvLockPath = null;
|
|
9182
9718
|
let uvProjectDir = null;
|
|
9183
9719
|
let projectName;
|
|
9184
|
-
await builderSpan.child(
|
|
9720
|
+
await builderSpan.child(import_build_utils20.BUILDER_INSTALLER_STEP, {
|
|
9185
9721
|
installCommand: projectInstallCommand || void 0,
|
|
9186
9722
|
runtime: "python",
|
|
9187
9723
|
"python.cache.restored": restoredCache
|
|
9188
9724
|
}).trace(async () => {
|
|
9189
9725
|
if (projectInstallCommand) {
|
|
9190
|
-
await
|
|
9726
|
+
await import_fs17.default.promises.rm(venvPath, { recursive: true, force: true });
|
|
9191
9727
|
await ensureVenv({
|
|
9192
9728
|
pythonVersion,
|
|
9193
9729
|
venvPath,
|
|
@@ -9198,7 +9734,7 @@ var build = async ({
|
|
|
9198
9734
|
console.log(
|
|
9199
9735
|
`Running "install" command: \`${projectInstallCommand}\`...`
|
|
9200
9736
|
);
|
|
9201
|
-
await (0,
|
|
9737
|
+
await (0, import_build_utils20.execCommand)(projectInstallCommand, {
|
|
9202
9738
|
env: pythonEnv,
|
|
9203
9739
|
cwd: workPath
|
|
9204
9740
|
});
|
|
@@ -9219,7 +9755,7 @@ var build = async ({
|
|
|
9219
9755
|
}
|
|
9220
9756
|
if (!assumeDepsInstalled) {
|
|
9221
9757
|
const lockCacheKey = service?.name ? `uv.lock.${service.name}` : "uv.lock";
|
|
9222
|
-
const cachedLockPath = (0,
|
|
9758
|
+
const cachedLockPath = (0, import_path17.join)(uvCacheDir, lockCacheKey);
|
|
9223
9759
|
const { projectDir, lockPath, lockFileProvidedByUser } = await ensureUvProject({
|
|
9224
9760
|
workPath,
|
|
9225
9761
|
rootDir,
|
|
@@ -9240,34 +9776,30 @@ var build = async ({
|
|
|
9240
9776
|
locked: !lockFileProvidedByUser,
|
|
9241
9777
|
pythonPlatform: target.uvPlatform
|
|
9242
9778
|
});
|
|
9243
|
-
if (lockPath &&
|
|
9244
|
-
await
|
|
9245
|
-
await
|
|
9779
|
+
if (lockPath && import_fs17.default.existsSync(lockPath)) {
|
|
9780
|
+
await import_fs17.default.promises.mkdir(uvCacheDir, { recursive: true });
|
|
9781
|
+
await import_fs17.default.promises.copyFile(lockPath, cachedLockPath);
|
|
9246
9782
|
}
|
|
9247
9783
|
}
|
|
9248
9784
|
});
|
|
9249
|
-
if ((0,
|
|
9785
|
+
if ((0, import_build_utils20.isPythonFramework)(framework)) {
|
|
9250
9786
|
const projectBuildCommand = config?.projectSettings?.buildCommand ?? // fallback if provided directly on config (some callers set this)
|
|
9251
9787
|
config?.buildCommand;
|
|
9252
|
-
await builderSpan.child(
|
|
9788
|
+
await builderSpan.child(import_build_utils20.BUILDER_COMPILE_STEP, {
|
|
9253
9789
|
buildCommand: projectBuildCommand || void 0
|
|
9254
9790
|
}).trace(async () => {
|
|
9255
9791
|
if (projectBuildCommand) {
|
|
9256
9792
|
console.log(`Running "${projectBuildCommand}"`);
|
|
9257
|
-
await (0,
|
|
9793
|
+
await (0, import_build_utils20.execCommand)(projectBuildCommand, {
|
|
9258
9794
|
env: pythonEnv,
|
|
9259
9795
|
cwd: workPath
|
|
9260
9796
|
});
|
|
9261
|
-
hasCustomBuildCommand = true;
|
|
9262
9797
|
} else {
|
|
9263
|
-
|
|
9798
|
+
await runPyprojectScript(
|
|
9264
9799
|
workPath,
|
|
9265
9800
|
["vercel-build", "now-build", "build"],
|
|
9266
9801
|
pythonEnv
|
|
9267
9802
|
);
|
|
9268
|
-
if (ranBuildScript) {
|
|
9269
|
-
hasCustomBuildCommand = true;
|
|
9270
|
-
}
|
|
9271
9803
|
}
|
|
9272
9804
|
});
|
|
9273
9805
|
}
|
|
@@ -9278,13 +9810,14 @@ var build = async ({
|
|
|
9278
9810
|
entrypoint,
|
|
9279
9811
|
detected
|
|
9280
9812
|
});
|
|
9281
|
-
const resolved = hookResult?.entrypoint ?? detected?.entrypoint;
|
|
9813
|
+
const resolved = isPyprojectEntrypoint ? detected?.entrypoint : hookResult?.entrypoint ?? detected?.entrypoint;
|
|
9282
9814
|
if (!resolved && detected?.error) {
|
|
9283
9815
|
throw detected?.error;
|
|
9284
9816
|
}
|
|
9285
9817
|
entrypoint = resolved?.entrypoint;
|
|
9286
|
-
|
|
9287
|
-
|
|
9818
|
+
const isWorkersOnly = !entrypoint && isPyprojectEntrypoint && (subscribers.length > 0 || workflows.length > 0);
|
|
9819
|
+
if (!entrypoint && !isWorkersOnly) {
|
|
9820
|
+
throw new import_build_utils20.NowBuildError({
|
|
9288
9821
|
code: "PYTHON_ENTRYPOINT_NOT_FOUND",
|
|
9289
9822
|
message: "No Python entrypoint could be detected. Please specify an entrypoint file."
|
|
9290
9823
|
});
|
|
@@ -9297,7 +9830,7 @@ var build = async ({
|
|
|
9297
9830
|
envOverride: baseEnv.VERCEL_RUNTIME_PYTHON,
|
|
9298
9831
|
uv,
|
|
9299
9832
|
venvPath,
|
|
9300
|
-
projectDir: (0,
|
|
9833
|
+
projectDir: (0, import_path17.join)(workPath, entryDirectory),
|
|
9301
9834
|
pipPlatformArgs
|
|
9302
9835
|
});
|
|
9303
9836
|
if (shouldInstallVercelWorkers) {
|
|
@@ -9307,7 +9840,7 @@ var build = async ({
|
|
|
9307
9840
|
envOverride: baseEnv.VERCEL_WORKERS_PYTHON,
|
|
9308
9841
|
uv,
|
|
9309
9842
|
venvPath,
|
|
9310
|
-
projectDir: (0,
|
|
9843
|
+
projectDir: (0, import_path17.join)(workPath, entryDirectory),
|
|
9311
9844
|
pipPlatformArgs
|
|
9312
9845
|
});
|
|
9313
9846
|
}
|
|
@@ -9320,61 +9853,67 @@ var build = async ({
|
|
|
9320
9853
|
const capturedEnv = { ...pythonEnv };
|
|
9321
9854
|
const capturedCwd = workPath;
|
|
9322
9855
|
registerPreDeploy(async () => {
|
|
9323
|
-
await builderSpan.child(
|
|
9856
|
+
await builderSpan.child(import_build_utils20.BUILDER_PRE_DEPLOY_STEP, {
|
|
9324
9857
|
preDeployCommand
|
|
9325
9858
|
}).trace(async () => {
|
|
9326
9859
|
console.log(`Running pre-deploy command: \`${preDeployCommand}\``);
|
|
9327
|
-
await (0,
|
|
9860
|
+
await (0, import_build_utils20.execCommand)(preDeployCommand, {
|
|
9328
9861
|
env: capturedEnv,
|
|
9329
9862
|
cwd: capturedCwd
|
|
9330
9863
|
});
|
|
9331
9864
|
});
|
|
9332
9865
|
});
|
|
9333
9866
|
}
|
|
9334
|
-
|
|
9335
|
-
|
|
9336
|
-
|
|
9337
|
-
|
|
9338
|
-
|
|
9339
|
-
const
|
|
9340
|
-
if (
|
|
9341
|
-
|
|
9342
|
-
|
|
9343
|
-
|
|
9344
|
-
|
|
9867
|
+
const vendorDir = resolveVendorDir();
|
|
9868
|
+
let crons;
|
|
9869
|
+
let runtimeTrampoline;
|
|
9870
|
+
if (entrypoint) {
|
|
9871
|
+
(0, import_build_utils20.debug)("Entrypoint is", entrypoint);
|
|
9872
|
+
const moduleName = entrypointToModule(entrypoint);
|
|
9873
|
+
if (handlerFunction) {
|
|
9874
|
+
const entrypointPath = (0, import_path17.join)(workPath, entrypoint);
|
|
9875
|
+
const source = await import_fs17.default.promises.readFile(entrypointPath, "utf-8");
|
|
9876
|
+
const found = await (0, import_python_analysis9.containsTopLevelCallable)(source, handlerFunction);
|
|
9877
|
+
if (!found) {
|
|
9878
|
+
throw new import_build_utils20.NowBuildError({
|
|
9879
|
+
code: "PYTHON_HANDLER_NOT_FOUND",
|
|
9880
|
+
message: `Handler function "${handlerFunction}" not found in ${entrypoint}. Ensure it is defined at the module's top level.`
|
|
9881
|
+
});
|
|
9882
|
+
}
|
|
9345
9883
|
}
|
|
9884
|
+
const suffix = meta.isDev && !entrypoint.endsWith(".py") ? ".py" : "";
|
|
9885
|
+
const entrypointWithSuffix = `${entrypoint}${suffix}`;
|
|
9886
|
+
(0, import_build_utils20.debug)("Entrypoint with suffix is", entrypointWithSuffix);
|
|
9887
|
+
crons = await getServiceCrons({
|
|
9888
|
+
service,
|
|
9889
|
+
entrypoint,
|
|
9890
|
+
rawEntrypoint,
|
|
9891
|
+
handlerFunction,
|
|
9892
|
+
pythonBin: getVenvPythonBin(venvPath),
|
|
9893
|
+
env: pythonEnv,
|
|
9894
|
+
workPath
|
|
9895
|
+
});
|
|
9896
|
+
const extraTrampolineEnv = [];
|
|
9897
|
+
if (crons?.length) {
|
|
9898
|
+
const json = JSON.stringify(buildCronRouteTable(crons));
|
|
9899
|
+
(0, import_assert.default)(!json.includes("\\"), `backslash in cron route table: ${json}`);
|
|
9900
|
+
extraTrampolineEnv.push(`"__VC_CRON_ROUTES": '${json}'`);
|
|
9901
|
+
}
|
|
9902
|
+
const variableName = resolved?.variableName ?? "";
|
|
9903
|
+
runtimeTrampoline = createRuntimeTrampoline({
|
|
9904
|
+
moduleName,
|
|
9905
|
+
entrypoint: entrypointWithSuffix,
|
|
9906
|
+
vendorDir,
|
|
9907
|
+
variableName,
|
|
9908
|
+
extraEnv: extraTrampolineEnv
|
|
9909
|
+
});
|
|
9346
9910
|
}
|
|
9347
|
-
const
|
|
9348
|
-
const suffix = meta.isDev && !entrypoint.endsWith(".py") ? ".py" : "";
|
|
9349
|
-
const entrypointWithSuffix = `${entrypoint}${suffix}`;
|
|
9350
|
-
(0, import_build_utils19.debug)("Entrypoint with suffix is", entrypointWithSuffix);
|
|
9351
|
-
const crons = await getServiceCrons({
|
|
9352
|
-
service,
|
|
9353
|
-
entrypoint,
|
|
9354
|
-
rawEntrypoint,
|
|
9355
|
-
handlerFunction,
|
|
9356
|
-
pythonBin: getVenvPythonBin(venvPath),
|
|
9357
|
-
env: pythonEnv,
|
|
9358
|
-
workPath
|
|
9359
|
-
});
|
|
9360
|
-
const extraTrampolineEnv = [];
|
|
9361
|
-
if (crons?.length) {
|
|
9362
|
-
const json = JSON.stringify(buildCronRouteTable(crons));
|
|
9363
|
-
(0, import_assert.default)(!json.includes("\\"), `backslash in cron route table: ${json}`);
|
|
9364
|
-
extraTrampolineEnv.push(`"__VC_CRON_ROUTES": '${json}'`);
|
|
9365
|
-
}
|
|
9366
|
-
const variableName = resolved?.variableName ?? "";
|
|
9367
|
-
const runtimeTrampoline = createRuntimeTrampoline({
|
|
9368
|
-
moduleName,
|
|
9369
|
-
entrypoint: entrypointWithSuffix,
|
|
9370
|
-
vendorDir,
|
|
9371
|
-
variableName,
|
|
9372
|
-
extraEnv: extraTrampolineEnv
|
|
9373
|
-
});
|
|
9374
|
-
const automaticCompileAllEnabled = shouldUseCompileAll({
|
|
9911
|
+
const compileAllEnabled = shouldCompileAll({
|
|
9375
9912
|
isDev: meta.isDev,
|
|
9376
9913
|
hasCustomCommand,
|
|
9377
|
-
|
|
9914
|
+
// A pre-deploy command can rewrite source after the build, which would make
|
|
9915
|
+
// unchecked-hash precompiled bytecode stale; skip precompilation to avoid serving it.
|
|
9916
|
+
hasPreDeployCommand: typeof preDeployCommand === "string"
|
|
9378
9917
|
});
|
|
9379
9918
|
const predefinedExcludes = [
|
|
9380
9919
|
".git/**",
|
|
@@ -9405,16 +9944,16 @@ var build = async ({
|
|
|
9405
9944
|
cwd: workPath,
|
|
9406
9945
|
ignore: config && typeof config.excludeFiles === "string" ? [...predefinedExcludes, config.excludeFiles] : predefinedExcludes
|
|
9407
9946
|
};
|
|
9408
|
-
const files = await (0,
|
|
9947
|
+
const files = await (0, import_build_utils20.glob)("**", globOptions);
|
|
9409
9948
|
if (djangoStatic?.manifestRelPath) {
|
|
9410
|
-
files[djangoStatic.manifestRelPath] = new
|
|
9411
|
-
fsPath: (0,
|
|
9949
|
+
files[djangoStatic.manifestRelPath] = new import_build_utils20.FileFsRef({
|
|
9950
|
+
fsPath: (0, import_path17.join)(workPath, djangoStatic.manifestRelPath)
|
|
9412
9951
|
});
|
|
9413
9952
|
}
|
|
9414
9953
|
const handlerPyFilename = "vc__handler__python";
|
|
9415
9954
|
if (config.framework === "fasthtml") {
|
|
9416
9955
|
const { SESSKEY = "" } = process.env;
|
|
9417
|
-
files[".sesskey"] = new
|
|
9956
|
+
files[".sesskey"] = new import_build_utils20.FileBlob({ data: `"${SESSKEY}"` });
|
|
9418
9957
|
}
|
|
9419
9958
|
const depExternalizer = new PythonDependencyExternalizer({
|
|
9420
9959
|
venvPath,
|
|
@@ -9443,99 +9982,217 @@ var build = async ({
|
|
|
9443
9982
|
});
|
|
9444
9983
|
}
|
|
9445
9984
|
});
|
|
9446
|
-
const runCompileAllAndFillBytecode = async () => {
|
|
9447
|
-
|
|
9448
|
-
|
|
9449
|
-
|
|
9450
|
-
|
|
9451
|
-
|
|
9452
|
-
|
|
9453
|
-
|
|
9454
|
-
|
|
9455
|
-
|
|
9985
|
+
const runCompileAllAndFillBytecode = async (capacityBytes, vendorPackageTiers) => {
|
|
9986
|
+
try {
|
|
9987
|
+
await builderSpan.child("vc.builder.python.compileall").trace(async (compileSpan) => {
|
|
9988
|
+
const sitePackageDirs = (await getVenvSitePackagesDirs(venvPath)).filter((d) => import_fs17.default.existsSync(d));
|
|
9989
|
+
const pythonBin = getVenvPythonBin(venvPath);
|
|
9990
|
+
console.log("Compiling Python bytecode...");
|
|
9991
|
+
await runCompileAll({
|
|
9992
|
+
pythonBin,
|
|
9993
|
+
filesOrDirectories: [workPath],
|
|
9994
|
+
env: pythonEnv,
|
|
9995
|
+
excludeRegex: getCompileAllAppExcludeRegex(workPath)
|
|
9996
|
+
});
|
|
9997
|
+
await runCompileAll({
|
|
9998
|
+
pythonBin,
|
|
9999
|
+
filesOrDirectories: sitePackageDirs,
|
|
10000
|
+
env: pythonEnv
|
|
10001
|
+
});
|
|
10002
|
+
compileSpan.setAttributes({
|
|
10003
|
+
"python.compileall.enabled": "true",
|
|
10004
|
+
"python.compileall.sitePackageDirectoryCount": String(
|
|
10005
|
+
sitePackageDirs.length
|
|
10006
|
+
)
|
|
10007
|
+
});
|
|
9456
10008
|
});
|
|
9457
|
-
|
|
9458
|
-
|
|
9459
|
-
|
|
9460
|
-
|
|
9461
|
-
|
|
10009
|
+
const currentSize = await calculateBundleSize(files);
|
|
10010
|
+
let remainingCapacity = capacityBytes - currentSize;
|
|
10011
|
+
if (pythonVersion.major != null && pythonVersion.minor != null) {
|
|
10012
|
+
const appBytecodeInfo = await collectAppBytecodeFiles({
|
|
10013
|
+
workPath,
|
|
10014
|
+
files,
|
|
10015
|
+
pythonMajor: pythonVersion.major,
|
|
10016
|
+
pythonMinor: pythonVersion.minor
|
|
10017
|
+
});
|
|
10018
|
+
remainingCapacity = addBytecodeWithinCapacity(
|
|
10019
|
+
files,
|
|
10020
|
+
appBytecodeInfo,
|
|
10021
|
+
remainingCapacity
|
|
10022
|
+
);
|
|
10023
|
+
}
|
|
10024
|
+
await addVendorBytecodeInTiers({
|
|
10025
|
+
files,
|
|
10026
|
+
depExternalizer,
|
|
10027
|
+
vendorDir,
|
|
10028
|
+
capacity: remainingCapacity,
|
|
10029
|
+
vendorPackageTiers: vendorPackageTiers ?? [void 0]
|
|
9462
10030
|
});
|
|
9463
|
-
|
|
9464
|
-
|
|
9465
|
-
"
|
|
9466
|
-
|
|
9467
|
-
|
|
10031
|
+
} catch (err) {
|
|
10032
|
+
console.log(
|
|
10033
|
+
"Bytecode precompilation failed; continuing without precompiled bytecode."
|
|
10034
|
+
);
|
|
10035
|
+
(0, import_build_utils20.debug)(`bytecode precompilation error details: ${err}`);
|
|
10036
|
+
}
|
|
10037
|
+
};
|
|
10038
|
+
const runPrefixCompileAndFill = async (bundleResult) => {
|
|
10039
|
+
const pyMajor = pythonVersion.major;
|
|
10040
|
+
const pyMinor = pythonVersion.minor;
|
|
10041
|
+
if (pyMajor == null || pyMinor == null)
|
|
10042
|
+
return;
|
|
10043
|
+
try {
|
|
10044
|
+
const currentSize = await calculateBundleSize(files);
|
|
10045
|
+
let remainingCapacity = BYTECODE_FILL_CEILING_BYTES - currentSize;
|
|
10046
|
+
if (remainingCapacity <= 0) {
|
|
10047
|
+
(0, import_build_utils20.debug)(
|
|
10048
|
+
`skipping bytecode precompilation: no zip capacity remaining (bundle is ${(currentSize / (1024 * 1024)).toFixed(2)} MB)`
|
|
10049
|
+
);
|
|
10050
|
+
return;
|
|
10051
|
+
}
|
|
10052
|
+
const stagingDir = (0, import_path17.join)(workPath, ".vercel", "python", "pycache");
|
|
10053
|
+
await import_fs17.default.promises.rm(stagingDir, { recursive: true, force: true });
|
|
10054
|
+
await import_fs17.default.promises.mkdir(stagingDir, { recursive: true });
|
|
10055
|
+
await builderSpan.child("vc.builder.python.compileall").trace(async (compileSpan) => {
|
|
10056
|
+
const sitePackageDirs = (await getVenvSitePackagesDirs(venvPath)).filter((d) => import_fs17.default.existsSync(d));
|
|
10057
|
+
const pythonBin = getVenvPythonBin(venvPath);
|
|
10058
|
+
console.log("Compiling Python bytecode...");
|
|
10059
|
+
await runCompileAll({
|
|
10060
|
+
pythonBin,
|
|
10061
|
+
filesOrDirectories: [workPath],
|
|
10062
|
+
env: pythonEnv,
|
|
10063
|
+
excludeRegex: getCompileAllAppExcludeRegex(workPath),
|
|
10064
|
+
pycachePrefix: stagingDir
|
|
10065
|
+
});
|
|
10066
|
+
await runCompileAll({
|
|
10067
|
+
pythonBin,
|
|
10068
|
+
filesOrDirectories: sitePackageDirs,
|
|
10069
|
+
env: pythonEnv,
|
|
10070
|
+
pycachePrefix: stagingDir
|
|
10071
|
+
});
|
|
10072
|
+
compileSpan.setAttributes({
|
|
10073
|
+
"python.compileall.enabled": "true",
|
|
10074
|
+
"python.compileall.mode": "pycache-prefix",
|
|
10075
|
+
"python.compileall.sitePackageDirectoryCount": String(
|
|
10076
|
+
sitePackageDirs.length
|
|
10077
|
+
)
|
|
10078
|
+
});
|
|
9468
10079
|
});
|
|
9469
|
-
|
|
9470
|
-
|
|
9471
|
-
|
|
9472
|
-
if (pythonVersion.major != null && pythonVersion.minor != null) {
|
|
9473
|
-
const appBytecodeInfo = await collectAppBytecodeFiles({
|
|
10080
|
+
const beforeCount = Object.keys(files).length;
|
|
10081
|
+
const appInfo = await collectAppPrefixBytecodeFiles({
|
|
10082
|
+
stagingDir,
|
|
9474
10083
|
workPath,
|
|
9475
10084
|
files,
|
|
9476
|
-
|
|
9477
|
-
|
|
10085
|
+
runtimeTaskRoot: "/var/task",
|
|
10086
|
+
pythonMajor: pyMajor,
|
|
10087
|
+
pythonMinor: pyMinor
|
|
9478
10088
|
});
|
|
9479
10089
|
remainingCapacity = addBytecodeWithinCapacity(
|
|
9480
10090
|
files,
|
|
9481
|
-
|
|
10091
|
+
appInfo,
|
|
9482
10092
|
remainingCapacity
|
|
9483
10093
|
);
|
|
10094
|
+
const alwaysBundled = bundleResult.alwaysBundledPackages ?? [];
|
|
10095
|
+
remainingCapacity = await addCollectedVendorBytecode({
|
|
10096
|
+
files,
|
|
10097
|
+
capacity: remainingCapacity,
|
|
10098
|
+
collect: (include) => depExternalizer.collectPrefixBytecodeFiles({
|
|
10099
|
+
stagingDir,
|
|
10100
|
+
runtimeRoot: `/var/task/${vendorDir}`,
|
|
10101
|
+
includePackages: include ?? alwaysBundled
|
|
10102
|
+
})
|
|
10103
|
+
});
|
|
10104
|
+
const externalized = bundleResult.externalizedPublicPackages ?? [];
|
|
10105
|
+
await addCollectedVendorBytecode({
|
|
10106
|
+
files,
|
|
10107
|
+
capacity: remainingCapacity,
|
|
10108
|
+
collect: (include) => depExternalizer.collectPrefixBytecodeFiles({
|
|
10109
|
+
stagingDir,
|
|
10110
|
+
runtimeRoot: `${RUNTIME_DEPS_DIR}/lib/python${pyMajor}.${pyMinor}/site-packages`,
|
|
10111
|
+
includePackages: include ?? externalized
|
|
10112
|
+
})
|
|
10113
|
+
});
|
|
10114
|
+
if (Object.keys(files).length > beforeCount) {
|
|
10115
|
+
lambdaEnv.PYTHONPYCACHEPREFIX = RUNTIME_PYCACHE_PREFIX;
|
|
10116
|
+
}
|
|
10117
|
+
} catch (err) {
|
|
10118
|
+
console.log(
|
|
10119
|
+
"Bytecode precompilation failed; continuing without precompiled bytecode."
|
|
10120
|
+
);
|
|
10121
|
+
(0, import_build_utils20.debug)(`bytecode precompilation error details: ${err}`);
|
|
9484
10122
|
}
|
|
9485
|
-
const vendorBytecodeInfo = await depExternalizer.collectBytecodeFiles({
|
|
9486
|
-
vendorDirName: vendorDir
|
|
9487
|
-
});
|
|
9488
|
-
await addVendorBytecodeWithinCapacity({
|
|
9489
|
-
files,
|
|
9490
|
-
depExternalizer,
|
|
9491
|
-
vendorDir,
|
|
9492
|
-
bytecodeInfo: vendorBytecodeInfo,
|
|
9493
|
-
capacity: remainingCapacity
|
|
9494
|
-
});
|
|
9495
10123
|
};
|
|
9496
10124
|
const announceLargeFunction = () => console.log(
|
|
9497
|
-
`Function "${entrypoint}" exceeds the standard size limit; enabling large functions (beta).`
|
|
10125
|
+
`Function "${entrypoint ?? rawEntrypoint}" exceeds the standard size limit; enabling large functions (beta).`
|
|
9498
10126
|
);
|
|
9499
10127
|
if (depAnalysis.runtimeInstallEnabled) {
|
|
9500
|
-
const
|
|
9501
|
-
|
|
10128
|
+
const bytecodeFirst = compileAllEnabled && pythonVersion.major != null && pythonVersion.minor != null;
|
|
10129
|
+
const bundleResult = await depExternalizer.generateBundle(files, {
|
|
10130
|
+
bytecodeFirst
|
|
10131
|
+
});
|
|
10132
|
+
if (bundleResult.fellBackToFullBundle) {
|
|
9502
10133
|
announceLargeFunction();
|
|
9503
|
-
if (
|
|
9504
|
-
await runCompileAllAndFillBytecode(
|
|
10134
|
+
if (compileAllEnabled) {
|
|
10135
|
+
await runCompileAllAndFillBytecode(
|
|
10136
|
+
MAX_LARGE_FUNCTION_UNCOMPRESSED_SIZE
|
|
10137
|
+
);
|
|
10138
|
+
}
|
|
10139
|
+
} else if (bundleResult.packingMode === "bytecode-first") {
|
|
10140
|
+
await runPrefixCompileAndFill(bundleResult);
|
|
10141
|
+
} else if (compileAllEnabled) {
|
|
10142
|
+
const currentSize = await calculateBundleSize(files);
|
|
10143
|
+
const capacity = BYTECODE_FILL_CEILING_BYTES - currentSize;
|
|
10144
|
+
const estimate = await estimateBytecodeSize(files);
|
|
10145
|
+
if (capacity >= BYTECODE_COVERAGE_FLOOR * estimate) {
|
|
10146
|
+
await runCompileAllAndFillBytecode(BYTECODE_FILL_CEILING_BYTES, [
|
|
10147
|
+
bundleResult.alwaysBundledPackages ?? [],
|
|
10148
|
+
bundleResult.bundledPublicPackages ?? []
|
|
10149
|
+
]);
|
|
9505
10150
|
}
|
|
9506
10151
|
}
|
|
9507
10152
|
} else {
|
|
9508
10153
|
addFiles(files, depAnalysis.allVendorFiles);
|
|
9509
|
-
if (
|
|
9510
|
-
|
|
9511
|
-
|
|
9512
|
-
|
|
9513
|
-
|
|
10154
|
+
if (depAnalysis.totalBundleSize > LAMBDA_SIZE_THRESHOLD_BYTES) {
|
|
10155
|
+
if (isLargeFunctionsEnabled()) {
|
|
10156
|
+
announceLargeFunction();
|
|
10157
|
+
}
|
|
10158
|
+
if (compileAllEnabled) {
|
|
10159
|
+
await runCompileAllAndFillBytecode(
|
|
10160
|
+
MAX_LARGE_FUNCTION_UNCOMPRESSED_SIZE
|
|
10161
|
+
);
|
|
10162
|
+
}
|
|
10163
|
+
} else if (compileAllEnabled) {
|
|
10164
|
+
const capacity = BYTECODE_FILL_CEILING_BYTES - depAnalysis.totalBundleSize;
|
|
10165
|
+
const estimate = await estimateBytecodeSize(files);
|
|
10166
|
+
if (capacity >= BYTECODE_COVERAGE_FLOOR * estimate) {
|
|
10167
|
+
await runCompileAllAndFillBytecode(BYTECODE_FILL_CEILING_BYTES);
|
|
10168
|
+
}
|
|
9514
10169
|
}
|
|
9515
10170
|
}
|
|
9516
10171
|
});
|
|
9517
|
-
|
|
9518
|
-
|
|
9519
|
-
|
|
9520
|
-
|
|
9521
|
-
|
|
9522
|
-
|
|
9523
|
-
|
|
9524
|
-
|
|
9525
|
-
|
|
9526
|
-
|
|
9527
|
-
|
|
9528
|
-
|
|
9529
|
-
|
|
9530
|
-
|
|
9531
|
-
|
|
9532
|
-
|
|
9533
|
-
|
|
10172
|
+
let output;
|
|
10173
|
+
if (entrypoint && runtimeTrampoline) {
|
|
10174
|
+
const webFiles = {
|
|
10175
|
+
...files,
|
|
10176
|
+
[`${handlerPyFilename}.py`]: new import_build_utils20.FileBlob({ data: runtimeTrampoline })
|
|
10177
|
+
};
|
|
10178
|
+
const lambdaOptions = await getPythonLambdaOptions({
|
|
10179
|
+
config,
|
|
10180
|
+
entrypoint
|
|
10181
|
+
});
|
|
10182
|
+
output = new import_build_utils20.Lambda({
|
|
10183
|
+
files: webFiles,
|
|
10184
|
+
handler: `${handlerPyFilename}.vc_handler`,
|
|
10185
|
+
runtime: pythonVersion.runtime,
|
|
10186
|
+
...lambdaOptions,
|
|
10187
|
+
architecture: target.architecture,
|
|
10188
|
+
environment: lambdaEnv,
|
|
10189
|
+
supportsResponseStreaming: true
|
|
10190
|
+
});
|
|
10191
|
+
}
|
|
9534
10192
|
const subscriberLambdas = {};
|
|
9535
10193
|
for (const subscriber of subscribers) {
|
|
9536
|
-
const
|
|
9537
|
-
const
|
|
9538
|
-
const consumer = (0, import_build_utils19.sanitizeConsumerName)(outputPath);
|
|
10194
|
+
const outputPath = getSubscriberOutputPath(subscriber.name);
|
|
10195
|
+
const consumer = getSubscriberConsumerName(subscriber.name);
|
|
9539
10196
|
const experimentalTriggers = subscriber.topics.map(
|
|
9540
10197
|
(topic) => ({
|
|
9541
10198
|
type: "queue/v2beta",
|
|
@@ -9544,10 +10201,10 @@ var build = async ({
|
|
|
9544
10201
|
...subscriber.triggerDefaults
|
|
9545
10202
|
})
|
|
9546
10203
|
);
|
|
9547
|
-
subscriberLambdas[outputPath] = new
|
|
10204
|
+
subscriberLambdas[outputPath] = new import_build_utils20.Lambda({
|
|
9548
10205
|
files: {
|
|
9549
10206
|
...files,
|
|
9550
|
-
[`${handlerPyFilename}.py`]: new
|
|
10207
|
+
[`${handlerPyFilename}.py`]: new import_build_utils20.FileBlob({
|
|
9551
10208
|
data: createRuntimeTrampoline({
|
|
9552
10209
|
moduleName: subscriber.moduleName,
|
|
9553
10210
|
entrypoint: subscriber.entrypoint,
|
|
@@ -9562,6 +10219,42 @@ var build = async ({
|
|
|
9562
10219
|
environment: {
|
|
9563
10220
|
...lambdaEnv,
|
|
9564
10221
|
VERCEL_HAS_WORKER_SERVICES: "1",
|
|
10222
|
+
// Compatibility marker consumed by the current Python runtime.
|
|
10223
|
+
VERCEL_SERVICE_TYPE: "worker"
|
|
10224
|
+
},
|
|
10225
|
+
experimentalTriggers,
|
|
10226
|
+
supportsResponseStreaming: true
|
|
10227
|
+
});
|
|
10228
|
+
}
|
|
10229
|
+
const workflowLambdas = {};
|
|
10230
|
+
for (const workflow of workflows) {
|
|
10231
|
+
const outputPath = getWorkflowOutputPath(workflow.name);
|
|
10232
|
+
const experimentalTriggers = [
|
|
10233
|
+
{
|
|
10234
|
+
type: "queue/v2beta",
|
|
10235
|
+
topic: WORKFLOW_TOPIC_PATTERN,
|
|
10236
|
+
consumer: getWorkflowConsumerName(workflow.name)
|
|
10237
|
+
}
|
|
10238
|
+
];
|
|
10239
|
+
workflowLambdas[outputPath] = new import_build_utils20.Lambda({
|
|
10240
|
+
files: {
|
|
10241
|
+
...files,
|
|
10242
|
+
[`${handlerPyFilename}.py`]: new import_build_utils20.FileBlob({
|
|
10243
|
+
data: createRuntimeTrampoline({
|
|
10244
|
+
moduleName: workflow.moduleName,
|
|
10245
|
+
entrypoint: workflow.entrypoint,
|
|
10246
|
+
vendorDir,
|
|
10247
|
+
variableName: workflow.variableName
|
|
10248
|
+
})
|
|
10249
|
+
})
|
|
10250
|
+
},
|
|
10251
|
+
handler: `${handlerPyFilename}.vc_handler`,
|
|
10252
|
+
runtime: pythonVersion.runtime,
|
|
10253
|
+
architecture: target.architecture,
|
|
10254
|
+
environment: {
|
|
10255
|
+
...lambdaEnv,
|
|
10256
|
+
VERCEL_HAS_WORKER_SERVICES: "1",
|
|
10257
|
+
// Compatibility marker consumed by the current Python runtime.
|
|
9565
10258
|
VERCEL_SERVICE_TYPE: "worker"
|
|
9566
10259
|
},
|
|
9567
10260
|
experimentalTriggers,
|
|
@@ -9576,21 +10269,22 @@ var build = async ({
|
|
|
9576
10269
|
pythonVersion,
|
|
9577
10270
|
uvLockPath,
|
|
9578
10271
|
framework,
|
|
9579
|
-
serviceType: service ? (0,
|
|
10272
|
+
serviceType: service ? (0, import_build_utils20.getReportedServiceType)(service) : void 0
|
|
9580
10273
|
});
|
|
9581
10274
|
} catch (err) {
|
|
9582
|
-
(0,
|
|
10275
|
+
(0, import_build_utils20.debug)(
|
|
9583
10276
|
`Failed to write project manifest: ${err instanceof Error ? err.message : String(err)}`
|
|
9584
10277
|
);
|
|
9585
10278
|
}
|
|
9586
10279
|
}
|
|
9587
|
-
if (!(0,
|
|
10280
|
+
if (!(0, import_build_utils20.isPythonFramework)(framework) && !service?.name && !isPyprojectEntrypoint) {
|
|
10281
|
+
(0, import_assert.default)(output, "web Lambda must exist for non-service builds");
|
|
9588
10282
|
return { resultVersion: 3, result: { output } };
|
|
9589
10283
|
}
|
|
9590
10284
|
const lambdaPath = service?.name && service.type ? `_svc/${service.name}/index` : "index";
|
|
9591
|
-
const staticFiles = djangoStatic?.cdnOutputDir ? await (0,
|
|
10285
|
+
const staticFiles = djangoStatic?.cdnOutputDir ? await (0, import_build_utils20.glob)("**", { cwd: djangoStatic.cdnOutputDir }) : {};
|
|
9592
10286
|
const isNonWebService = service?.name && service.type && service.type !== "web";
|
|
9593
|
-
const routes = isNonWebService ? void 0 : [
|
|
10287
|
+
const routes = isNonWebService || !output ? void 0 : [
|
|
9594
10288
|
{ handle: "filesystem" },
|
|
9595
10289
|
{ src: "/(.*)", dest: `/${lambdaPath}` }
|
|
9596
10290
|
];
|
|
@@ -9598,8 +10292,9 @@ var build = async ({
|
|
|
9598
10292
|
resultVersion: 2,
|
|
9599
10293
|
result: {
|
|
9600
10294
|
output: {
|
|
9601
|
-
[lambdaPath]: output,
|
|
10295
|
+
...output ? { [lambdaPath]: output } : {},
|
|
9602
10296
|
...subscriberLambdas,
|
|
10297
|
+
...workflowLambdas,
|
|
9603
10298
|
...staticFiles
|
|
9604
10299
|
},
|
|
9605
10300
|
...routes ? { routes } : {},
|
|
@@ -9622,14 +10317,14 @@ var prepareCache = async ({
|
|
|
9622
10317
|
}
|
|
9623
10318
|
} catch {
|
|
9624
10319
|
}
|
|
9625
|
-
return (0,
|
|
10320
|
+
return (0, import_build_utils20.glob)("**/.vercel/python/{.venv,services/*/.venv,cache/uv}/**", {
|
|
9626
10321
|
cwd: root,
|
|
9627
10322
|
ignore
|
|
9628
10323
|
});
|
|
9629
10324
|
};
|
|
9630
10325
|
var shouldServe = (opts) => {
|
|
9631
10326
|
const framework = opts.config.framework;
|
|
9632
|
-
if ((0,
|
|
10327
|
+
if ((0, import_build_utils20.isPythonFramework)(framework)) {
|
|
9633
10328
|
const requestPath = opts.requestPath.replace(/\/$/, "");
|
|
9634
10329
|
if (requestPath.startsWith("api") && opts.hasMatched) {
|
|
9635
10330
|
return false;
|
|
@@ -9648,7 +10343,7 @@ var defaultShouldServe = ({
|
|
|
9648
10343
|
if (entrypoint === requestPath && hasProp(files, entrypoint)) {
|
|
9649
10344
|
return true;
|
|
9650
10345
|
}
|
|
9651
|
-
const { dir, name } = (0,
|
|
10346
|
+
const { dir, name } = (0, import_path17.parse)(entrypoint);
|
|
9652
10347
|
if (name === "index" && dir === requestPath && hasProp(files, entrypoint)) {
|
|
9653
10348
|
return true;
|
|
9654
10349
|
}
|
|
@@ -9659,11 +10354,14 @@ function hasProp(obj, key) {
|
|
|
9659
10354
|
}
|
|
9660
10355
|
// Annotate the CommonJS export names for ESM import in node:
|
|
9661
10356
|
0 && (module.exports = {
|
|
10357
|
+
addCollectedVendorBytecode,
|
|
10358
|
+
addVendorBytecodeInTiers,
|
|
9662
10359
|
build,
|
|
9663
10360
|
defaultShouldServe,
|
|
9664
10361
|
detectEntrypoint,
|
|
9665
10362
|
diagnostics,
|
|
9666
10363
|
downloadFilesInWorkPath,
|
|
10364
|
+
getDevSidecars,
|
|
9667
10365
|
installRequirement,
|
|
9668
10366
|
installRequirementsFile,
|
|
9669
10367
|
prepareCache,
|