@vercel/python 6.30.0 → 6.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +123 -85
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -3225,19 +3225,19 @@ __export(src_exports, {
3225
3225
  });
3226
3226
  module.exports = __toCommonJS(src_exports);
3227
3227
  var import_child_process3 = require("child_process");
3228
- var import_fs11 = __toESM(require("fs"));
3228
+ var import_fs12 = __toESM(require("fs"));
3229
3229
  var import_path13 = require("path");
3230
3230
 
3231
3231
  // src/package-versions.ts
3232
3232
  var VERCEL_RUNTIME_VERSION = "0.12.0";
3233
- var VERCEL_WORKERS_VERSION = "0.0.15";
3233
+ var VERCEL_WORKERS_VERSION = "0.0.16";
3234
3234
 
3235
3235
  // src/index.ts
3236
3236
  var import_build_utils15 = require("@vercel/build-utils");
3237
3237
 
3238
3238
  // src/install.ts
3239
3239
  var import_execa3 = __toESM(require_execa());
3240
- var import_fs3 = __toESM(require("fs"));
3240
+ var import_fs4 = __toESM(require("fs"));
3241
3241
  var import_path5 = require("path");
3242
3242
  var import_build_utils4 = require("@vercel/build-utils");
3243
3243
  var import_python_analysis2 = require("@vercel/python-analysis");
@@ -3265,8 +3265,14 @@ var UV_PYTHON_DOWNLOADS_MODE = "automatic";
3265
3265
  var UV_CACHE_DIR_SUBPATH = [".vercel", "python", "cache", "uv"];
3266
3266
  var isWin = process.platform === "win32";
3267
3267
  var uvExec = isWin ? "uv.exe" : "uv";
3268
+ var KNOWN_UV_PATH = "/usr/local/bin/uv";
3269
+ function findUvOnBuildImage(knownPath = KNOWN_UV_PATH) {
3270
+ if (!process.env.VERCEL_BUILD_IMAGE)
3271
+ return null;
3272
+ return import_fs.default.existsSync(knownPath) ? knownPath : null;
3273
+ }
3268
3274
  function findUvInPath() {
3269
- return import_which.default.sync("uv", { nothrow: true });
3275
+ return findUvOnBuildImage() ?? import_which.default.sync("uv", { nothrow: true });
3270
3276
  }
3271
3277
  function getUvCacheDir(workPath) {
3272
3278
  return (0, import_path.join)(workPath, ...UV_CACHE_DIR_SUBPATH);
@@ -3448,6 +3454,9 @@ async function getUserScriptsDir(pythonPath) {
3448
3454
  }
3449
3455
  }
