@vercel/python 6.25.0 → 6.28.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 +239 -99
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -3223,11 +3223,12 @@ __export(src_exports, {
|
|
|
3223
3223
|
version: () => version
|
|
3224
3224
|
});
|
|
3225
3225
|
module.exports = __toCommonJS(src_exports);
|
|
3226
|
+
var import_child_process3 = require("child_process");
|
|
3226
3227
|
var import_fs11 = __toESM(require("fs"));
|
|
3227
3228
|
var import_path13 = require("path");
|
|
3228
3229
|
|
|
3229
3230
|
// src/package-versions.ts
|
|
3230
|
-
var VERCEL_RUNTIME_VERSION = "0.
|
|
3231
|
+
var VERCEL_RUNTIME_VERSION = "0.11.0";
|
|
3231
3232
|
var VERCEL_WORKERS_VERSION = "0.0.13";
|
|
3232
3233
|
|
|
3233
3234
|
// src/index.ts
|
|
@@ -3257,7 +3258,7 @@ var import_fs = __toESM(require("fs"));
|
|
|
3257
3258
|
var import_os = __toESM(require("os"));
|
|
3258
3259
|
var import_which = __toESM(require_lib());
|
|
3259
3260
|
var import_build_utils = require("@vercel/build-utils");
|
|
3260
|
-
var UV_VERSION = "0.
|
|
3261
|
+
var UV_VERSION = "0.10.11";
|
|
3261
3262
|
var UV_PYTHON_PATH_PREFIX = "/uv/python/";
|
|
3262
3263
|
var UV_PYTHON_DOWNLOADS_MODE = "automatic";
|
|
3263
3264
|
var isWin = process.platform === "win32";
|
|
@@ -3331,34 +3332,16 @@ var UvRunner = class {
|
|
|
3331
3332
|
args.push("--no-editable");
|
|
3332
3333
|
await this.runUvCmd(args, projectDir, venvPath);
|
|
3333
3334
|
}
|
|
3334
|
-
async lock(
|
|
3335
|
-
const
|
|
3336
|
-
|
|
3335
|
+
async lock(options) {
|
|
3336
|
+
const { projectDir, venvPath, noBuild, upgrade } = options;
|
|
3337
|
+
const args = ["lock", "--python", getVenvPythonBin(venvPath)];
|
|
3338
|
+
if (noBuild) {
|
|
3337
3339
|
args.push("--no-build");
|
|
3338
3340
|
}
|
|
3339
|
-
if (
|
|
3341
|
+
if (upgrade) {
|
|
3340
3342
|
args.push("--upgrade");
|
|
3341
3343
|
}
|
|
3342
|
-
|
|
3343
|
-
(0, import_build_utils.debug)(`Running "${pretty}" in ${projectDir}...`);
|
|
3344
|
-
try {
|
|
3345
|
-
await (0, import_execa.default)(this.uvPath, args, {
|
|
3346
|
-
cwd: projectDir,
|
|
3347
|
-
env: getProtectedUvEnv(process.env)
|
|
3348
|
-
});
|
|
3349
|
-
} catch (err) {
|
|
3350
|
-
const error = new Error(
|
|
3351
|
-
`Failed to run "${pretty}": ${err instanceof Error ? err.message : String(err)}`
|
|
3352
|
-
);
|
|
3353
|
-
if (err && typeof err === "object") {
|
|
3354
|
-
if ("code" in err) {
|
|
3355
|
-
error.code = err.code;
|
|
3356
|
-
} else if ("signal" in err) {
|
|
3357
|
-
error.code = err.signal;
|
|
3358
|
-
}
|
|
3359
|
-
}
|
|
3360
|
-
throw error;
|
|
3361
|
-
}
|
|
3344
|
+
await this.runUvCmd(args, projectDir, venvPath);
|
|
3362
3345
|
}
|
|
3363
3346
|
async addDependencies(options) {
|
|
3364
3347
|
const { venvPath, projectDir, dependencies } = options;
|
|
@@ -3659,7 +3642,27 @@ function detectPlatform() {
|
|
|
3659
3642
|
osMinor = 17;
|
|
3660
3643
|
}
|
|
3661
3644
|
const libc = libcFamily === detectLibc.MUSL ? "musl" : "gnu";
|
|
3662
|
-
|
|
3645
|
+
const SYS_PLATFORM_MAP = {
|
|
3646
|
+
linux: "linux",
|
|
3647
|
+
win32: "win32",
|
|
3648
|
+
darwin: "darwin"
|
|
3649
|
+
};
|
|
3650
|
+
const sysPlatform = SYS_PLATFORM_MAP[process.platform] || "linux";
|
|
3651
|
+
const OS_MAP = {
|
|
3652
|
+
linux: "linux",
|
|
3653
|
+
win32: "windows",
|
|
3654
|
+
darwin: "macos"
|
|
3655
|
+
};
|
|
3656
|
+
const detectedOs = OS_MAP[process.platform] || "linux";
|
|
3657
|
+
return {
|
|
3658
|
+
osName,
|
|
3659
|
+
archName,
|
|
3660
|
+
osMajor,
|
|
3661
|
+
osMinor,
|
|
3662
|
+
os: detectedOs,
|
|
3663
|
+
sysPlatform,
|
|
3664
|
+
libc
|
|
3665
|
+
};
|
|
3663
3666
|
}
|
|
3664
3667
|
|
|
3665
3668
|
// src/version.ts
|
|
@@ -4017,6 +4020,7 @@ function detectInstallSource(pythonPackage, rootDir) {
|
|
|
4017
4020
|
async function ensureUvProject({
|
|
4018
4021
|
workPath,
|
|
4019
4022
|
rootDir,
|
|
4023
|
+
venvPath,
|
|
4020
4024
|
pythonPackage,
|
|
4021
4025
|
pythonVersion,
|
|
4022
4026
|
uv,
|
|
@@ -4073,16 +4077,18 @@ async function ensureUvProject({
|
|
|
4073
4077
|
if (workspaceLockFile) {
|
|
4074
4078
|
lockPath = (0, import_path5.join)(rootDir, workspaceLockFile.path);
|
|
4075
4079
|
} else {
|
|
4076
|
-
await uv.lock(
|
|
4080
|
+
await uv.lock({
|
|
4077
4081
|
projectDir,
|
|
4078
|
-
|
|
4079
|
-
|
|
4082
|
+
venvPath,
|
|
4083
|
+
...requireBinaryWheels ? { noBuild: true, upgrade: true } : {}
|
|
4084
|
+
});
|
|
4080
4085
|
}
|
|
4081
4086
|
if (generateLockFile && !lockPath) {
|
|
4082
|
-
await uv.lock(
|
|
4087
|
+
await uv.lock({
|
|
4083
4088
|
projectDir,
|
|
4084
|
-
|
|
4085
|
-
|
|
4089
|
+
venvPath,
|
|
4090
|
+
...requireBinaryWheels ? { noBuild: true, upgrade: true } : {}
|
|
4091
|
+
});
|
|
4086
4092
|
}
|
|
4087
4093
|
} else {
|
|
4088
4094
|
projectDir = workPath;
|
|
@@ -4098,10 +4104,11 @@ async function ensureUvProject({
|
|
|
4098
4104
|
});
|
|
4099
4105
|
const content = (0, import_python_analysis2.stringifyManifest)(minimalManifest);
|
|
4100
4106
|
await import_fs3.default.promises.writeFile(pyprojectPath, content);
|
|
4101
|
-
await uv.lock(
|
|
4107
|
+
await uv.lock({
|
|
4102
4108
|
projectDir,
|
|
4103
|
-
|
|
4104
|
-
|
|
4109
|
+
venvPath,
|
|
4110
|
+
...requireBinaryWheels ? { noBuild: true, upgrade: true } : {}
|
|
4111
|
+
});
|
|
4105
4112
|
}
|
|
4106
4113
|
const resolvedLockPath = lockPath && import_fs3.default.existsSync(lockPath) ? lockPath : (0, import_path5.join)(projectDir, "uv.lock");
|
|
4107
4114
|
return {
|
|
@@ -4418,6 +4425,19 @@ To fix this, either:
|
|
|
4418
4425
|
runtimeToolingOverhead = 50 * 1024 * 1024;
|
|
4419
4426
|
}
|
|
4420
4427
|
}
|
|
4428
|
+
runtimeToolingOverhead += 4 * 1024;
|
|
4429
|
+
const projectDirRel = (0, import_path6.relative)(this.workPath, this.uvProjectDir);
|
|
4430
|
+
const uvLockRel = (0, import_path6.relative)(this.workPath, this.uvLockPath);
|
|
4431
|
+
const isOutsideWorkPath = projectDirRel.startsWith("..") || uvLockRel.startsWith("..");
|
|
4432
|
+
if (isOutsideWorkPath) {
|
|
4433
|
+
const pyprojectPath = (0, import_path6.join)(this.uvProjectDir, "pyproject.toml");
|
|
4434
|
+
const pyprojectStats = await import_fs4.default.promises.stat(pyprojectPath).catch(() => null);
|
|
4435
|
+
const uvLockStats = await import_fs4.default.promises.stat(this.uvLockPath).catch(() => null);
|
|
4436
|
+
if (pyprojectStats)
|
|
4437
|
+
runtimeToolingOverhead += pyprojectStats.size;
|
|
4438
|
+
if (uvLockStats)
|
|
4439
|
+
runtimeToolingOverhead += uvLockStats.size;
|
|
4440
|
+
}
|
|
4421
4441
|
const remainingCapacity = LAMBDA_SIZE_THRESHOLD_BYTES - fixedOverhead - runtimeToolingOverhead;
|
|
4422
4442
|
(0, import_build_utils5.debug)(
|
|
4423
4443
|
`Fixed overhead: ${(fixedOverhead / (1024 * 1024)).toFixed(2)} MB, runtime tooling: ${(runtimeToolingOverhead / (1024 * 1024)).toFixed(2)} MB, remaining capacity for public packages: ${(remainingCapacity / (1024 * 1024)).toFixed(2)} MB`
|
|
@@ -4446,9 +4466,6 @@ To fix this, either:
|
|
|
4446
4466
|
...this.alwaysBundlePackages,
|
|
4447
4467
|
...forceBundledDueToWheels
|
|
4448
4468
|
];
|
|
4449
|
-
const projectDirRel = (0, import_path6.relative)(this.workPath, this.uvProjectDir);
|
|
4450
|
-
const uvLockRel = (0, import_path6.relative)(this.workPath, this.uvLockPath);
|
|
4451
|
-
const isOutsideWorkPath = projectDirRel.startsWith("..") || uvLockRel.startsWith("..");
|
|
4452
4469
|
if (isOutsideWorkPath) {
|
|
4453
4470
|
const srcPyproject = (0, import_path6.join)(this.uvProjectDir, "pyproject.toml");
|
|
4454
4471
|
files[`${UV_BUNDLE_DIR}/pyproject.toml`] = new import_build_utils5.FileFsRef({
|
|
@@ -4488,7 +4505,7 @@ To fix this, either:
|
|
|
4488
4505
|
}
|
|
4489
4506
|
}
|
|
4490
4507
|
const finalBundleSize = await calculateBundleSize(files);
|
|
4491
|
-
if (finalBundleSize > LAMBDA_SIZE_THRESHOLD_BYTES) {
|
|
4508
|
+
if (finalBundleSize > LAMBDA_SIZE_THRESHOLD_BYTES + 100 * 1024) {
|
|
4492
4509
|
const finalSizeMB = (finalBundleSize / (1024 * 1024)).toFixed(2);
|
|
4493
4510
|
const limitMB = (LAMBDA_SIZE_THRESHOLD_BYTES / (1024 * 1024)).toFixed(0);
|
|
4494
4511
|
throw new import_build_utils5.NowBuildError({
|
|
@@ -4503,10 +4520,31 @@ To fix this, either:
|
|
|
4503
4520
|
* Identify public packages that have no compatible wheel for the Lambda platform.
|
|
4504
4521
|
* These packages must be force-bundled because `uv sync --no-build` at cold start
|
|
4505
4522
|
* will refuse to build from source.
|
|
4523
|
+
*
|
|
4524
|
+
* Packages that are not reachable on the target platform (e.g. pywin32 which is
|
|
4525
|
+
* only a dependency when `sys_platform == 'win32'`) are excluded -- they will
|
|
4526
|
+
* never be installed by `uv sync` on Lambda, so their wheel compatibility is
|
|
4527
|
+
* irrelevant.
|
|
4506
4528
|
*/
|
|
4507
4529
|
async findPackagesWithoutCompatibleWheels(lockFile, publicPackageNames) {
|
|
4508
4530
|
const platform = detectPlatform();
|
|
4509
|
-
const
|
|
4531
|
+
const reachable = await getPackagesReachableOnPlatform(
|
|
4532
|
+
lockFile,
|
|
4533
|
+
this.projectName,
|
|
4534
|
+
this.pythonMajor,
|
|
4535
|
+
this.pythonMinor,
|
|
4536
|
+
platform.sysPlatform,
|
|
4537
|
+
platform.archName
|
|
4538
|
+
);
|
|
4539
|
+
const relevantPackages = reachable ? publicPackageNames.filter(
|
|
4540
|
+
(name) => reachable.has((0, import_python_analysis3.normalizePackageName)(name))
|
|
4541
|
+
) : publicPackageNames;
|
|
4542
|
+
if (relevantPackages.length < publicPackageNames.length) {
|
|
4543
|
+
(0, import_build_utils5.debug)(
|
|
4544
|
+
`Skipping wheel check for ${publicPackageNames.length - relevantPackages.length} package(s) not reachable on the target platform`
|
|
4545
|
+
);
|
|
4546
|
+
}
|
|
4547
|
+
const publicSet = new Set(relevantPackages.map(import_python_analysis3.normalizePackageName));
|
|
4510
4548
|
const packageWheels = /* @__PURE__ */ new Map();
|
|
4511
4549
|
for (const pkg of lockFile.packages) {
|
|
4512
4550
|
const normalized = (0, import_python_analysis3.normalizePackageName)(pkg.name);
|
|
@@ -4515,7 +4553,7 @@ To fix this, either:
|
|
|
4515
4553
|
}
|
|
4516
4554
|
}
|
|
4517
4555
|
const incompatible = [];
|
|
4518
|
-
for (const name of
|
|
4556
|
+
for (const name of relevantPackages) {
|
|
4519
4557
|
const normalized = (0, import_python_analysis3.normalizePackageName)(name);
|
|
4520
4558
|
const wheels = packageWheels.get(normalized);
|
|
4521
4559
|
if (!wheels || wheels.length === 0) {
|
|
@@ -4554,6 +4592,64 @@ To fix this, either:
|
|
|
4554
4592
|
return incompatible;
|
|
4555
4593
|
}
|
|
4556
4594
|
};
|
|
4595
|
+
async function getPackagesReachableOnPlatform(lockFile, projectName, pythonMajor, pythonMinor, sysPlatform, platformMachine) {
|
|
4596
|
+
if (!projectName)
|
|
4597
|
+
return null;
|
|
4598
|
+
const rootNormalized = (0, import_python_analysis3.normalizePackageName)(projectName);
|
|
4599
|
+
const packageMap = /* @__PURE__ */ new Map();
|
|
4600
|
+
for (const pkg of lockFile.packages) {
|
|
4601
|
+
packageMap.set((0, import_python_analysis3.normalizePackageName)(pkg.name), pkg);
|
|
4602
|
+
}
|
|
4603
|
+
const rootPkg = packageMap.get(rootNormalized);
|
|
4604
|
+
if (!rootPkg)
|
|
4605
|
+
return null;
|
|
4606
|
+
const visited = /* @__PURE__ */ new Set();
|
|
4607
|
+
const queue = [];
|
|
4608
|
+
let queueHead = 0;
|
|
4609
|
+
async function enqueueDeps(pkg) {
|
|
4610
|
+
if (!pkg.dependencies)
|
|
4611
|
+
return;
|
|
4612
|
+
for (const dep of pkg.dependencies) {
|
|
4613
|
+
const normalized = (0, import_python_analysis3.normalizePackageName)(dep.name);
|
|
4614
|
+
if (visited.has(normalized))
|
|
4615
|
+
continue;
|
|
4616
|
+
if (dep.marker) {
|
|
4617
|
+
try {
|
|
4618
|
+
const compatible = await (0, import_python_analysis3.evaluateMarker)(
|
|
4619
|
+
dep.marker,
|
|
4620
|
+
pythonMajor,
|
|
4621
|
+
pythonMinor,
|
|
4622
|
+
sysPlatform,
|
|
4623
|
+
platformMachine
|
|
4624
|
+
);
|
|
4625
|
+
if (!compatible) {
|
|
4626
|
+
(0, import_build_utils5.debug)(
|
|
4627
|
+
`Skipping dependency ${dep.name}: marker "${dep.marker}" not satisfied on ${sysPlatform}`
|
|
4628
|
+
);
|
|
4629
|
+
continue;
|
|
4630
|
+
}
|
|
4631
|
+
} catch (err) {
|
|
4632
|
+
(0, import_build_utils5.debug)(
|
|
4633
|
+
`Failed to evaluate marker "${dep.marker}" for ${dep.name}, including conservatively: ${err instanceof Error ? err.message : String(err)}`
|
|
4634
|
+
);
|
|
4635
|
+
}
|
|
4636
|
+
}
|
|
4637
|
+
queue.push(normalized);
|
|
4638
|
+
}
|
|
4639
|
+
}
|
|
4640
|
+
await enqueueDeps(rootPkg);
|
|
4641
|
+
while (queueHead < queue.length) {
|
|
4642
|
+
const current = queue[queueHead++];
|
|
4643
|
+
if (visited.has(current))
|
|
4644
|
+
continue;
|
|
4645
|
+
visited.add(current);
|
|
4646
|
+
const pkg = packageMap.get(current);
|
|
4647
|
+
if (pkg) {
|
|
4648
|
+
await enqueueDeps(pkg);
|
|
4649
|
+
}
|
|
4650
|
+
}
|
|
4651
|
+
return visited;
|
|
4652
|
+
}
|
|
4557
4653
|
async function mirrorPackagesIntoVendor({
|
|
4558
4654
|
venvPath,
|
|
4559
4655
|
vendorDirName,
|
|
@@ -4917,6 +5013,7 @@ var import_fs6 = __toESM(require("fs"));
|
|
|
4917
5013
|
var import_path8 = require("path");
|
|
4918
5014
|
var import_build_utils7 = require("@vercel/build-utils");
|
|
4919
5015
|
var import_build_utils8 = require("@vercel/build-utils");
|
|
5016
|
+
var import_python_analysis5 = require("@vercel/python-analysis");
|
|
4920
5017
|
var PYTHON_ENTRYPOINT_FILENAMES = [
|
|
4921
5018
|
"app",
|
|
4922
5019
|
"index",
|
|
@@ -4947,8 +5044,9 @@ async function fileExists(filePath) {
|
|
|
4947
5044
|
async function checkEntrypoint(workPath, relPath) {
|
|
4948
5045
|
const absPath = (0, import_path8.join)(workPath, relPath);
|
|
4949
5046
|
if (!await fileExists(absPath))
|
|
4950
|
-
return
|
|
4951
|
-
|
|
5047
|
+
return null;
|
|
5048
|
+
const content = await import_fs6.default.promises.readFile(absPath, "utf-8");
|
|
5049
|
+
return (0, import_python_analysis5.findAppOrHandler)(content);
|
|
4952
5050
|
}
|
|
4953
5051
|
async function getPyprojectEntrypoint(workPath) {
|
|
4954
5052
|
const pyprojectData = await (0, import_build_utils8.readConfigFile)((0, import_path8.join)(workPath, "pyproject.toml"));
|
|
@@ -4974,9 +5072,10 @@ async function getPyprojectEntrypoint(workPath) {
|
|
|
4974
5072
|
}
|
|
4975
5073
|
async function findValidEntrypoint(workPath, candidates) {
|
|
4976
5074
|
for (const candidate of candidates) {
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
5075
|
+
const varName = await checkEntrypoint(workPath, candidate);
|
|
5076
|
+
if (varName) {
|
|
5077
|
+
(0, import_build_utils7.debug)(`Detected Python entrypoint: ${candidate} (variable: ${varName})`);
|
|
5078
|
+
return { entrypoint: candidate, variableName: varName };
|
|
4980
5079
|
}
|
|
4981
5080
|
}
|
|
4982
5081
|
return null;
|
|
@@ -5006,9 +5105,10 @@ async function getSubdirectories(workPath) {
|
|
|
5006
5105
|
async function detectGenericPythonEntrypoint(workPath, configuredEntrypoint) {
|
|
5007
5106
|
const entry = configuredEntrypoint.endsWith(".py") ? configuredEntrypoint : `${configuredEntrypoint}.py`;
|
|
5008
5107
|
try {
|
|
5009
|
-
|
|
5108
|
+
const varName = await checkEntrypoint(workPath, entry);
|
|
5109
|
+
if (varName) {
|
|
5010
5110
|
(0, import_build_utils7.debug)(`Using configured Python entrypoint: ${entry}`);
|
|
5011
|
-
return { entrypoint: entry };
|
|
5111
|
+
return { entrypoint: { entrypoint: entry, variableName: varName } };
|
|
5012
5112
|
}
|
|
5013
5113
|
const found = await findValidEntrypoint(
|
|
5014
5114
|
workPath,
|
|
@@ -5023,9 +5123,10 @@ async function detectGenericPythonEntrypoint(workPath, configuredEntrypoint) {
|
|
|
5023
5123
|
async function detectDjangoPythonEntrypoint(workPath, configuredEntrypoint) {
|
|
5024
5124
|
const entry = configuredEntrypoint.endsWith(".py") ? configuredEntrypoint : `${configuredEntrypoint}.py`;
|
|
5025
5125
|
try {
|
|
5026
|
-
|
|
5126
|
+
const varName = await checkEntrypoint(workPath, entry);
|
|
5127
|
+
if (varName) {
|
|
5027
5128
|
(0, import_build_utils7.debug)(`Using configured Python entrypoint: ${entry}`);
|
|
5028
|
-
return { entrypoint: entry };
|
|
5129
|
+
return { entrypoint: { entrypoint: entry, variableName: varName } };
|
|
5029
5130
|
}
|
|
5030
5131
|
const subdirs = await getSubdirectories(workPath);
|
|
5031
5132
|
const rootDirs = ["", ...subdirs];
|
|
@@ -5049,16 +5150,11 @@ async function detectPythonEntrypoint(framework, workPath, configuredEntrypoint)
|
|
|
5049
5150
|
if (result)
|
|
5050
5151
|
return result;
|
|
5051
5152
|
const pyprojectEntry = await getPyprojectEntrypoint(workPath);
|
|
5052
|
-
|
|
5053
|
-
return null;
|
|
5054
|
-
return {
|
|
5055
|
-
entrypoint: pyprojectEntry.entrypoint,
|
|
5056
|
-
variableName: pyprojectEntry.variableName
|
|
5057
|
-
};
|
|
5153
|
+
return pyprojectEntry ? { entrypoint: pyprojectEntry } : null;
|
|
5058
5154
|
}
|
|
5059
5155
|
|
|
5060
5156
|
// src/start-dev-server.ts
|
|
5061
|
-
var
|
|
5157
|
+
var import_python_analysis6 = require("@vercel/python-analysis");
|
|
5062
5158
|
var DEV_SERVER_STARTUP_TIMEOUT = 5 * 6e4;
|
|
5063
5159
|
function silenceNodeWarnings() {
|
|
5064
5160
|
const original = process.emitWarning.bind(
|
|
@@ -5151,7 +5247,7 @@ async function syncDependencies({
|
|
|
5151
5247
|
const syncDir = (0, import_path9.join)(workPath, ".vercel", "python", "sync");
|
|
5152
5248
|
(0, import_fs7.mkdirSync)(syncDir, { recursive: true });
|
|
5153
5249
|
const tempPyproject = (0, import_path9.join)(syncDir, "pyproject.toml");
|
|
5154
|
-
const content = (0,
|
|
5250
|
+
const content = (0, import_python_analysis6.stringifyManifest)(manifest.data);
|
|
5155
5251
|
(0, import_fs7.writeFileSync)(tempPyproject, content, "utf8");
|
|
5156
5252
|
manifestPath = tempPyproject;
|
|
5157
5253
|
(0, import_build_utils9.debug)(
|
|
@@ -5593,19 +5689,18 @@ var startDevServer = async (opts) => {
|
|
|
5593
5689
|
installGlobalCleanupHandlers();
|
|
5594
5690
|
const env = { ...process.env, ...meta.env || {} };
|
|
5595
5691
|
const serviceType = env.VERCEL_SERVICE_TYPE;
|
|
5596
|
-
let
|
|
5597
|
-
let variableName;
|
|
5692
|
+
let resolved;
|
|
5598
5693
|
if ((serviceType === "cron" || serviceType === "worker") && rawEntrypoint?.endsWith(".py")) {
|
|
5599
|
-
|
|
5694
|
+
resolved = { entrypoint: rawEntrypoint, variableName: "app" };
|
|
5600
5695
|
} else {
|
|
5601
5696
|
const detected = await detectPythonEntrypoint(
|
|
5602
5697
|
framework,
|
|
5603
5698
|
workPath,
|
|
5604
5699
|
rawEntrypoint
|
|
5605
5700
|
);
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5701
|
+
if (detected?.entrypoint) {
|
|
5702
|
+
resolved = detected.entrypoint;
|
|
5703
|
+
} else {
|
|
5609
5704
|
const hookResult = await runFrameworkHook(framework, {
|
|
5610
5705
|
pythonEnv: env,
|
|
5611
5706
|
projectDir: (0, import_path9.join)(workPath, detected?.baseDir ?? ""),
|
|
@@ -5613,10 +5708,9 @@ var startDevServer = async (opts) => {
|
|
|
5613
5708
|
entrypoint: rawEntrypoint,
|
|
5614
5709
|
detected: detected ?? void 0
|
|
5615
5710
|
});
|
|
5616
|
-
|
|
5617
|
-
variableName = hookResult?.variableName;
|
|
5711
|
+
resolved = hookResult?.entrypoint;
|
|
5618
5712
|
}
|
|
5619
|
-
if (!
|
|
5713
|
+
if (!resolved) {
|
|
5620
5714
|
const searched = PYTHON_CANDIDATE_ENTRYPOINTS.join(", ");
|
|
5621
5715
|
throw new import_build_utils9.NowBuildError({
|
|
5622
5716
|
code: "PYTHON_ENTRYPOINT_NOT_FOUND",
|
|
@@ -5626,6 +5720,7 @@ var startDevServer = async (opts) => {
|
|
|
5626
5720
|
});
|
|
5627
5721
|
}
|
|
5628
5722
|
}
|
|
5723
|
+
const { entrypoint: entry, variableName } = resolved;
|
|
5629
5724
|
const modulePath = entry.replace(/\.py$/i, "").replace(/[\\/]/g, ".");
|
|
5630
5725
|
let childProcess = null;
|
|
5631
5726
|
let stdoutLogListener = null;
|
|
@@ -5817,7 +5912,7 @@ If you are using a virtual environment, activate it before running "vercel dev",
|
|
|
5817
5912
|
|
|
5818
5913
|
// src/quirks/index.ts
|
|
5819
5914
|
var import_build_utils12 = require("@vercel/build-utils");
|
|
5820
|
-
var
|
|
5915
|
+
var import_python_analysis8 = require("@vercel/python-analysis");
|
|
5821
5916
|
|
|
5822
5917
|
// src/quirks/matplotlib.ts
|
|
5823
5918
|
var matplotlibQuirk = {
|
|
@@ -5897,7 +5992,7 @@ var import_fs9 = __toESM(require("fs"));
|
|
|
5897
5992
|
var import_path11 = require("path");
|
|
5898
5993
|
var import_execa4 = __toESM(require_execa());
|
|
5899
5994
|
var import_build_utils11 = require("@vercel/build-utils");
|
|
5900
|
-
var
|
|
5995
|
+
var import_python_analysis7 = require("@vercel/python-analysis");
|
|
5901
5996
|
function execErrorMessage(err) {
|
|
5902
5997
|
if (err != null && typeof err === "object" && "stderr" in err) {
|
|
5903
5998
|
const stderr = String(err.stderr);
|
|
@@ -6157,7 +6252,7 @@ echo "OpenSSL ${RUNTIME_OPENSSL_VERSION}.0 1 Jan 2024 (Library: OpenSSL ${RUNTIM
|
|
|
6157
6252
|
(0, import_path11.join)(sitePackages, "prisma"),
|
|
6158
6253
|
sitePackages
|
|
6159
6254
|
);
|
|
6160
|
-
const count = await (0,
|
|
6255
|
+
const count = await (0, import_python_analysis7.extendDistRecord)(sitePackages, "prisma", allFiles);
|
|
6161
6256
|
if (count > 0) {
|
|
6162
6257
|
(0, import_build_utils11.debug)(`Appended ${count} entries to prisma RECORD`);
|
|
6163
6258
|
}
|
|
@@ -6182,7 +6277,7 @@ var quirks = [litellmQuirk, prismaQuirk, matplotlibQuirk];
|
|
|
6182
6277
|
function toposortQuirks(activated) {
|
|
6183
6278
|
const nameToQuirk = /* @__PURE__ */ new Map();
|
|
6184
6279
|
for (const q of activated) {
|
|
6185
|
-
nameToQuirk.set((0,
|
|
6280
|
+
nameToQuirk.set((0, import_python_analysis8.normalizePackageName)(q.dependency), q);
|
|
6186
6281
|
}
|
|
6187
6282
|
const adj = /* @__PURE__ */ new Map();
|
|
6188
6283
|
const inDegree = /* @__PURE__ */ new Map();
|
|
@@ -6193,7 +6288,7 @@ function toposortQuirks(activated) {
|
|
|
6193
6288
|
for (const q of activated) {
|
|
6194
6289
|
if (q.runsBefore) {
|
|
6195
6290
|
for (const dep of q.runsBefore) {
|
|
6196
|
-
const target = nameToQuirk.get((0,
|
|
6291
|
+
const target = nameToQuirk.get((0, import_python_analysis8.normalizePackageName)(dep));
|
|
6197
6292
|
if (target) {
|
|
6198
6293
|
adj.get(q).add(target);
|
|
6199
6294
|
inDegree.set(target, inDegree.get(target) + 1);
|
|
@@ -6202,7 +6297,7 @@ function toposortQuirks(activated) {
|
|
|
6202
6297
|
}
|
|
6203
6298
|
if (q.runsAfter) {
|
|
6204
6299
|
for (const dep of q.runsAfter) {
|
|
6205
|
-
const source = nameToQuirk.get((0,
|
|
6300
|
+
const source = nameToQuirk.get((0, import_python_analysis8.normalizePackageName)(dep));
|
|
6206
6301
|
if (source) {
|
|
6207
6302
|
adj.get(source).add(q);
|
|
6208
6303
|
inDegree.set(q, inDegree.get(q) + 1);
|
|
@@ -6243,14 +6338,14 @@ async function runQuirks(ctx) {
|
|
|
6243
6338
|
const installedNames = /* @__PURE__ */ new Set();
|
|
6244
6339
|
const sitePackageDirs = await getVenvSitePackagesDirs(ctx.venvPath);
|
|
6245
6340
|
for (const dir of sitePackageDirs) {
|
|
6246
|
-
const distributions = await (0,
|
|
6341
|
+
const distributions = await (0, import_python_analysis8.scanDistributions)(dir);
|
|
6247
6342
|
for (const name of distributions.keys()) {
|
|
6248
|
-
installedNames.add((0,
|
|
6343
|
+
installedNames.add((0, import_python_analysis8.normalizePackageName)(name));
|
|
6249
6344
|
}
|
|
6250
6345
|
}
|
|
6251
6346
|
const activated = quirks.filter((quirk) => {
|
|
6252
6347
|
const installed = installedNames.has(
|
|
6253
|
-
(0,
|
|
6348
|
+
(0, import_python_analysis8.normalizePackageName)(quirk.dependency)
|
|
6254
6349
|
);
|
|
6255
6350
|
if (!installed) {
|
|
6256
6351
|
(0, import_build_utils12.debug)(`Quirk "${quirk.dependency}": not installed, skipping`);
|
|
@@ -6329,6 +6424,7 @@ async function runDjangoCollectStatic(venvPath, workPath, env, outputStaticDir,
|
|
|
6329
6424
|
return {
|
|
6330
6425
|
staticSourceDirs,
|
|
6331
6426
|
staticRoot: staticRoot ? (0, import_path12.resolve)(workPath, staticRoot) : null,
|
|
6427
|
+
cdnOutputDir: null,
|
|
6332
6428
|
manifestRelPath: null
|
|
6333
6429
|
};
|
|
6334
6430
|
}
|
|
@@ -6380,14 +6476,15 @@ async function runDjangoCollectStatic(venvPath, workPath, env, outputStaticDir,
|
|
|
6380
6476
|
return {
|
|
6381
6477
|
staticSourceDirs,
|
|
6382
6478
|
staticRoot: staticRoot ? (0, import_path12.resolve)(workPath, staticRoot) : null,
|
|
6479
|
+
cdnOutputDir: outputStaticDir,
|
|
6383
6480
|
manifestRelPath
|
|
6384
6481
|
};
|
|
6385
6482
|
}
|
|
6386
6483
|
|
|
6387
6484
|
// src/index.ts
|
|
6388
|
-
var
|
|
6485
|
+
var import_python_analysis9 = require("@vercel/python-analysis");
|
|
6389
6486
|
var writeFile = import_fs11.default.promises.writeFile;
|
|
6390
|
-
var version =
|
|
6487
|
+
var version = -1;
|
|
6391
6488
|
async function runFrameworkHook(framework, ctx) {
|
|
6392
6489
|
const hook = framework ? frameworkHooks[framework] : void 0;
|
|
6393
6490
|
return hook?.(ctx);
|
|
@@ -6409,28 +6506,27 @@ var frameworkHooks = {
|
|
|
6409
6506
|
if (!settingsResult)
|
|
6410
6507
|
return;
|
|
6411
6508
|
const { djangoSettings, settingsModule } = settingsResult;
|
|
6412
|
-
let
|
|
6413
|
-
let variableName;
|
|
6509
|
+
let resolvedEntrypoint;
|
|
6414
6510
|
const baseDir = detected?.baseDir ?? "";
|
|
6415
6511
|
const asgiApp = djangoSettings["ASGI_APPLICATION"];
|
|
6416
6512
|
if (typeof asgiApp === "string") {
|
|
6417
6513
|
const parts = asgiApp.split(".");
|
|
6418
|
-
variableName = parts.at(-1);
|
|
6514
|
+
const variableName = parts.at(-1);
|
|
6419
6515
|
const rel = `${parts.slice(0, -1).join("/")}.py`;
|
|
6420
|
-
|
|
6421
|
-
(0, import_build_utils14.debug)(
|
|
6422
|
-
|
|
6423
|
-
);
|
|
6516
|
+
const ep = baseDir ? `${baseDir}/${rel}` : rel;
|
|
6517
|
+
(0, import_build_utils14.debug)(`Django hook: ASGI entrypoint: ${ep} (variable: ${variableName})`);
|
|
6518
|
+
resolvedEntrypoint = { entrypoint: ep, variableName };
|
|
6424
6519
|
} else {
|
|
6425
6520
|
const wsgiApp = djangoSettings["WSGI_APPLICATION"];
|
|
6426
6521
|
if (typeof wsgiApp === "string") {
|
|
6427
6522
|
const parts = wsgiApp.split(".");
|
|
6428
|
-
variableName = parts.at(-1);
|
|
6523
|
+
const variableName = parts.at(-1);
|
|
6429
6524
|
const rel = `${parts.slice(0, -1).join("/")}.py`;
|
|
6430
|
-
|
|
6525
|
+
const ep = baseDir ? `${baseDir}/${rel}` : rel;
|
|
6431
6526
|
(0, import_build_utils14.debug)(
|
|
6432
|
-
`Django hook: WSGI entrypoint: ${
|
|
6527
|
+
`Django hook: WSGI entrypoint: ${ep} (variable: ${variableName})`
|
|
6433
6528
|
);
|
|
6529
|
+
resolvedEntrypoint = { entrypoint: ep, variableName };
|
|
6434
6530
|
}
|
|
6435
6531
|
}
|
|
6436
6532
|
let djangoStatic = null;
|
|
@@ -6445,7 +6541,7 @@ var frameworkHooks = {
|
|
|
6445
6541
|
djangoSettings
|
|
6446
6542
|
);
|
|
6447
6543
|
}
|
|
6448
|
-
return { entrypoint
|
|
6544
|
+
return { entrypoint: resolvedEntrypoint, djangoStatic };
|
|
6449
6545
|
}
|
|
6450
6546
|
};
|
|
6451
6547
|
async function downloadFilesInWorkPath({
|
|
@@ -6458,7 +6554,8 @@ async function downloadFilesInWorkPath({
|
|
|
6458
6554
|
let downloadedFiles = await (0, import_build_utils14.download)(files, workPath, meta);
|
|
6459
6555
|
if (meta.isDev) {
|
|
6460
6556
|
const { devCacheDir = (0, import_path13.join)(workPath, ".now", "cache") } = meta;
|
|
6461
|
-
const
|
|
6557
|
+
const cacheKey = (0, import_path13.basename)(entrypoint).replace(/\./g, "_");
|
|
6558
|
+
const destCache = (0, import_path13.join)(devCacheDir, cacheKey);
|
|
6462
6559
|
await (0, import_build_utils14.download)(downloadedFiles, destCache);
|
|
6463
6560
|
downloadedFiles = await (0, import_build_utils14.glob)("**", destCache);
|
|
6464
6561
|
workPath = destCache;
|
|
@@ -6509,9 +6606,9 @@ var build = async ({
|
|
|
6509
6606
|
) ?? void 0;
|
|
6510
6607
|
if (detected?.entrypoint) {
|
|
6511
6608
|
(0, import_build_utils14.debug)(
|
|
6512
|
-
`Resolved Python entrypoint to "${detected.entrypoint}" (configured "${entrypoint}" not found).`
|
|
6609
|
+
`Resolved Python entrypoint to "${detected.entrypoint.entrypoint}" (configured "${entrypoint}" not found).`
|
|
6513
6610
|
);
|
|
6514
|
-
entrypoint = detected.entrypoint;
|
|
6611
|
+
entrypoint = detected.entrypoint.entrypoint;
|
|
6515
6612
|
} else {
|
|
6516
6613
|
const searchedList = PYTHON_CANDIDATE_ENTRYPOINTS.join(", ");
|
|
6517
6614
|
entrypointNotFound = new import_build_utils14.NowBuildError({
|
|
@@ -6522,6 +6619,27 @@ var build = async ({
|
|
|
6522
6619
|
});
|
|
6523
6620
|
}
|
|
6524
6621
|
}
|
|
6622
|
+
if (!detected?.entrypoint && entrypoint.endsWith(".py") && fsFiles[entrypoint]) {
|
|
6623
|
+
const content = await import_fs11.default.promises.readFile(
|
|
6624
|
+
(0, import_path13.join)(workPath, entrypoint),
|
|
6625
|
+
"utf-8"
|
|
6626
|
+
);
|
|
6627
|
+
let varName = await (0, import_python_analysis9.findAppOrHandler)(content);
|
|
6628
|
+
if (!varName) {
|
|
6629
|
+
const isSpecialService = service?.type === "cron" || service?.type === "worker";
|
|
6630
|
+
if (isSpecialService) {
|
|
6631
|
+
varName = "app";
|
|
6632
|
+
} else if (!varName) {
|
|
6633
|
+
throw new import_build_utils14.NowBuildError({
|
|
6634
|
+
code: "PYTHON_ENTRYPOINT_NOT_FOUND",
|
|
6635
|
+
message: `Could not find a top-level "app", "application", or "handler" in "${entrypoint}".`,
|
|
6636
|
+
link: "https://vercel.com/docs/functions/serverless-functions/runtimes/python",
|
|
6637
|
+
action: "Learn More"
|
|
6638
|
+
});
|
|
6639
|
+
}
|
|
6640
|
+
}
|
|
6641
|
+
detected = { entrypoint: { entrypoint, variableName: varName } };
|
|
6642
|
+
}
|
|
6525
6643
|
if (entrypointNotFound && detected?.baseDir === void 0) {
|
|
6526
6644
|
throw entrypointNotFound;
|
|
6527
6645
|
}
|
|
@@ -6596,8 +6714,11 @@ var build = async ({
|
|
|
6596
6714
|
let uv;
|
|
6597
6715
|
try {
|
|
6598
6716
|
const uvPath = await getUvBinaryOrInstall(pythonVersion.pythonPath);
|
|
6599
|
-
console.log(`Using uv at "${uvPath}"`);
|
|
6600
6717
|
uv = new UvRunner(uvPath);
|
|
6718
|
+
const uvVersionOutput = (0, import_child_process3.execSync)(`${uvPath} --version`, {
|
|
6719
|
+
encoding: "utf8"
|
|
6720
|
+
}).trim();
|
|
6721
|
+
console.log(`Using ${uvVersionOutput}`);
|
|
6601
6722
|
} catch (err) {
|
|
6602
6723
|
console.log("Failed to install or locate uv");
|
|
6603
6724
|
throw new Error(
|
|
@@ -6636,6 +6757,7 @@ var build = async ({
|
|
|
6636
6757
|
const { projectDir, lockPath, lockFileProvidedByUser } = await ensureUvProject({
|
|
6637
6758
|
workPath,
|
|
6638
6759
|
rootDir,
|
|
6760
|
+
venvPath,
|
|
6639
6761
|
pythonPackage,
|
|
6640
6762
|
pythonVersion: pythonVersionString(pythonVersion),
|
|
6641
6763
|
uv,
|
|
@@ -6682,8 +6804,9 @@ var build = async ({
|
|
|
6682
6804
|
entrypoint,
|
|
6683
6805
|
detected
|
|
6684
6806
|
});
|
|
6685
|
-
|
|
6686
|
-
|
|
6807
|
+
const resolved = hookResult?.entrypoint ?? detected?.entrypoint;
|
|
6808
|
+
if (entrypointNotFound && resolved) {
|
|
6809
|
+
entrypoint = resolved.entrypoint;
|
|
6687
6810
|
entrypointNotFound = void 0;
|
|
6688
6811
|
}
|
|
6689
6812
|
if (entrypointNotFound) {
|
|
@@ -6716,7 +6839,7 @@ var build = async ({
|
|
|
6716
6839
|
if (handlerFunction) {
|
|
6717
6840
|
const entrypointPath = (0, import_path13.join)(workPath, entrypoint);
|
|
6718
6841
|
const source = await import_fs11.default.promises.readFile(entrypointPath, "utf-8");
|
|
6719
|
-
const found = await (0,
|
|
6842
|
+
const found = await (0, import_python_analysis9.containsTopLevelCallable)(source, handlerFunction);
|
|
6720
6843
|
if (!found) {
|
|
6721
6844
|
throw new import_build_utils14.NowBuildError({
|
|
6722
6845
|
code: "PYTHON_HANDLER_NOT_FOUND",
|
|
@@ -6730,7 +6853,7 @@ var build = async ({
|
|
|
6730
6853
|
(0, import_build_utils14.debug)("Entrypoint with suffix is", entrypointWithSuffix);
|
|
6731
6854
|
const handlerFuncEnvLine = handlerFunction ? `
|
|
6732
6855
|
"__VC_HANDLER_FUNC_NAME": "${handlerFunction}",` : "";
|
|
6733
|
-
const variableName =
|
|
6856
|
+
const variableName = resolved?.variableName ?? "";
|
|
6734
6857
|
const runtimeTrampoline = `
|
|
6735
6858
|
import importlib
|
|
6736
6859
|
import os
|
|
@@ -6875,7 +6998,24 @@ from vercel_runtime.vc_init import vc_handler
|
|
|
6875
6998
|
);
|
|
6876
6999
|
}
|
|
6877
7000
|
}
|
|
6878
|
-
|
|
7001
|
+
if (djangoStatic?.cdnOutputDir) {
|
|
7002
|
+
const lambdaPath = entrypoint.replace(/\.py$/, "");
|
|
7003
|
+
const staticFiles = await (0, import_build_utils14.glob)("**", { cwd: djangoStatic.cdnOutputDir });
|
|
7004
|
+
return {
|
|
7005
|
+
resultVersion: 2,
|
|
7006
|
+
result: {
|
|
7007
|
+
output: {
|
|
7008
|
+
[lambdaPath]: output,
|
|
7009
|
+
...staticFiles
|
|
7010
|
+
},
|
|
7011
|
+
routes: [
|
|
7012
|
+
{ handle: "filesystem" },
|
|
7013
|
+
{ src: "/(.*)", dest: `/${lambdaPath}` }
|
|
7014
|
+
]
|
|
7015
|
+
}
|
|
7016
|
+
};
|
|
7017
|
+
}
|
|
7018
|
+
return { resultVersion: 3, result: { output } };
|
|
6879
7019
|
};
|
|
6880
7020
|
var shouldServe = (opts) => {
|
|
6881
7021
|
const framework = opts.config.framework;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vercel/python",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.28.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"directory": "packages/python"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@vercel/python-analysis": "0.
|
|
18
|
+
"@vercel/python-analysis": "0.11.0"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@renovatebot/pep440": "4.2.1",
|
|
@@ -36,14 +36,14 @@
|
|
|
36
36
|
"smol-toml": "1.5.2",
|
|
37
37
|
"vitest": "2.1.4",
|
|
38
38
|
"which": "3.0.0",
|
|
39
|
-
"@vercel/build-utils": "13.
|
|
40
|
-
"@vercel/
|
|
41
|
-
"@vercel/
|
|
39
|
+
"@vercel/build-utils": "13.10.0",
|
|
40
|
+
"@vercel/python-runtime": "0.11.0",
|
|
41
|
+
"@vercel/error-utils": "2.0.3"
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"build": "node ../../utils/build-builder.mjs",
|
|
45
45
|
"type-check": "tsc --noEmit",
|
|
46
|
-
"test": "cross-env VERCEL_FORCE_PYTHON_STREAMING=1 jest --reporters=default --reporters=jest-junit --env node --verbose --runInBand --bail",
|
|
46
|
+
"test": "cross-env VERCEL_FORCE_PYTHON_STREAMING=1 NODE_OPTIONS=--experimental-vm-modules jest --reporters=default --reporters=jest-junit --env node --verbose --runInBand --bail",
|
|
47
47
|
"test-unit": "vitest run --config ../../vitest.config.mts test/unit.test.ts",
|
|
48
48
|
"test-e2e": "pnpm test test/integration-*",
|
|
49
49
|
"vitest-run": "vitest -c ../../vitest.config.mts",
|