3450
3456
  async function findUvBinary(pythonPath) {
3457
+ const buildImageUv = findUvOnBuildImage();
3458
+ if (buildImageUv)
3459
+ return buildImageUv;
3451
3460
  const found = import_which.default.sync("uv", { nothrow: true });
3452
3461
  if (found)
3453
3462
  return found;
@@ -3573,7 +3582,9 @@ function useVirtualEnv(workPath, env, systemPython) {
3573
3582
  function createVenvEnv(venvPath, baseEnv = process.env, uvCacheDir) {
3574
3583
  const env = {
3575
3584
  ...getProtectedUvEnv(baseEnv, uvCacheDir),
3576
- VIRTUAL_ENV: venvPath
3585
+ VIRTUAL_ENV: venvPath,
3586
+ UV_PROJECT_ENVIRONMENT: venvPath,
3587
+ UV_NO_DEV: "true"
3577
3588
  };
3578
3589
  const binDir = getVenvBinDir(venvPath);
3579
3590
  const existingPath = env.PATH || process.env.PATH || "";
@@ -3729,6 +3740,7 @@ function detectPlatform() {
3729
3740
 
3730
3741
  // src/version.ts
3731
3742
  var import_path4 = require("path");
3743
+ var import_fs3 = require("fs");
3732
3744
  var import_build_utils3 = require("@vercel/build-utils");
3733
3745
  var import_python_analysis = require("@vercel/python-analysis");
3734
3746
  function pythonVersionString(pv) {
@@ -3932,10 +3944,24 @@ function isDiscontinued({ discontinueDate }) {
3932
3944
  return discontinueDate !== void 0 && discontinueDate.getTime() <= today;
3933
3945
  }
3934
3946
  var installedPythonsCache = null;
3947
+ function getInstalledPythonsFromFilesystem(basePath = UV_PYTHON_PATH_PREFIX) {
3948
+ const result = /* @__PURE__ */ new Set();
3949
+ for (const opt of allOptions) {
3950
+ const binPath = (0, import_path4.join)(basePath, "bin", `python${opt.major}.${opt.minor}`);
3951
+ if ((0, import_fs3.existsSync)(binPath)) {
3952
+ result.add(pythonVersionString(opt));
3953
+ }
3954
+ }
3955
+ return result;
3956
+ }
3935
3957
  function getInstalledPythons() {
3936
3958
  if (installedPythonsCache !== null) {
3937
3959
  return installedPythonsCache;
3938
3960
  }
3961
+ if (process.env.VERCEL_BUILD_IMAGE) {
3962
+ installedPythonsCache = getInstalledPythonsFromFilesystem();
3963
+ return installedPythonsCache;
3964
+ }
3939
3965
  const uvPath = findUvInPath();
3940
3966
  if (!uvPath) {
3941
3967
  throw new import_build_utils3.NowBuildError({
@@ -3966,9 +3992,9 @@ async function restoreCachedLock(cachedLockPath, projectDir) {
3966
3992
  if (!cachedLockPath)
3967
3993
  return;
3968
3994
  const targetLockPath = (0, import_path5.join)(projectDir, "uv.lock");
3969
- if (import_fs3.default.existsSync(cachedLockPath) && !import_fs3.default.existsSync(targetLockPath)) {
3995
+ if (import_fs4.default.existsSync(cachedLockPath) && !import_fs4.default.existsSync(targetLockPath)) {
3970
3996
  (0, import_build_utils4.debug)("Restoring cached uv.lock");
3971
- await import_fs3.default.promises.copyFile(cachedLockPath, targetLockPath);
3997
+ await import_fs4.default.promises.copyFile(cachedLockPath, targetLockPath);
3972
3998
  }
3973
3999
  }
3974
4000
  var makeDependencyCheckCode = (dependency) => `
@@ -4115,7 +4141,7 @@ async function ensureUvProject({
4115
4141
  lockPath = (0, import_path5.join)(rootDir, lockFile.path);
4116
4142
  projectDir = (0, import_path5.dirname)(lockPath);
4117
4143
  pyprojectPath = (0, import_path5.join)(projectDir, "pyproject.toml");
4118
- if (!import_fs3.default.existsSync(pyprojectPath)) {
4144
+ if (!import_fs4.default.existsSync(pyprojectPath)) {
4119
4145
  throw new Error(
4120
4146
  `Expected "pyproject.toml" next to "${lockFile.kind}" in "${projectDir}"`
4121
4147
  );
@@ -4142,7 +4168,7 @@ async function ensureUvProject({
4142
4168
  }
4143
4169
  const content = (0, import_python_analysis2.stringifyManifest)(manifest.data);
4144
4170
  pyprojectPath = (0, import_path5.join)(projectDir, "pyproject.toml");
4145
- await import_fs3.default.promises.writeFile(pyprojectPath, content);
4171
+ await import_fs4.default.promises.writeFile(pyprojectPath, content);
4146
4172
  }
4147
4173
  const workspaceLockFile = pythonPackage.workspaceLockFile;
4148
4174
  if (workspaceLockFile) {
@@ -4169,7 +4195,7 @@ async function ensureUvProject({
4169
4195
  dependencies: []
4170
4196
  });
4171
4197
  const content = (0, import_python_analysis2.stringifyManifest)(minimalManifest);
4172
- await import_fs3.default.promises.writeFile(pyprojectPath, content);
4198
+ await import_fs4.default.promises.writeFile(pyprojectPath, content);
4173
4199
  await restoreCachedLock(cachedLockPath, projectDir);
4174
4200
  await uv.lock({
4175
4201
  projectDir,
@@ -4177,7 +4203,7 @@ async function ensureUvProject({
4177
4203
  ...requireBinaryWheels ? { noBuild: true, upgrade: true } : {}
4178
4204
  });
4179
4205
  }
4180
- const resolvedLockPath = lockPath && import_fs3.default.existsSync(lockPath) ? lockPath : (0, import_path5.join)(projectDir, "uv.lock");
4206
+ const resolvedLockPath = lockPath && import_fs4.default.existsSync(lockPath) ? lockPath : (0, import_path5.join)(projectDir, "uv.lock");
4181
4207
  return {
4182
4208
  projectDir,
4183
4209
  pyprojectPath,
@@ -4278,12 +4304,12 @@ async function installRequirementsFile({
4278
4304
  }
4279
4305
 
4280
4306
  // src/dependency-externalizer.ts
4281
- var import_fs4 = __toESM(require("fs"));
4307
+ var import_fs5 = __toESM(require("fs"));
4282
4308
  var import_util = require("util");
4283
4309
  var import_path6 = require("path");
4284
4310
  var import_build_utils5 = require("@vercel/build-utils");
4285
4311
  var import_python_analysis3 = require("@vercel/python-analysis");
4286
- var readFile = (0, import_util.promisify)(import_fs4.default.readFile);
4312
+ var readFile = (0, import_util.promisify)(import_fs5.default.readFile);
4287
4313
  var LAMBDA_SIZE_THRESHOLD_BYTES = 245 * 1024 * 1024;
4288
4314
  var LAMBDA_EPHEMERAL_STORAGE_BYTES = 500 * 1024 * 1024;
4289
4315
  var PythonDependencyExternalizer = class {
@@ -4486,7 +4512,7 @@ To fix this, either:
4486
4512
  if (process.env.VERCEL_BUILD_IMAGE) {
4487
4513
  try {
4488
4514
  const uvBinaryPath = await getUvBinaryForBundling(this.pythonPath);
4489
- const uvStats = await import_fs4.default.promises.stat(uvBinaryPath);
4515
+ const uvStats = await import_fs5.default.promises.stat(uvBinaryPath);
4490
4516
  runtimeToolingOverhead = uvStats.size;
4491
4517
  } catch {
4492
4518
  runtimeToolingOverhead = 50 * 1024 * 1024;
@@ -4498,8 +4524,8 @@ To fix this, either:
4498
4524
  const isOutsideWorkPath = projectDirRel.startsWith("..") || uvLockRel.startsWith("..");
4499
4525
  if (isOutsideWorkPath) {
4500
4526
  const pyprojectPath = (0, import_path6.join)(this.uvProjectDir, "pyproject.toml");
4501
- const pyprojectStats = await import_fs4.default.promises.stat(pyprojectPath).catch(() => null);
4502
- const uvLockStats = await import_fs4.default.promises.stat(this.uvLockPath).catch(() => null);
4527
+ const pyprojectStats = await import_fs5.default.promises.stat(pyprojectPath).catch(() => null);
4528
+ const uvLockStats = await import_fs5.default.promises.stat(this.uvLockPath).catch(() => null);
4503
4529
  if (pyprojectStats)
4504
4530
  runtimeToolingOverhead += pyprojectStats.size;
4505
4531
  if (uvLockStats)
@@ -4554,9 +4580,9 @@ To fix this, either:
4554
4580
  const uvBinaryPath = await getUvBinaryForBundling(this.pythonPath);
4555
4581
  const uvBundleDir = (0, import_path6.join)(this.workPath, UV_BUNDLE_DIR);
4556
4582
  const uvLocalPath = (0, import_path6.join)(uvBundleDir, "uv");
4557
- await import_fs4.default.promises.mkdir(uvBundleDir, { recursive: true });
4558
- await import_fs4.default.promises.copyFile(uvBinaryPath, uvLocalPath);
4559
- await import_fs4.default.promises.chmod(uvLocalPath, 493);
4583
+ await import_fs5.default.promises.mkdir(uvBundleDir, { recursive: true });
4584
+ await import_fs5.default.promises.copyFile(uvBinaryPath, uvLocalPath);
4585
+ await import_fs5.default.promises.chmod(uvLocalPath, 493);
4560
4586
  const uvBundlePath = `${UV_BUNDLE_DIR}/uv`;
4561
4587
  files[uvBundlePath] = new import_build_utils5.FileFsRef({
4562
4588
  fsPath: uvLocalPath,
@@ -4729,7 +4755,7 @@ async function mirrorPackagesIntoVendor({
4729
4755
  const includeSet = includePackages ? new Set(includePackages.map(import_python_analysis3.normalizePackageName)) : null;
4730
4756
  const sitePackageDirs = await getVenvSitePackagesDirs(venvPath);
4731
4757
  for (const dir of sitePackageDirs) {
4732
- if (!import_fs4.default.existsSync(dir))
4758
+ if (!import_fs5.default.existsSync(dir))
4733
4759
  continue;
4734
4760
  const resolvedDir = (0, import_path6.resolve)(dir);
4735
4761
  const dirPrefix = resolvedDir + import_path6.sep;
@@ -4746,7 +4772,7 @@ async function mirrorPackagesIntoVendor({
4746
4772
  continue;
4747
4773
  }
4748
4774
  const srcFsPath = (0, import_path6.join)(dir, filePath);
4749
- if (!import_fs4.default.existsSync(srcFsPath)) {
4775
+ if (!import_fs5.default.existsSync(srcFsPath)) {
4750
4776
  continue;
4751
4777
  }
4752
4778
  const bundlePath = (0, import_path6.join)(vendorDirName, filePath).replace(/\\/g, "/");
@@ -4765,7 +4791,7 @@ async function calculateBundleSize(files) {
4765
4791
  const file = files[filePath];
4766
4792
  if ("fsPath" in file && file.fsPath) {
4767
4793
  try {
4768
- const stats = await import_fs4.default.promises.stat(file.fsPath);
4794
+ const stats = await import_fs5.default.promises.stat(file.fsPath);
4769
4795
  totalSize += stats.size;
4770
4796
  } catch (err) {
4771
4797
  console.warn(
@@ -4798,7 +4824,7 @@ async function calculatePerPackageSizes(venvPath) {
4798
4824
  const sizes = /* @__PURE__ */ new Map();
4799
4825
  const sitePackageDirs = await getVenvSitePackagesDirs(venvPath);
4800
4826
  for (const dir of sitePackageDirs) {
4801
- if (!import_fs4.default.existsSync(dir))
4827
+ if (!import_fs5.default.existsSync(dir))
4802
4828
  continue;
4803
4829
  const resolvedDir = (0, import_path6.resolve)(dir);
4804
4830
  const dirPrefix = resolvedDir + import_path6.sep;
@@ -4814,7 +4840,7 @@ async function calculatePerPackageSizes(venvPath) {
4814
4840
  continue;
4815
4841
  }
4816
4842
  try {
4817
- const stats = await import_fs4.default.promises.stat((0, import_path6.join)(dir, filePath));
4843
+ const stats = await import_fs5.default.promises.stat((0, import_path6.join)(dir, filePath));
4818
4844
  totalSize += stats.size;
4819
4845
  } catch {
4820
4846
  }
@@ -4826,7 +4852,7 @@ async function calculatePerPackageSizes(venvPath) {
4826
4852
  }
4827
4853
 
4828
4854
  // src/diagnostics.ts
4829
- var import_fs5 = __toESM(require("fs"));
4855
+ var import_fs6 = __toESM(require("fs"));
4830
4856
  var import_path7 = require("path");
4831
4857
  var import_build_utils6 = require("@vercel/build-utils");
4832
4858
  var import_python_analysis4 = require("@vercel/python-analysis");
@@ -4943,7 +4969,7 @@ async function generateProjectManifest({
4943
4969
  const directEntries = [];
4944
4970
  const transitiveEntries = [];
4945
4971
  {
4946
- const content = await import_fs5.default.promises.readFile(uvLockPath, "utf-8");
4972
+ const content = await import_fs6.default.promises.readFile(uvLockPath, "utf-8");
4947
4973
  const uvLock = (0, import_python_analysis4.parseUvLock)(content, uvLockPath);
4948
4974
  const projectName = project?.name;
4949
4975
  const excludeSet = new Set(
@@ -5047,15 +5073,15 @@ async function generateProjectManifest({
5047
5073
  ]
5048
5074
  };
5049
5075
  const outPath = (0, import_path7.join)(workPath, DIAGNOSTICS_PATH);
5050
- await import_fs5.default.promises.mkdir((0, import_path7.dirname)(outPath), { recursive: true });
5051
- await import_fs5.default.promises.writeFile(outPath, JSON.stringify(manifest, null, 2));
5076
+ await import_fs6.default.promises.mkdir((0, import_path7.dirname)(outPath), { recursive: true });
5077
+ await import_fs6.default.promises.writeFile(outPath, JSON.stringify(manifest, null, 2));
5052
5078
  }
5053
5079
  var diagnostics = async ({
5054
5080
  workPath
5055
5081
  }) => {
5056
5082
  try {
5057
5083
  const manifestPath = (0, import_path7.join)(workPath, DIAGNOSTICS_PATH);
5058
- const data = await import_fs5.default.promises.readFile(manifestPath, "utf-8");
5084
+ const data = await import_fs6.default.promises.readFile(manifestPath, "utf-8");
5059
5085
  return {
5060
5086
  [MANIFEST_FILENAME]: new import_build_utils6.FileBlob({ data })
5061
5087
  };
@@ -5069,14 +5095,14 @@ var diagnostics = async ({
5069
5095
 
5070
5096
  // src/start-dev-server.ts
5071
5097
  var import_child_process2 = require("child_process");
5072
- var import_fs7 = require("fs");
5098
+ var import_fs8 = require("fs");
5073
5099
  var import_path9 = require("path");
5074
5100
  var import_build_utils10 = require("@vercel/build-utils");
5075
5101
  var import_get_port = __toESM(require_get_port());
5076
5102
  var import_is_port_reachable = __toESM(require_is_port_reachable());
5077
5103
 
5078
5104
  // src/entrypoint.ts
5079
- var import_fs6 = __toESM(require("fs"));
5105
+ var import_fs7 = __toESM(require("fs"));
5080
5106
  var import_path8 = require("path");
5081
5107
  var import_build_utils7 = require("@vercel/build-utils");
5082
5108
  var import_build_utils8 = require("@vercel/build-utils");
@@ -5103,7 +5129,7 @@ function getCandidateEntrypointsInDirs(dirs) {
5103
5129
  }
5104
5130
  async function fileExists(filePath) {
5105
5131
  try {
5106
- const stat = await import_fs6.default.promises.stat(filePath);
5132
+ const stat = await import_fs7.default.promises.stat(filePath);
5107
5133
  return stat.isFile();
5108
5134
  } catch {
5109
5135
  return false;
@@ -5113,7 +5139,7 @@ async function checkEntrypoint(workPath, relPath) {
5113
5139
  const absPath = (0, import_path8.join)(workPath, relPath);
5114
5140
  if (!await fileExists(absPath))
5115
5141
  return null;
5116
- const content = await import_fs6.default.promises.readFile(absPath, "utf-8");
5142
+ const content = await import_fs7.default.promises.readFile(absPath, "utf-8");
5117
5143
  return (0, import_python_analysis5.findAppOrHandler)(content);
5118
5144
  }
5119
5145
  async function getPyprojectEntrypoint(workPath) {
@@ -5151,7 +5177,7 @@ async function findValidEntrypoint(workPath, candidates) {
5151
5177
  async function checkDjangoManage(workPath) {
5152
5178
  const managePath = (0, import_path8.join)(workPath, "manage.py");
5153
5179
  try {
5154
- const content = await import_fs6.default.promises.readFile(managePath, "utf-8");
5180
+ const content = await import_fs7.default.promises.readFile(managePath, "utf-8");
5155
5181
  if (!content.includes("DJANGO_SETTINGS_MODULE"))
5156
5182
  return false;
5157
5183
  (0, import_build_utils8.debug)(`Found Django manage.py with DJANGO_SETTINGS_MODULE at ${workPath}`);
@@ -5162,7 +5188,7 @@ async function checkDjangoManage(workPath) {
5162
5188
  }
5163
5189
  async function getSubdirectories(workPath) {
5164
5190
  try {
5165
- const entries = await import_fs6.default.promises.readdir(workPath, {
5191
+ const entries = await import_fs7.default.promises.readdir(workPath, {
5166
5192
  withFileTypes: true
5167
5193
  });
5168
5194
  return entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name).sort();
@@ -5212,8 +5238,9 @@ async function detectDjangoPythonEntrypoint(workPath) {
5212
5238
  }
5213
5239
  async function detectPythonEntrypoint(framework, workPath, configuredEntrypoint, service) {
5214
5240
  if (configuredEntrypoint) {
5215
- const entrypoint = configuredEntrypoint.endsWith(".py") ? configuredEntrypoint : `${configuredEntrypoint}.py`;
5216
- let varName = await checkEntrypoint(workPath, entrypoint);
5241
+ const { filePath: configEntryFile, varName: configEntryVar } = configuredEntrypoint;
5242
+ const entrypoint = configEntryFile.endsWith(".py") ? configEntryFile : `${configEntryFile}.py`;
5243
+ let varName = configEntryVar ?? await checkEntrypoint(workPath, entrypoint);
5217
5244
  if (!varName) {
5218
5245
  const isSpecialService = service?.type === "cron" || service?.type === "worker";
5219
5246
  if (isSpecialService) {
@@ -5336,10 +5363,10 @@ async function syncDependencies({
5336
5363
  }
5337
5364
  if (manifest?.origin && manifestType === "pyproject.toml") {
5338
5365
  const syncDir = (0, import_path9.join)(workPath, ".vercel", "python", "sync");
5339
- (0, import_fs7.mkdirSync)(syncDir, { recursive: true });
5366
+ (0, import_fs8.mkdirSync)(syncDir, { recursive: true });
5340
5367
  const tempPyproject = (0, import_path9.join)(syncDir, "pyproject.toml");
5341
5368
  const content = (0, import_python_analysis6.stringifyManifest)(manifest.data);
5342
- (0, import_fs7.writeFileSync)(tempPyproject, content, "utf8");
5369
+ (0, import_fs8.writeFileSync)(tempPyproject, content, "utf8");
5343
5370
  manifestPath = tempPyproject;
5344
5371
  (0, import_build_utils10.debug)(
5345
5372
  `Wrote converted ${manifest.origin.kind} manifest to ${tempPyproject}`
@@ -5492,7 +5519,7 @@ async function doInstallVercelRuntime({
5492
5519
  onStdout,
5493
5520
  onStderr
5494
5521
  }) {
5495
- (0, import_fs7.mkdirSync)(targetDir, { recursive: true });
5522
+ (0, import_fs8.mkdirSync)(targetDir, { recursive: true });
5496
5523
  const localRuntimeDir = (0, import_path9.join)(
5497
5524
  __dirname,
5498
5525
  "..",
@@ -5501,14 +5528,14 @@ async function doInstallVercelRuntime({
5501
5528
  "python",
5502
5529
  "vercel-runtime"
5503
5530
  );
5504
- const isLocalDev = (0, import_fs7.existsSync)((0, import_path9.join)(localRuntimeDir, "pyproject.toml"));
5531
+ const isLocalDev = (0, import_fs8.existsSync)((0, import_path9.join)(localRuntimeDir, "pyproject.toml"));
5505
5532
  const runtimeDep = env.VERCEL_RUNTIME_PYTHON || (isLocalDev ? localRuntimeDir : `vercel-runtime==${VERCEL_RUNTIME_VERSION}`);
5506
5533
  if (!isLocalDev && !env.VERCEL_RUNTIME_PYTHON) {
5507
5534
  const distInfo = (0, import_path9.join)(
5508
5535
  targetDir,
5509
5536
  `vercel_runtime-${VERCEL_RUNTIME_VERSION}.dist-info`
5510
5537
  );
5511
- if ((0, import_fs7.existsSync)(distInfo)) {
5538
+ if ((0, import_fs8.existsSync)(distInfo)) {
5512
5539
  (0, import_build_utils10.debug)(
5513
5540
  `vercel-runtime ${VERCEL_RUNTIME_VERSION} already installed, skipping`
5514
5541
  );
@@ -5588,7 +5615,7 @@ async function doInstallVercelWorkers({
5588
5615
  onStdout,
5589
5616
  onStderr
5590
5617
  }) {
5591
- (0, import_fs7.mkdirSync)(targetDir, { recursive: true });
5618
+ (0, import_fs8.mkdirSync)(targetDir, { recursive: true });
5592
5619
  const localWorkersDir = (0, import_path9.join)(
5593
5620
  __dirname,
5594
5621
  "..",
@@ -5597,14 +5624,14 @@ async function doInstallVercelWorkers({
5597
5624
  "python",
5598
5625
  "vercel-workers"
5599
5626
  );
5600
- const isLocalDev = (0, import_fs7.existsSync)((0, import_path9.join)(localWorkersDir, "pyproject.toml"));
5627
+ const isLocalDev = (0, import_fs8.existsSync)((0, import_path9.join)(localWorkersDir, "pyproject.toml"));
5601
5628
  const workersDep = env.VERCEL_WORKERS_PYTHON || (isLocalDev ? localWorkersDir : `vercel-workers==${VERCEL_WORKERS_VERSION}`);
5602
5629
  if (!isLocalDev && !env.VERCEL_WORKERS_PYTHON) {
5603
5630
  const distInfo = (0, import_path9.join)(
5604
5631
  targetDir,
5605
5632
  `vercel_workers-${VERCEL_WORKERS_VERSION}.dist-info`
5606
5633
  );
5607
- if ((0, import_fs7.existsSync)(distInfo)) {
5634
+ if ((0, import_fs8.existsSync)(distInfo)) {
5608
5635
  (0, import_build_utils10.debug)(
5609
5636
  `vercel-workers ${VERCEL_WORKERS_VERSION} already installed, skipping`
5610
5637
  );
@@ -5694,10 +5721,10 @@ function installGlobalCleanupHandlers() {
5694
5721
  function createDevShim(workPath, entry, modulePath, serviceName, framework, variableName) {
5695
5722
  try {
5696
5723
  const vercelPythonDir = serviceName ? (0, import_path9.join)(workPath, ".vercel", "python", "services", serviceName) : (0, import_path9.join)(workPath, ".vercel", "python");
5697
- (0, import_fs7.mkdirSync)(vercelPythonDir, { recursive: true });
5724
+ (0, import_fs8.mkdirSync)(vercelPythonDir, { recursive: true });
5698
5725
  let qualifiedModule = modulePath;
5699
5726
  let extraPythonPath;
5700
- if ((0, import_fs7.existsSync)((0, import_path9.join)(workPath, "__init__.py"))) {
5727
+ if ((0, import_fs8.existsSync)((0, import_path9.join)(workPath, "__init__.py"))) {
5701
5728
  const pkgName = (0, import_path9.basename)(workPath);
5702
5729
  qualifiedModule = `${pkgName}.${modulePath}`;
5703
5730
  extraPythonPath = (0, import_path9.dirname)(workPath);
@@ -5710,9 +5737,9 @@ function createDevShim(workPath, entry, modulePath, serviceName, framework, vari
5710
5737
  "templates",
5711
5738
  `${DEV_SHIM_MODULE}.py`
5712
5739
  );
5713
- const template = (0, import_fs7.readFileSync)(templatePath, "utf8");
5740
+ const template = (0, import_fs8.readFileSync)(templatePath, "utf8");
5714
5741
  const shimSource = template.replace(/__VC_DEV_MODULE_NAME__/g, qualifiedModule).replace(/__VC_DEV_ENTRY_ABS__/g, entryAbs).replace(/__VC_DEV_FRAMEWORK__/g, framework).replace(/__VC_DEV_VARIABLE_NAME__/g, variableName);
5715
- (0, import_fs7.writeFileSync)(shimPath, shimSource, "utf8");
5742
+ (0, import_fs8.writeFileSync)(shimPath, shimSource, "utf8");
5716
5743
  (0, import_build_utils10.debug)(`Prepared Python dev shim at ${shimPath}`);
5717
5744
  return {
5718
5745
  module: DEV_SHIM_MODULE,
@@ -5787,10 +5814,16 @@ var startDevServer = async (opts) => {
5787
5814
  const env = { ...process.env, ...meta.env || {} };
5788
5815
  const entrypoint = rawEntrypoint === "<detect>" ? void 0 : rawEntrypoint;
5789
5816
  let resolved;
5817
+ const handlerFunction = typeof config?.handlerFunction === "string" ? config.handlerFunction : void 0;
5790
5818
  const detected = await detectPythonEntrypoint(
5791
5819
  framework,
5792
5820
  workPath,
5793
- entrypoint,
5821
+ entrypoint ? {
5822
+ filePath: entrypoint,
5823
+ // For cron services, the WSGI variable is always 'app' (created dynamically).
5824
+ // For other services, handlerFunction is used as the entrypoint variable name.
5825
+ varName: service?.type === "cron" ? void 0 : handlerFunction
5826
+ } : void 0,
5794
5827
  service
5795
5828
  );
5796
5829
  if (detected?.entrypoint) {
@@ -6019,7 +6052,7 @@ var matplotlibQuirk = {
6019
6052
  };
6020
6053
 
6021
6054
  // src/quirks/litellm.ts
6022
- var import_fs8 = __toESM(require("fs"));
6055
+ var import_fs9 = __toESM(require("fs"));
6023
6056
  var import_path10 = require("path");
6024
6057
  var import_build_utils11 = require("@vercel/build-utils");
6025
6058
  var LAMBDA_ROOT = "/var/task";
@@ -6033,7 +6066,7 @@ async function findConfigFile(workPath) {
6033
6066
  for (const name of CONFIG_CANDIDATES) {
6034
6067
  const candidate = (0, import_path10.join)(workPath, name);
6035
6068
  try {
6036
- await import_fs8.default.promises.access(candidate);
6069
+ await import_fs9.default.promises.access(candidate);
6037
6070
  return name;
6038
6071
  } catch {
6039
6072
  }
@@ -6055,7 +6088,7 @@ var litellmQuirk = {
6055
6088
  "schema.prisma"
6056
6089
  );
6057
6090
  try {
6058
- await import_fs8.default.promises.access(schemaPath);
6091
+ await import_fs9.default.promises.access(schemaPath);
6059
6092
  (0, import_build_utils11.debug)(`LiteLLM quirk: found schema at ${schemaPath}`);
6060
6093
  buildEnv.PRISMA_SCHEMA_PATH = schemaPath;
6061
6094
  break;
@@ -6082,7 +6115,7 @@ var litellmQuirk = {
6082
6115
  };
6083
6116
 
6084
6117
  // src/quirks/prisma.ts
6085
- var import_fs9 = __toESM(require("fs"));
6118
+ var import_fs10 = __toESM(require("fs"));
6086
6119
  var import_path11 = require("path");
6087
6120
  var import_execa4 = __toESM(require_execa());
6088
6121
  var import_build_utils12 = require("@vercel/build-utils");
@@ -6125,7 +6158,7 @@ async function findUserSchema(workPath) {
6125
6158
  if (envPath) {
6126
6159
  const resolved = (0, import_path11.isAbsolute)(envPath) ? envPath : (0, import_path11.join)(workPath, envPath);
6127
6160
  try {
6128
- await import_fs9.default.promises.access(resolved);
6161
+ await import_fs10.default.promises.access(resolved);
6129
6162
  return resolved;
6130
6163
  } catch {
6131
6164
  (0, import_build_utils12.debug)(`PRISMA_SCHEMA_PATH=${envPath} not found at ${resolved}`);
@@ -6138,7 +6171,7 @@ async function findUserSchema(workPath) {
6138
6171
  ];
6139
6172
  for (const candidate of candidates) {
6140
6173
  try {
6141
- await import_fs9.default.promises.access(candidate);
6174
+ await import_fs10.default.promises.access(candidate);
6142
6175
  return candidate;
6143
6176
  } catch {
6144
6177
  }
@@ -6149,7 +6182,7 @@ async function collectFiles(dir, base) {
6149
6182
  const result = [];
6150
6183
  let entries;
6151
6184
  try {
6152
- entries = await import_fs9.default.promises.readdir(dir, { withFileTypes: true });
6185
+ entries = await import_fs10.default.promises.readdir(dir, { withFileTypes: true });
6153
6186
  } catch {
6154
6187
  return result;
6155
6188
  }
@@ -6174,7 +6207,7 @@ async function cleanCacheArtifacts(cacheDir, extras = []) {
6174
6207
  ];
6175
6208
  for (const p of paths) {
6176
6209
  try {
6177
- await import_fs9.default.promises.rm(p, { recursive: true, force: true });
6210
+ await import_fs10.default.promises.rm(p, { recursive: true, force: true });
6178
6211
  } catch (err) {
6179
6212
  console.warn(
6180
6213
  `could not clean up ${p}: ${err instanceof Error ? err.message : String(err)}`
@@ -6208,7 +6241,7 @@ var prismaQuirk = {
6208
6241
  let sitePackages;
6209
6242
  for (const dir of sitePackagesDirs) {
6210
6243
  try {
6211
- await import_fs9.default.promises.access((0, import_path11.join)(dir, "prisma"));
6244
+ await import_fs10.default.promises.access((0, import_path11.join)(dir, "prisma"));
6212
6245
  sitePackages = dir;
6213
6246
  break;
6214
6247
  } catch {
@@ -6221,14 +6254,14 @@ var prismaQuirk = {
6221
6254
  return {};
6222
6255
  }
6223
6256
  const cacheDir = (0, import_path11.join)(sitePackages, "prisma", "__bincache__");
6224
- await import_fs9.default.promises.mkdir(cacheDir, { recursive: true });
6257
+ await import_fs10.default.promises.mkdir(cacheDir, { recursive: true });
6225
6258
  const generateEnv = {
6226
6259
  ...pythonEnv,
6227
6260
  PRISMA_BINARY_CACHE_DIR: cacheDir
6228
6261
  };
6229
6262
  const generatedDir = (0, import_path11.join)(workPath, "_prisma_generated");
6230
6263
  const dummySchemaPath = (0, import_path11.join)(workPath, DUMMY_SCHEMA_NAME);
6231
- await import_fs9.default.promises.writeFile(
6264
+ await import_fs10.default.promises.writeFile(
6232
6265
  dummySchemaPath,
6233
6266
  buildDummySchema(generatedDir)
6234
6267
  );
@@ -6259,18 +6292,18 @@ var prismaQuirk = {
6259
6292
  const nodeModulesDir = (0, import_path11.join)(cacheDir, "node_modules", "prisma");
6260
6293
  let engineCopied = false;
6261
6294
  try {
6262
- const entries = await import_fs9.default.promises.readdir(nodeModulesDir);
6295
+ const entries = await import_fs10.default.promises.readdir(nodeModulesDir);
6263
6296
  for (const entry of entries) {
6264
6297
  if (!entry.startsWith(srcBinaryPrefix))
6265
6298
  continue;
6266
6299
  const srcPath = (0, import_path11.join)(nodeModulesDir, entry);
6267
6300
  const destPath = (0, import_path11.join)(cacheDir, runtimeName);
6268
6301
  try {
6269
- await import_fs9.default.promises.access(destPath);
6302
+ await import_fs10.default.promises.access(destPath);
6270
6303
  (0, import_build_utils12.debug)(`Engine binary: ${runtimeName} already exists, skipping`);
6271
6304
  } catch {
6272
6305
  (0, import_build_utils12.debug)(`Engine binary: copying ${entry} -> ${runtimeName}`);
6273
- await import_fs9.default.promises.copyFile(srcPath, destPath);
6306
+ await import_fs10.default.promises.copyFile(srcPath, destPath);
6274
6307
  }
6275
6308
  engineCopied = true;
6276
6309
  }
@@ -6288,15 +6321,15 @@ var prismaQuirk = {
6288
6321
  });
6289
6322
  }
6290
6323
  const shimPath = (0, import_path11.join)(cacheDir, "openssl");
6291
- await import_fs9.default.promises.writeFile(
6324
+ await import_fs10.default.promises.writeFile(
6292
6325
  shimPath,
6293
6326
  `#!/bin/sh
6294
6327
  echo "OpenSSL ${RUNTIME_OPENSSL_VERSION}.0 1 Jan 2024 (Library: OpenSSL ${RUNTIME_OPENSSL_VERSION}.0)"
6295
6328
  `
6296
6329
  );
6297
- await import_fs9.default.promises.chmod(shimPath, 493);
6330
+ await import_fs10.default.promises.chmod(shimPath, 493);
6298
6331
  for (const p of [generatedDir, dummySchemaPath]) {
6299
- await import_fs9.default.promises.rm(p, { recursive: true, force: true });
6332
+ await import_fs10.default.promises.rm(p, { recursive: true, force: true });
6300
6333
  }
6301
6334
  await cleanCacheArtifacts(cacheDir);
6302
6335
  const generateMode = (process.env.VERCEL_PRISMA_GENERATE_CLIENT ?? "auto").toLowerCase();
@@ -6469,12 +6502,12 @@ async function runQuirks(ctx) {
6469
6502
  }
6470
6503
 
6471
6504
  // src/django.ts
6472
- var import_fs10 = __toESM(require("fs"));
6505
+ var import_fs11 = __toESM(require("fs"));
6473
6506
  var import_path12 = require("path");
6474
6507
  var import_execa5 = __toESM(require_execa());
6475
6508
  var import_build_utils14 = require("@vercel/build-utils");
6476
6509
  var scriptPath = (0, import_path12.join)(__dirname, "..", "templates", "vc_django_settings.py");
6477
- var script = import_fs10.default.readFileSync(scriptPath, "utf-8");
6510
+ var script = import_fs11.default.readFileSync(scriptPath, "utf-8");
6478
6511
  async function getDjangoSettings(projectDir, env) {
6479
6512
  const { stdout } = await (0, import_execa5.default)("python", ["-c", script], {
6480
6513
  env,
@@ -6505,7 +6538,7 @@ async function runDjangoCollectStatic(venvPath, workPath, env, outputStaticDir,
6505
6538
  ...installedApps.map((app) => (0, import_path12.join)(workPath, ...app.split("."), "static")),
6506
6539
  // TODO: Deal with optional prefixes in STATICFILES_DIRS.
6507
6540
  ...staticfilesDirs.map((d) => Array.isArray(d) ? d[1] : d)
6508
- ].filter((d) => import_fs10.default.existsSync(d));
6541
+ ].filter((d) => import_fs11.default.existsSync(d));
6509
6542
  if (storageBackend.startsWith("storages.backends.")) {
6510
6543
  console.log(
6511
6544
  "django-storages detected \u2014 running collectstatic with original settings"
@@ -6529,7 +6562,7 @@ async function runDjangoCollectStatic(venvPath, workPath, env, outputStaticDir,
6529
6562
  }
6530
6563
  const staticUrlPath = staticUrl.replace(/^\/|\/$/g, "") || "static";
6531
6564
  const staticOutputDir = (0, import_path12.join)(outputStaticDir, staticUrlPath);
6532
- await import_fs10.default.promises.mkdir(staticOutputDir, { recursive: true });
6565
+ await import_fs11.default.promises.mkdir(staticOutputDir, { recursive: true });
6533
6566
  const shimPath = (0, import_path12.join)(workPath, "_vercel_collectstatic_settings.py");
6534
6567
  const shimLines = [
6535
6568
  `from ${settingsModule} import *`,
@@ -6538,7 +6571,7 @@ async function runDjangoCollectStatic(venvPath, workPath, env, outputStaticDir,
6538
6571
  if (whitenoiseUseFinders) {
6539
6572
  shimLines.push(`WHITENOISE_USE_FINDERS = False`);
6540
6573
  }
6541
- await import_fs10.default.promises.writeFile(shimPath, shimLines.join("\n") + "\n");
6574
+ await import_fs11.default.promises.writeFile(shimPath, shimLines.join("\n") + "\n");
6542
6575
  try {
6543
6576
  console.log("Running collectstatic...");
6544
6577
  await (0, import_execa5.default)(pythonPath, ["manage.py", "collectstatic", "--noinput"], {
@@ -6549,7 +6582,7 @@ async function runDjangoCollectStatic(venvPath, workPath, env, outputStaticDir,
6549
6582
  cwd: workPath
6550
6583
  });
6551
6584
  } finally {
6552
- await import_fs10.default.promises.unlink(shimPath).catch(() => {
6585
+ await import_fs11.default.promises.unlink(shimPath).catch(() => {
6553
6586
  });
6554
6587
  }
6555
6588
  const MANIFEST_STORAGE_BACKENDS = [
@@ -6561,8 +6594,8 @@ async function runDjangoCollectStatic(venvPath, workPath, env, outputStaticDir,
6561
6594
  const manifestSrc = (0, import_path12.join)(staticOutputDir, "staticfiles.json");
6562
6595
  const resolvedStaticRoot = (0, import_path12.resolve)(workPath, staticRoot);
6563
6596
  const manifestDest = (0, import_path12.join)(resolvedStaticRoot, "staticfiles.json");
6564
- await import_fs10.default.promises.mkdir(resolvedStaticRoot, { recursive: true });
6565
- await import_fs10.default.promises.copyFile(manifestSrc, manifestDest);
6597
+ await import_fs11.default.promises.mkdir(resolvedStaticRoot, { recursive: true });
6598
+ await import_fs11.default.promises.copyFile(manifestSrc, manifestDest);
6566
6599
  manifestRelPath = (0, import_path12.relative)(workPath, manifestDest);
6567
6600
  (0, import_build_utils14.debug)(`Copied staticfiles.json to ${manifestDest} for Lambda bundle`);
6568
6601
  }
@@ -6576,7 +6609,7 @@ async function runDjangoCollectStatic(venvPath, workPath, env, outputStaticDir,
6576
6609
 
6577
6610
  // src/index.ts
6578
6611
  var import_python_analysis9 = require("@vercel/python-analysis");
6579
- var writeFile = import_fs11.default.promises.writeFile;
6612
+ var writeFile = import_fs12.default.promises.writeFile;
6580
6613
  var version = -1;
6581
6614
  async function runFrameworkHook(framework, ctx) {
6582
6615
  const hook = framework ? frameworkHooks[framework] : void 0;
@@ -6707,10 +6740,16 @@ var build = async ({
6707
6740
  throw err;
6708
6741
  }
6709
6742
  let detected;
6743
+ const handlerFunction = typeof config?.handlerFunction === "string" ? config.handlerFunction : void 0;
6710
6744
  detected = await detectPythonEntrypoint(
6711
6745
  config.framework,
6712
6746
  workPath,
6713
- entrypoint,
6747
+ entrypoint ? {
6748
+ filePath: entrypoint,
6749
+ // For cron services, the WSGI variable is always 'app' (created dynamically).
6750
+ // For other services, handlerFunction is used as the entrypoint variable name.
6751
+ varName: service?.type === "cron" ? void 0 : handlerFunction
6752
+ } : void 0,
6714
6753
  service
6715
6754
  ) ?? void 0;
6716
6755
  if (detected?.error && detected?.baseDir === void 0) {
@@ -6749,8 +6788,8 @@ var build = async ({
6749
6788
  }
6750
6789
  const venvPath = service?.name ? (0, import_path13.join)(workPath, ".vercel", "python", "services", service.name, ".venv") : (0, import_path13.join)(workPath, ".vercel", "python", ".venv");
6751
6790
  const uvCacheDir = getUvCacheDir(workPath);
6752
- const hasCachedVenv = import_fs11.default.existsSync((0, import_path13.join)(venvPath, "pyvenv.cfg"));
6753
- const hasCachedUv = import_fs11.default.existsSync(uvCacheDir);
6791
+ const hasCachedVenv = import_fs12.default.existsSync((0, import_path13.join)(venvPath, "pyvenv.cfg"));
6792
+ const hasCachedUv = import_fs12.default.existsSync(uvCacheDir);
6754
6793
  if (hasCachedVenv || hasCachedUv) {
6755
6794
  (0, import_build_utils15.debug)(
6756
6795
  `Build cache detected: venv=${hasCachedVenv}, uv-cache=${hasCachedUv}`
@@ -6813,7 +6852,7 @@ var build = async ({
6813
6852
  installCommand: projectInstallCommand || void 0
6814
6853
  }).trace(async () => {
6815
6854
  if (projectInstallCommand) {
6816
- await import_fs11.default.promises.rm(venvPath, { recursive: true, force: true });
6855
+ await import_fs12.default.promises.rm(venvPath, { recursive: true, force: true });
6817
6856
  await ensureVenv({
6818
6857
  pythonVersion,
6819
6858
  venvPath,
@@ -6864,9 +6903,9 @@ var build = async ({
6864
6903
  frozen: lockFileProvidedByUser,
6865
6904
  locked: !lockFileProvidedByUser
6866
6905
  });
6867
- if (lockPath && import_fs11.default.existsSync(lockPath)) {
6868
- await import_fs11.default.promises.mkdir(uvCacheDir, { recursive: true });
6869
- await import_fs11.default.promises.copyFile(lockPath, cachedLockPath);
6906
+ if (lockPath && import_fs12.default.existsSync(lockPath)) {
6907
+ await import_fs12.default.promises.mkdir(uvCacheDir, { recursive: true });
6908
+ await import_fs12.default.promises.copyFile(lockPath, cachedLockPath);
6870
6909
  }
6871
6910
  }
6872
6911
  });
@@ -6933,10 +6972,9 @@ var build = async ({
6933
6972
  }
6934
6973
  (0, import_build_utils15.debug)("Entrypoint is", entrypoint);
6935
6974
  const moduleName = entrypoint.replace(/\//g, ".").replace(/\.py$/i, "");
6936
- const handlerFunction = typeof config?.handlerFunction === "string" ? config.handlerFunction : void 0;
6937
6975
  if (handlerFunction) {
6938
6976
  const entrypointPath = (0, import_path13.join)(workPath, entrypoint);
6939
- const source = await import_fs11.default.promises.readFile(entrypointPath, "utf-8");
6977
+ const source = await import_fs12.default.promises.readFile(entrypointPath, "utf-8");
6940
6978
  const found = await (0, import_python_analysis9.containsTopLevelCallable)(source, handlerFunction);
6941
6979
  if (!found) {
6942
6980
  throw new import_build_utils15.NowBuildError({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/python",
3
- "version": "6.30.0",
3
+ "version": "6.31.0",
4
4
  "main": "./dist/index.js",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
@@ -36,9 +36,9 @@
36
36
  "smol-toml": "1.5.2",
37
37
  "vitest": "2.1.4",
38
38
  "which": "3.0.0",
39
- "@vercel/error-utils": "2.0.3",
39
+ "@vercel/build-utils": "13.15.0",
40
40
  "@vercel/python-runtime": "0.12.0",
41
- "@vercel/build-utils": "13.14.2"
41
+ "@vercel/error-utils": "2.0.3"
42
42
  },
43
43
  "scripts": {
44
44
  "build": "node ../../utils/build-builder.mjs",