@vercel/python 6.16.1 → 6.18.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 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 fs6 = require("fs");
51
+ var fs7 = 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
- fs6.stat(path, function(er, stat) {
76
+ fs7.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(fs6.statSync(path), path, options);
81
+ return checkStat(fs7.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 fs6 = require("fs");
91
+ var fs7 = require("fs");
92
92
  function isexe(path, options, cb) {
93
- fs6.stat(path, function(er, stat) {
93
+ fs7.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(fs6.statSync(path), options);
98
+ return checkStat(fs7.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 fs6 = require("fs");
122
+ var fs7 = 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 fs6 = require("fs");
398
+ var fs7 = 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 = fs6.openSync(command, "r");
412
- fs6.readSync(fd, buffer, 0, size, 0);
413
- fs6.closeSync(fd);
411
+ fd = fs7.openSync(command, "r");
412
+ fs7.readSync(fd, buffer, 0, size, 0);
413
+ fs7.closeSync(fd);
414
414
  } catch (e) {
415
415
  }
416
416
  return shebangCommand(buffer.toString());
@@ -423,15 +423,15 @@ var require_readShebang = __commonJS({
423
423
  var require_semver = __commonJS({
424
424
  "../../node_modules/.pnpm/semver@5.7.2/node_modules/semver/semver.js"(exports, module2) {
425
425
  exports = module2.exports = SemVer;
426
- var debug7;
426
+ var debug9;
427
427
  if (typeof process === "object" && process.env && process.env.NODE_DEBUG && /\bsemver\b/i.test(process.env.NODE_DEBUG)) {
428
- debug7 = function() {
428
+ debug9 = function() {
429
429
  var args = Array.prototype.slice.call(arguments, 0);
430
430
  args.unshift("SEMVER");
431
431
  console.log.apply(console, args);
432
432
  };
433
433
  } else {
434
- debug7 = function() {
434
+ debug9 = function() {
435
435
  };
436
436
  }
437
437
  exports.SEMVER_SPEC_VERSION = "2.0.0";
@@ -540,7 +540,7 @@ var require_semver = __commonJS({
540
540
  var STAR = R++;
541
541
  src[STAR] = "(<|>)?=?\\s*\\*";
542
542
  for (i = 0; i < R; i++) {
543
- debug7(i, src[i]);
543
+ debug9(i, src[i]);
544
544
  if (!re[i]) {
545
545
  re[i] = new RegExp(src[i]);
546
546
  safeRe[i] = new RegExp(makeSafeRe(src[i]));
@@ -607,7 +607,7 @@ var require_semver = __commonJS({
607
607
  if (!(this instanceof SemVer)) {
608
608
  return new SemVer(version2, options);
609
609
  }
610
- debug7("SemVer", version2, options);
610
+ debug9("SemVer", version2, options);
611
611
  this.options = options;
612
612
  this.loose = !!options.loose;
613
613
  var m = version2.trim().match(options.loose ? safeRe[LOOSE] : safeRe[FULL]);
@@ -654,7 +654,7 @@ var require_semver = __commonJS({
654
654
  return this.version;
655
655
  };
656
656
  SemVer.prototype.compare = function(other) {
657
- debug7("SemVer.compare", this.version, this.options, other);
657
+ debug9("SemVer.compare", this.version, this.options, other);
658
658
  if (!(other instanceof SemVer)) {
659
659
  other = new SemVer(other, this.options);
660
660
  }
@@ -681,7 +681,7 @@ var require_semver = __commonJS({
681
681
  do {
682
682
  var a = this.prerelease[i2];
683
683
  var b = other.prerelease[i2];
684
- debug7("prerelease compare", i2, a, b);
684
+ debug9("prerelease compare", i2, a, b);
685
685
  if (a === void 0 && b === void 0) {
686
686
  return 0;
687
687
  } else if (b === void 0) {
@@ -935,7 +935,7 @@ var require_semver = __commonJS({
935
935
  return new Comparator(comp, options);
936
936
  }
937
937
  comp = comp.trim().split(/\s+/).join(" ");
938
- debug7("comparator", comp, options);
938
+ debug9("comparator", comp, options);
939
939
  this.options = options;
940
940
  this.loose = !!options.loose;
941
941
  this.parse(comp);
@@ -944,7 +944,7 @@ var require_semver = __commonJS({
944
944
  } else {
945
945
  this.value = this.operator + this.semver.version;
946
946
  }
947
- debug7("comp", this);
947
+ debug9("comp", this);
948
948
  }
949
949
  var ANY = {};
950
950
  Comparator.prototype.parse = function(comp) {
@@ -967,7 +967,7 @@ var require_semver = __commonJS({
967
967
  return this.value;
968
968
  };
969
969
  Comparator.prototype.test = function(version2) {
970
- debug7("Comparator.test", version2, this.options.loose);
970
+ debug9("Comparator.test", version2, this.options.loose);
971
971
  if (this.semver === ANY) {
972
972
  return true;
973
973
  }
@@ -1050,9 +1050,9 @@ var require_semver = __commonJS({
1050
1050
  var loose = this.options.loose;
1051
1051
  var hr = loose ? safeRe[HYPHENRANGELOOSE] : safeRe[HYPHENRANGE];
1052
1052
  range = range.replace(hr, hyphenReplace);
1053
- debug7("hyphen replace", range);
1053
+ debug9("hyphen replace", range);
1054
1054
  range = range.replace(safeRe[COMPARATORTRIM], comparatorTrimReplace);
1055
- debug7("comparator trim", range, safeRe[COMPARATORTRIM]);
1055
+ debug9("comparator trim", range, safeRe[COMPARATORTRIM]);
1056
1056
  range = range.replace(safeRe[TILDETRIM], tildeTrimReplace);
1057
1057
  range = range.replace(safeRe[CARETTRIM], caretTrimReplace);
1058
1058
  var compRe = loose ? safeRe[COMPARATORLOOSE] : safeRe[COMPARATOR];
@@ -1092,15 +1092,15 @@ var require_semver = __commonJS({
1092
1092
  });
1093
1093
  }
1094
1094
  function parseComparator(comp, options) {
1095
- debug7("comp", comp, options);
1095
+ debug9("comp", comp, options);
1096
1096
  comp = replaceCarets(comp, options);
1097
- debug7("caret", comp);
1097
+ debug9("caret", comp);
1098
1098
  comp = replaceTildes(comp, options);
1099
- debug7("tildes", comp);
1099
+ debug9("tildes", comp);
1100
1100
  comp = replaceXRanges(comp, options);
1101
- debug7("xrange", comp);
1101
+ debug9("xrange", comp);
1102
1102
  comp = replaceStars(comp, options);
1103
- debug7("stars", comp);
1103
+ debug9("stars", comp);
1104
1104
  return comp;
1105
1105
  }
1106
1106
  function isX(id) {
@@ -1114,7 +1114,7 @@ var require_semver = __commonJS({
1114
1114
  function replaceTilde(comp, options) {
1115
1115
  var r = options.loose ? safeRe[TILDELOOSE] : safeRe[TILDE];
1116
1116
  return comp.replace(r, function(_, M, m, p, pr) {
1117
- debug7("tilde", comp, _, M, m, p, pr);
1117
+ debug9("tilde", comp, _, M, m, p, pr);
1118
1118
  var ret;
1119
1119
  if (isX(M)) {
1120
1120
  ret = "";
@@ -1123,12 +1123,12 @@ var require_semver = __commonJS({
1123
1123
  } else if (isX(p)) {
1124
1124
  ret = ">=" + M + "." + m + ".0 <" + M + "." + (+m + 1) + ".0";
1125
1125
  } else if (pr) {
1126
- debug7("replaceTilde pr", pr);
1126
+ debug9("replaceTilde pr", pr);
1127
1127
  ret = ">=" + M + "." + m + "." + p + "-" + pr + " <" + M + "." + (+m + 1) + ".0";
1128
1128
  } else {
1129
1129
  ret = ">=" + M + "." + m + "." + p + " <" + M + "." + (+m + 1) + ".0";
1130
1130
  }
1131
- debug7("tilde return", ret);
1131
+ debug9("tilde return", ret);
1132
1132
  return ret;
1133
1133
  });
1134
1134
  }
@@ -1138,10 +1138,10 @@ var require_semver = __commonJS({
1138
1138
  }).join(" ");
1139
1139
  }
1140
1140
  function replaceCaret(comp, options) {
1141
- debug7("caret", comp, options);
1141
+ debug9("caret", comp, options);
1142
1142
  var r = options.loose ? safeRe[CARETLOOSE] : safeRe[CARET];
1143
1143
  return comp.replace(r, function(_, M, m, p, pr) {
1144
- debug7("caret", comp, _, M, m, p, pr);
1144
+ debug9("caret", comp, _, M, m, p, pr);
1145
1145
  var ret;
1146
1146
  if (isX(M)) {
1147
1147
  ret = "";
@@ -1154,7 +1154,7 @@ var require_semver = __commonJS({
1154
1154
  ret = ">=" + M + "." + m + ".0 <" + (+M + 1) + ".0.0";
1155
1155
  }
1156
1156
  } else if (pr) {
1157
- debug7("replaceCaret pr", pr);
1157
+ debug9("replaceCaret pr", pr);
1158
1158
  if (M === "0") {
1159
1159
  if (m === "0") {
1160
1160
  ret = ">=" + M + "." + m + "." + p + "-" + pr + " <" + M + "." + m + "." + (+p + 1);
@@ -1165,7 +1165,7 @@ var require_semver = __commonJS({
1165
1165
  ret = ">=" + M + "." + m + "." + p + "-" + pr + " <" + (+M + 1) + ".0.0";
1166
1166
  }
1167
1167
  } else {
1168
- debug7("no pr");
1168
+ debug9("no pr");
1169
1169
  if (M === "0") {
1170
1170
  if (m === "0") {
1171
1171
  ret = ">=" + M + "." + m + "." + p + " <" + M + "." + m + "." + (+p + 1);
@@ -1176,12 +1176,12 @@ var require_semver = __commonJS({
1176
1176
  ret = ">=" + M + "." + m + "." + p + " <" + (+M + 1) + ".0.0";
1177
1177
  }
1178
1178
  }
1179
- debug7("caret return", ret);
1179
+ debug9("caret return", ret);
1180
1180
  return ret;
1181
1181
  });
1182
1182
  }
1183
1183
  function replaceXRanges(comp, options) {
1184
- debug7("replaceXRanges", comp, options);
1184
+ debug9("replaceXRanges", comp, options);
1185
1185
  return comp.split(/\s+/).map(function(comp2) {
1186
1186
  return replaceXRange(comp2, options);
1187
1187
  }).join(" ");
@@ -1190,7 +1190,7 @@ var require_semver = __commonJS({
1190
1190
  comp = comp.trim();
1191
1191
  var r = options.loose ? safeRe[XRANGELOOSE] : safeRe[XRANGE];
1192
1192
  return comp.replace(r, function(ret, gtlt, M, m, p, pr) {
1193
- debug7("xRange", comp, ret, gtlt, M, m, p, pr);
1193
+ debug9("xRange", comp, ret, gtlt, M, m, p, pr);
1194
1194
  var xM = isX(M);
1195
1195
  var xm = xM || isX(m);
1196
1196
  var xp = xm || isX(p);
@@ -1233,12 +1233,12 @@ var require_semver = __commonJS({
1233
1233
  } else if (xp) {
1234
1234
  ret = ">=" + M + "." + m + ".0 <" + M + "." + (+m + 1) + ".0";
1235
1235
  }
1236
- debug7("xRange return", ret);
1236
+ debug9("xRange return", ret);
1237
1237
  return ret;
1238
1238
  });
1239
1239
  }
1240
1240
  function replaceStars(comp, options) {
1241
- debug7("replaceStars", comp, options);
1241
+ debug9("replaceStars", comp, options);
1242
1242
  return comp.trim().replace(safeRe[STAR], "");
1243
1243
  }
1244
1244
  function hyphenReplace($0, from, fM, fm, fp, fpr, fb, to, tM, tm, tp, tpr, tb) {
@@ -1286,7 +1286,7 @@ var require_semver = __commonJS({
1286
1286
  }
1287
1287
  if (version2.prerelease.length && !options.includePrerelease) {
1288
1288
  for (i2 = 0; i2 < set.length; i2++) {
1289
- debug7(set[i2].semver);
1289
+ debug9(set[i2].semver);
1290
1290
  if (set[i2].semver === ANY) {
1291
1291
  continue;
1292
1292
  }
@@ -1895,9 +1895,9 @@ var require_pump = __commonJS({
1895
1895
  "../../node_modules/.pnpm/pump@3.0.2/node_modules/pump/index.js"(exports, module2) {
1896
1896
  var once = require_once();
1897
1897
  var eos = require_end_of_stream();
1898
- var fs6;
1898
+ var fs7;
1899
1899
  try {
1900
- fs6 = require("fs");
1900
+ fs7 = 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 (!fs6)
1912
+ if (!fs7)
1913
1913
  return false;
1914
- return (stream instanceof (fs6.ReadStream || noop) || stream instanceof (fs6.WriteStream || noop)) && isFn(stream.close);
1914
+ return (stream instanceof (fs7.ReadStream || noop) || stream instanceof (fs7.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: join8, delimiter: delimiter2, sep: sep2, posix } = require("path");
2654
+ var { join: join9, delimiter: delimiter2, sep: sep2, posix } = require("path");
2655
2655
  var isWindows = process.platform === "win32";
2656
2656
  var rSlash = new RegExp(`[${posix.sep}${sep2 === posix.sep ? "" : sep2}]`.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 + join8(pathPart, cmd);
2683
+ return prefix + join9(pathPart, cmd);
2684
2684
  };
2685
2685
  var which2 = async (cmd, opt = {}) => {
2686
2686
  const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
@@ -2867,15 +2867,15 @@ __export(src_exports, {
2867
2867
  version: () => version
2868
2868
  });
2869
2869
  module.exports = __toCommonJS(src_exports);
2870
- var import_fs6 = __toESM(require("fs"));
2870
+ var import_fs7 = __toESM(require("fs"));
2871
2871
  var import_util2 = require("util");
2872
- var import_path8 = require("path");
2872
+ var import_path9 = require("path");
2873
2873
 
2874
- // src/runtime-version.ts
2875
- var VERCEL_RUNTIME_VERSION = "0.5.1";
2874
+ // src/package-versions.ts
2875
+ var VERCEL_RUNTIME_VERSION = "0.5.3";
2876
2876
 
2877
2877
  // src/index.ts
2878
- var import_build_utils9 = require("@vercel/build-utils");
2878
+ var import_build_utils11 = require("@vercel/build-utils");
2879
2879
 
2880
2880
  // src/install.ts
2881
2881
  var import_execa3 = __toESM(require_execa());
@@ -3881,6 +3881,7 @@ var PythonDependencyExternalizer = class {
3881
3881
  this.noBuildCheckFailed = options.noBuildCheckFailed;
3882
3882
  this.pythonPath = options.pythonPath;
3883
3883
  this.hasCustomCommand = options.hasCustomCommand;
3884
+ this.alwaysBundlePackages = options.alwaysBundlePackages ?? [];
3884
3885
  }
3885
3886
  shouldEnableRuntimeInstall() {
3886
3887
  if (this.hasCustomCommand) {
@@ -4033,7 +4034,8 @@ ${error.fileContent}`
4033
4034
  const alwaysBundled = [
4034
4035
  ...classification.privatePackages,
4035
4036
  "vercel-runtime",
4036
- "vercel_runtime"
4037
+ "vercel_runtime",
4038
+ ...this.alwaysBundlePackages
4037
4039
  ];
4038
4040
  const alwaysBundledFiles = await mirrorPackagesIntoVendor({
4039
4041
  venvPath: this.venvPath,
@@ -4076,7 +4078,8 @@ ${error.fileContent}`
4076
4078
  }
4077
4079
  const bundledPackagesForConfig = [
4078
4080
  ...classification.privatePackages,
4079
- ...bundledPublic
4081
+ ...bundledPublic,
4082
+ ...this.alwaysBundlePackages
4080
4083
  ];
4081
4084
  const projectDirRel = (0, import_path5.relative)(this.workPath, this.uvProjectDir);
4082
4085
  const uvLockRel = (0, import_path5.relative)(this.workPath, this.uvLockPath);
@@ -4241,7 +4244,7 @@ async function calculatePerPackageSizes(venvPath) {
4241
4244
  }
4242
4245
 
4243
4246
  // src/index.ts
4244
- var import_build_utils10 = require("@vercel/build-utils");
4247
+ var import_build_utils12 = require("@vercel/build-utils");
4245
4248
 
4246
4249
  // src/start-dev-server.ts
4247
4250
  var import_child_process2 = require("child_process");
@@ -4264,11 +4267,16 @@ var PYTHON_ENTRYPOINT_FILENAMES = [
4264
4267
  "asgi"
4265
4268
  ];
4266
4269
  var PYTHON_ENTRYPOINT_DIRS = ["", "src", "app", "api"];
4267
- var PYTHON_CANDIDATE_ENTRYPOINTS = PYTHON_ENTRYPOINT_FILENAMES.flatMap(
4268
- (filename) => PYTHON_ENTRYPOINT_DIRS.map(
4269
- (dir) => import_path6.posix.join(dir, `${filename}.py`)
4270
- )
4270
+ var PYTHON_CANDIDATE_ENTRYPOINTS = getCandidateEntrypointsInDirs(
4271
+ PYTHON_ENTRYPOINT_DIRS
4271
4272
  );
4273
+ function getCandidateEntrypointsInDirs(dirs) {
4274
+ return dirs.flatMap(
4275
+ (dir) => PYTHON_ENTRYPOINT_FILENAMES.map(
4276
+ (filename) => import_path6.posix.join(dir, `${filename}.py`)
4277
+ )
4278
+ );
4279
+ }
4272
4280
  async function getPyprojectEntrypoint(workPath) {
4273
4281
  const pyprojectData = await (0, import_build_utils7.readConfigFile)((0, import_path6.join)(workPath, "pyproject.toml"));
4274
4282
  if (!pyprojectData)
@@ -4295,6 +4303,18 @@ async function getPyprojectEntrypoint(workPath) {
4295
4303
  return null;
4296
4304
  }
4297
4305
  }
4306
+ async function findValidEntrypoint(fsFiles, candidates) {
4307
+ for (const candidate of candidates) {
4308
+ if (fsFiles[candidate]) {
4309
+ const isValid = await (0, import_build_utils6.isPythonEntrypoint)(fsFiles[candidate]);
4310
+ if (isValid) {
4311
+ (0, import_build_utils6.debug)(`Detected Python entrypoint: ${candidate}`);
4312
+ return candidate;
4313
+ }
4314
+ }
4315
+ }
4316
+ return null;
4317
+ }
4298
4318
  async function detectGenericPythonEntrypoint(workPath, configuredEntrypoint) {
4299
4319
  const entry = configuredEntrypoint.endsWith(".py") ? configuredEntrypoint : `${configuredEntrypoint}.py`;
4300
4320
  try {
@@ -4309,24 +4329,54 @@ async function detectGenericPythonEntrypoint(workPath, configuredEntrypoint) {
4309
4329
  const candidates = PYTHON_CANDIDATE_ENTRYPOINTS.filter(
4310
4330
  (c) => !!fsFiles[c]
4311
4331
  );
4312
- for (const candidate of candidates) {
4313
- const isValid = await (0, import_build_utils6.isPythonEntrypoint)(fsFiles[candidate]);
4332
+ return findValidEntrypoint(fsFiles, candidates);
4333
+ } catch {
4334
+ (0, import_build_utils6.debug)("Failed to discover Python entrypoint");
4335
+ return null;
4336
+ }
4337
+ }
4338
+ async function detectDjangoPythonEntrypoint(workPath, configuredEntrypoint) {
4339
+ const entry = configuredEntrypoint.endsWith(".py") ? configuredEntrypoint : `${configuredEntrypoint}.py`;
4340
+ try {
4341
+ const fsFiles = await (0, import_build_utils6.glob)("**", workPath);
4342
+ if (fsFiles[entry]) {
4343
+ const isValid = await (0, import_build_utils6.isPythonEntrypoint)(fsFiles[entry]);
4314
4344
  if (isValid) {
4315
- (0, import_build_utils6.debug)(`Detected Python entrypoint: ${candidate}`);
4316
- return candidate;
4345
+ (0, import_build_utils6.debug)(`Using configured Python entrypoint: ${entry}`);
4346
+ return entry;
4317
4347
  }
4318
4348
  }
4319
- return null;
4349
+ const rootGlobs = await (0, import_build_utils6.glob)("*", {
4350
+ cwd: workPath,
4351
+ includeDirectories: true
4352
+ });
4353
+ const rootDirs = [
4354
+ "",
4355
+ ...Object.keys(rootGlobs).filter(
4356
+ (name) => !name.startsWith(".") && rootGlobs[name].mode != null && (0, import_build_utils6.isDirectory)(rootGlobs[name].mode)
4357
+ )
4358
+ ];
4359
+ for (const rootDir of rootDirs) {
4360
+ const currPath = (0, import_path6.join)(workPath, rootDir);
4361
+ const wsgiEntry = await (0, import_build_utils6.getDjangoEntrypoint)(currPath);
4362
+ if (wsgiEntry) {
4363
+ const fullWsgiEntry = import_path6.posix.join(rootDir, wsgiEntry);
4364
+ if (fsFiles[fullWsgiEntry]) {
4365
+ (0, import_build_utils6.debug)(`Using Django WSGI entrypoint: ${fullWsgiEntry}`);
4366
+ return fullWsgiEntry;
4367
+ }
4368
+ }
4369
+ }
4370
+ const baseCandidates = getCandidateEntrypointsInDirs(rootDirs);
4371
+ const candidates = baseCandidates.filter((c) => !!fsFiles[c]);
4372
+ return findValidEntrypoint(fsFiles, candidates);
4320
4373
  } catch {
4321
- (0, import_build_utils6.debug)("Failed to discover Python entrypoint");
4374
+ (0, import_build_utils6.debug)("Failed to discover Django Python entrypoint");
4322
4375
  return null;
4323
4376
  }
4324
4377
  }
4325
- async function detectPythonEntrypoint(_framework, workPath, configuredEntrypoint) {
4326
- const entrypoint = await detectGenericPythonEntrypoint(
4327
- workPath,
4328
- configuredEntrypoint
4329
- );
4378
+ async function detectPythonEntrypoint(framework, workPath, configuredEntrypoint) {
4379
+ const entrypoint = framework === "django" ? await detectDjangoPythonEntrypoint(workPath, configuredEntrypoint) : await detectGenericPythonEntrypoint(workPath, configuredEntrypoint);
4330
4380
  if (entrypoint)
4331
4381
  return entrypoint;
4332
4382
  return await getPyprojectEntrypoint(workPath);
@@ -4579,17 +4629,25 @@ function installGlobalCleanupHandlers() {
4579
4629
  killAll();
4580
4630
  });
4581
4631
  }
4582
- function createDevShim(workPath, modulePath) {
4632
+ function createDevShim(workPath, entry, modulePath) {
4583
4633
  try {
4584
4634
  const vercelPythonDir = (0, import_path7.join)(workPath, ".vercel", "python");
4585
4635
  (0, import_fs5.mkdirSync)(vercelPythonDir, { recursive: true });
4636
+ let qualifiedModule = modulePath;
4637
+ let extraPythonPath;
4638
+ if ((0, import_fs5.existsSync)((0, import_path7.join)(workPath, "__init__.py"))) {
4639
+ const pkgName = (0, import_path7.basename)(workPath);
4640
+ qualifiedModule = `${pkgName}.${modulePath}`;
4641
+ extraPythonPath = (0, import_path7.dirname)(workPath);
4642
+ }
4643
+ const entryAbs = (0, import_path7.join)(workPath, entry);
4586
4644
  const shimPath = (0, import_path7.join)(vercelPythonDir, `${DEV_SHIM_MODULE}.py`);
4587
4645
  const templatePath = (0, import_path7.join)(__dirname, "..", `${DEV_SHIM_MODULE}.py`);
4588
4646
  const template = (0, import_fs5.readFileSync)(templatePath, "utf8");
4589
- const shimSource = template.replace(/__VC_DEV_MODULE_PATH__/g, modulePath);
4647
+ const shimSource = template.replace(/__VC_DEV_MODULE_NAME__/g, qualifiedModule).replace(/__VC_DEV_ENTRY_ABS__/g, entryAbs);
4590
4648
  (0, import_fs5.writeFileSync)(shimPath, shimSource, "utf8");
4591
4649
  (0, import_build_utils8.debug)(`Prepared Python dev shim at ${shimPath}`);
4592
- return DEV_SHIM_MODULE;
4650
+ return { module: DEV_SHIM_MODULE, extraPythonPath };
4593
4651
  } catch (err) {
4594
4652
  (0, import_build_utils8.debug)(`Failed to prepare dev shim: ${err?.message || err}`);
4595
4653
  return null;
@@ -4753,22 +4811,33 @@ If you are using a virtual environment, activate it before running "vercel dev",
4753
4811
  }
4754
4812
  const port = typeof meta.port === "number" ? meta.port : await (0, import_get_port.default)();
4755
4813
  env.PORT = `${port}`;
4756
- const devShimModule = createDevShim(workPath, modulePath);
4757
- if (devShimModule) {
4814
+ const devShim = createDevShim(workPath, entry, modulePath);
4815
+ if (devShim) {
4758
4816
  const vercelPythonDir = (0, import_path7.join)(workPath, ".vercel", "python");
4817
+ const pathParts = [vercelPythonDir];
4818
+ if (devShim.extraPythonPath) {
4819
+ pathParts.push(devShim.extraPythonPath);
4820
+ }
4759
4821
  const existingPythonPath = env.PYTHONPATH || "";
4760
- env.PYTHONPATH = existingPythonPath ? `${vercelPythonDir}:${existingPythonPath}` : vercelPythonDir;
4822
+ if (existingPythonPath) {
4823
+ pathParts.push(existingPythonPath);
4824
+ }
4825
+ env.PYTHONPATH = pathParts.join(import_path7.delimiter);
4761
4826
  }
4762
- const moduleToRun = devShimModule || modulePath;
4827
+ const moduleToRun = devShim?.module || modulePath;
4763
4828
  const pythonArgs = ["-u", "-m", moduleToRun];
4764
4829
  const argv = [...spawnArgsPrefix, ...pythonArgs];
4765
4830
  (0, import_build_utils8.debug)(
4766
4831
  `Starting Python dev server (${framework}): ${spawnCommand} ${argv.join(" ")} [PORT=${port}]`
4767
4832
  );
4833
+ if (process.stdout.columns) {
4834
+ env.COLUMNS = `${process.stdout.columns}`;
4835
+ }
4768
4836
  const child = (0, import_child_process2.spawn)(spawnCommand, argv, {
4769
4837
  cwd: workPath,
4770
4838
  env,
4771
- stdio: ["inherit", "pipe", "pipe"]
4839
+ stdio: ["ignore", "pipe", "pipe"],
4840
+ detached: true
4772
4841
  });
4773
4842
  childProcess = child;
4774
4843
  stdoutLogListener = createLogListener(onStdout, process.stdout);
@@ -4811,9 +4880,399 @@ If you are using a virtual environment, activate it before running "vercel dev",
4811
4880
  }
4812
4881
  };
4813
4882
 
4883
+ // src/quirks/index.ts
4884
+ var import_build_utils10 = require("@vercel/build-utils");
4885
+ var import_python_analysis5 = require("@vercel/python-analysis");
4886
+
4887
+ // src/quirks/prisma.ts
4888
+ var import_fs6 = __toESM(require("fs"));
4889
+ var import_path8 = require("path");
4890
+ var import_execa4 = __toESM(require_execa());
4891
+ var import_build_utils9 = require("@vercel/build-utils");
4892
+ var import_python_analysis4 = require("@vercel/python-analysis");
4893
+ function execErrorMessage(err) {
4894
+ if (err != null && typeof err === "object" && "stderr" in err) {
4895
+ const stderr = String(err.stderr);
4896
+ if (stderr)
4897
+ return stderr;
4898
+ }
4899
+ return err instanceof Error ? err.message : String(err);
4900
+ }
4901
+ var DUMMY_SCHEMA_NAME = "_prisma_dummy.prisma";
4902
+ var LAMBDA_ROOT = "/var/task";
4903
+ var RUNTIME_OPENSSL_VERSION = "3.2";
4904
+ function getLambdaBinaryTarget() {
4905
+ return process.arch === "arm64" ? "linux-arm64-openssl-3.0.x" : "rhel-openssl-3.0.x";
4906
+ }
4907
+ function buildDummySchema(generatedDir) {
4908
+ const lambdaTarget = getLambdaBinaryTarget();
4909
+ return `datasource db {
4910
+ provider = "sqlite"
4911
+ url = "file:dev.db"
4912
+ }
4913
+
4914
+ generator client {
4915
+ provider = "prisma-client-py"
4916
+ binaryTargets = ["native", "${lambdaTarget}"]
4917
+ output = "${generatedDir}"
4918
+ }
4919
+
4920
+ model DummyModel {
4921
+ id Int @id
4922
+ }
4923
+ `;
4924
+ }
4925
+ async function findUserSchema(workPath) {
4926
+ const envPath = process.env.PRISMA_SCHEMA_PATH;
4927
+ if (envPath) {
4928
+ const resolved = (0, import_path8.isAbsolute)(envPath) ? envPath : (0, import_path8.join)(workPath, envPath);
4929
+ try {
4930
+ await import_fs6.default.promises.access(resolved);
4931
+ return resolved;
4932
+ } catch {
4933
+ (0, import_build_utils9.debug)(`PRISMA_SCHEMA_PATH=${envPath} not found at ${resolved}`);
4934
+ return null;
4935
+ }
4936
+ }
4937
+ const candidates = [
4938
+ (0, import_path8.join)(workPath, "schema.prisma"),
4939
+ (0, import_path8.join)(workPath, "prisma", "schema.prisma")
4940
+ ];
4941
+ for (const candidate of candidates) {
4942
+ try {
4943
+ await import_fs6.default.promises.access(candidate);
4944
+ return candidate;
4945
+ } catch {
4946
+ }
4947
+ }
4948
+ return null;
4949
+ }
4950
+ async function collectFiles(dir, base) {
4951
+ const result = [];
4952
+ let entries;
4953
+ try {
4954
+ entries = await import_fs6.default.promises.readdir(dir, { withFileTypes: true });
4955
+ } catch {
4956
+ return result;
4957
+ }
4958
+ for (const entry of entries) {
4959
+ if (entry.name === "__pycache__")
4960
+ continue;
4961
+ const full = (0, import_path8.join)(dir, entry.name);
4962
+ if (entry.isDirectory()) {
4963
+ result.push(...await collectFiles(full, base));
4964
+ } else {
4965
+ result.push((0, import_path8.relative)(base, full));
4966
+ }
4967
+ }
4968
+ return result;
4969
+ }
4970
+ async function cleanCacheArtifacts(cacheDir, extras = []) {
4971
+ const paths = [
4972
+ (0, import_path8.join)(cacheDir, "node_modules"),
4973
+ (0, import_path8.join)(cacheDir, "package.json"),
4974
+ (0, import_path8.join)(cacheDir, "package-lock.json"),
4975
+ ...extras
4976
+ ];
4977
+ for (const p of paths) {
4978
+ try {
4979
+ await import_fs6.default.promises.rm(p, { recursive: true, force: true });
4980
+ } catch (err) {
4981
+ console.warn(
4982
+ `could not clean up ${p}: ${err instanceof Error ? err.message : String(err)}`
4983
+ );
4984
+ }
4985
+ }
4986
+ }
4987
+ async function isClientGenerated(pythonPath, env) {
4988
+ try {
4989
+ await (0, import_execa4.default)(pythonPath, ["-c", "import prisma.client"], {
4990
+ env,
4991
+ stdio: "pipe"
4992
+ });
4993
+ return true;
4994
+ } catch {
4995
+ return false;
4996
+ }
4997
+ }
4998
+ var prismaQuirk = {
4999
+ dependency: "prisma",
5000
+ async run(ctx) {
5001
+ const { venvPath, pythonEnv, workPath } = ctx;
5002
+ const pythonPath = getVenvPythonBin(venvPath);
5003
+ const runtimeCacheDir = (0, import_path8.join)(
5004
+ LAMBDA_ROOT,
5005
+ resolveVendorDir(),
5006
+ "prisma",
5007
+ "__bincache__"
5008
+ );
5009
+ const sitePackagesDirs = await getVenvSitePackagesDirs(venvPath);
5010
+ let sitePackages;
5011
+ for (const dir of sitePackagesDirs) {
5012
+ try {
5013
+ await import_fs6.default.promises.access((0, import_path8.join)(dir, "prisma"));
5014
+ sitePackages = dir;
5015
+ break;
5016
+ } catch {
5017
+ }
5018
+ }
5019
+ if (!sitePackages) {
5020
+ console.warn(
5021
+ "prisma: could not find prisma in any site-packages directory"
5022
+ );
5023
+ return {};
5024
+ }
5025
+ const cacheDir = (0, import_path8.join)(sitePackages, "prisma", "__bincache__");
5026
+ await import_fs6.default.promises.mkdir(cacheDir, { recursive: true });
5027
+ const generateEnv = {
5028
+ ...pythonEnv,
5029
+ PRISMA_BINARY_CACHE_DIR: cacheDir
5030
+ };
5031
+ const generatedDir = (0, import_path8.join)(workPath, "_prisma_generated");
5032
+ const dummySchemaPath = (0, import_path8.join)(workPath, DUMMY_SCHEMA_NAME);
5033
+ await import_fs6.default.promises.writeFile(
5034
+ dummySchemaPath,
5035
+ buildDummySchema(generatedDir)
5036
+ );
5037
+ (0, import_build_utils9.debug)(`Running prisma generate (dummy) with cache dir: ${cacheDir}`);
5038
+ try {
5039
+ const dummyResult = await (0, import_execa4.default)(
5040
+ pythonPath,
5041
+ ["-m", "prisma", "generate", `--schema=${dummySchemaPath}`],
5042
+ {
5043
+ cwd: workPath,
5044
+ env: generateEnv,
5045
+ stdio: "pipe"
5046
+ }
5047
+ );
5048
+ if (dummyResult.stdout)
5049
+ (0, import_build_utils9.debug)(`prisma generate (dummy) stdout: ${dummyResult.stdout}`);
5050
+ if (dummyResult.stderr)
5051
+ (0, import_build_utils9.debug)(`prisma generate (dummy) stderr: ${dummyResult.stderr}`);
5052
+ } catch (err) {
5053
+ throw new import_build_utils9.NowBuildError({
5054
+ code: "PRISMA_GENERATE_FAILED",
5055
+ message: `Prisma engine download failed during \`prisma generate\`. Check that your prisma version is compatible with this Python version.
5056
+ ` + execErrorMessage(err)
5057
+ });
5058
+ }
5059
+ const srcBinaryPrefix = `query-engine-${getLambdaBinaryTarget()}`;
5060
+ const runtimeName = `prisma-query-engine-rhel-openssl-${RUNTIME_OPENSSL_VERSION}.x`;
5061
+ const nodeModulesDir = (0, import_path8.join)(cacheDir, "node_modules", "prisma");
5062
+ let engineCopied = false;
5063
+ try {
5064
+ const entries = await import_fs6.default.promises.readdir(nodeModulesDir);
5065
+ for (const entry of entries) {
5066
+ if (!entry.startsWith(srcBinaryPrefix))
5067
+ continue;
5068
+ const srcPath = (0, import_path8.join)(nodeModulesDir, entry);
5069
+ const destPath = (0, import_path8.join)(cacheDir, runtimeName);
5070
+ try {
5071
+ await import_fs6.default.promises.access(destPath);
5072
+ (0, import_build_utils9.debug)(`Engine binary: ${runtimeName} already exists, skipping`);
5073
+ } catch {
5074
+ (0, import_build_utils9.debug)(`Engine binary: copying ${entry} -> ${runtimeName}`);
5075
+ await import_fs6.default.promises.copyFile(srcPath, destPath);
5076
+ }
5077
+ engineCopied = true;
5078
+ }
5079
+ } catch (err) {
5080
+ throw new import_build_utils9.NowBuildError({
5081
+ code: "PRISMA_ENGINE_NOT_FOUND",
5082
+ message: `could not read Prisma engine directory "${nodeModulesDir}". This may indicate an incompatible prisma version.
5083
+ ` + (err instanceof Error ? err.message : String(err))
5084
+ });
5085
+ }
5086
+ if (!engineCopied) {
5087
+ throw new import_build_utils9.NowBuildError({
5088
+ code: "PRISMA_ENGINE_NOT_FOUND",
5089
+ message: `could not find engine binary matching "${srcBinaryPrefix}*" in "${nodeModulesDir}". This may indicate an incompatible prisma version or an unsupported platform (${process.arch}).`
5090
+ });
5091
+ }
5092
+ const shimPath = (0, import_path8.join)(cacheDir, "openssl");
5093
+ await import_fs6.default.promises.writeFile(
5094
+ shimPath,
5095
+ `#!/bin/sh
5096
+ echo "OpenSSL ${RUNTIME_OPENSSL_VERSION}.0 1 Jan 2024 (Library: OpenSSL ${RUNTIME_OPENSSL_VERSION}.0)"
5097
+ `
5098
+ );
5099
+ await import_fs6.default.promises.chmod(shimPath, 493);
5100
+ for (const p of [generatedDir, dummySchemaPath]) {
5101
+ await import_fs6.default.promises.rm(p, { recursive: true, force: true });
5102
+ }
5103
+ await cleanCacheArtifacts(cacheDir);
5104
+ const generateMode = (process.env.VERCEL_PRISMA_GENERATE_CLIENT ?? "auto").toLowerCase();
5105
+ const userSchema = generateMode !== "never" ? await findUserSchema(workPath) : null;
5106
+ if (userSchema) {
5107
+ let shouldGenerate = true;
5108
+ if (generateMode === "auto") {
5109
+ const clientAlreadyGenerated = await isClientGenerated(
5110
+ pythonPath,
5111
+ pythonEnv
5112
+ );
5113
+ if (clientAlreadyGenerated) {
5114
+ (0, import_build_utils9.debug)(
5115
+ "Prisma quirk: client already generated, skipping user schema generate"
5116
+ );
5117
+ shouldGenerate = false;
5118
+ }
5119
+ }
5120
+ if (shouldGenerate) {
5121
+ (0, import_build_utils9.debug)(`Running prisma generate with user schema: ${userSchema}`);
5122
+ try {
5123
+ const userResult = await (0, import_execa4.default)(
5124
+ pythonPath,
5125
+ ["-m", "prisma", "generate", `--schema=${userSchema}`],
5126
+ {
5127
+ cwd: workPath,
5128
+ env: generateEnv,
5129
+ stdio: "pipe"
5130
+ }
5131
+ );
5132
+ if (userResult.stdout)
5133
+ (0, import_build_utils9.debug)(`prisma generate stdout: ${userResult.stdout}`);
5134
+ if (userResult.stderr)
5135
+ (0, import_build_utils9.debug)(`prisma generate stderr: ${userResult.stderr}`);
5136
+ } catch (err) {
5137
+ throw new import_build_utils9.NowBuildError({
5138
+ code: "PRISMA_GENERATE_FAILED",
5139
+ message: `\`prisma generate\` failed for schema "${userSchema}".
5140
+ ` + execErrorMessage(err)
5141
+ });
5142
+ }
5143
+ await cleanCacheArtifacts(cacheDir);
5144
+ }
5145
+ }
5146
+ try {
5147
+ const allFiles = await collectFiles(
5148
+ (0, import_path8.join)(sitePackages, "prisma"),
5149
+ sitePackages
5150
+ );
5151
+ const count = await (0, import_python_analysis4.extendDistRecord)(sitePackages, "prisma", allFiles);
5152
+ if (count > 0) {
5153
+ (0, import_build_utils9.debug)(`Appended ${count} entries to prisma RECORD`);
5154
+ }
5155
+ } catch (err) {
5156
+ console.warn(
5157
+ `could not patch prisma RECORD: ${err instanceof Error ? err.message : String(err)}`
5158
+ );
5159
+ }
5160
+ return {
5161
+ env: {
5162
+ PRISMA_BINARY_CACHE_DIR: runtimeCacheDir,
5163
+ VERCEL_RUNTIME_ENV_PATH_PREPEND: runtimeCacheDir
5164
+ },
5165
+ buildEnv: { PRISMA_BINARY_CACHE_DIR: cacheDir },
5166
+ alwaysBundlePackages: ["prisma"]
5167
+ };
5168
+ }
5169
+ };
5170
+
5171
+ // src/quirks/index.ts
5172
+ var quirks = [prismaQuirk];
5173
+ function toposortQuirks(activated) {
5174
+ const nameToQuirk = /* @__PURE__ */ new Map();
5175
+ for (const q of activated) {
5176
+ nameToQuirk.set((0, import_python_analysis5.normalizePackageName)(q.dependency), q);
5177
+ }
5178
+ const adj = /* @__PURE__ */ new Map();
5179
+ const inDegree = /* @__PURE__ */ new Map();
5180
+ for (const q of activated) {
5181
+ adj.set(q, /* @__PURE__ */ new Set());
5182
+ inDegree.set(q, 0);
5183
+ }
5184
+ for (const q of activated) {
5185
+ if (q.runsBefore) {
5186
+ for (const dep of q.runsBefore) {
5187
+ const target = nameToQuirk.get((0, import_python_analysis5.normalizePackageName)(dep));
5188
+ if (target) {
5189
+ adj.get(q).add(target);
5190
+ inDegree.set(target, inDegree.get(target) + 1);
5191
+ }
5192
+ }
5193
+ }
5194
+ if (q.runsAfter) {
5195
+ for (const dep of q.runsAfter) {
5196
+ const source = nameToQuirk.get((0, import_python_analysis5.normalizePackageName)(dep));
5197
+ if (source) {
5198
+ adj.get(source).add(q);
5199
+ inDegree.set(q, inDegree.get(q) + 1);
5200
+ }
5201
+ }
5202
+ }
5203
+ }
5204
+ const queue = [];
5205
+ for (const q of activated) {
5206
+ if (inDegree.get(q) === 0) {
5207
+ queue.push(q);
5208
+ }
5209
+ }
5210
+ const sorted = [];
5211
+ while (queue.length > 0) {
5212
+ const q = queue.shift();
5213
+ sorted.push(q);
5214
+ for (const neighbor of adj.get(q)) {
5215
+ const deg = inDegree.get(neighbor) - 1;
5216
+ inDegree.set(neighbor, deg);
5217
+ if (deg === 0) {
5218
+ queue.push(neighbor);
5219
+ }
5220
+ }
5221
+ }
5222
+ if (sorted.length !== activated.length) {
5223
+ const unsorted = activated.filter((q) => !sorted.includes(q)).map((q) => q.dependency);
5224
+ throw new Error(
5225
+ `Circular dependency detected among quirks: ${unsorted.join(", ")}`
5226
+ );
5227
+ }
5228
+ return sorted;
5229
+ }
5230
+ async function runQuirks(ctx) {
5231
+ const mergedEnv = {};
5232
+ const mergedBuildEnv = {};
5233
+ const mergedAlwaysBundle = [];
5234
+ const installedNames = /* @__PURE__ */ new Set();
5235
+ const sitePackageDirs = await getVenvSitePackagesDirs(ctx.venvPath);
5236
+ for (const dir of sitePackageDirs) {
5237
+ const distributions = await (0, import_python_analysis5.scanDistributions)(dir);
5238
+ for (const name of distributions.keys()) {
5239
+ installedNames.add((0, import_python_analysis5.normalizePackageName)(name));
5240
+ }
5241
+ }
5242
+ const activated = quirks.filter((quirk) => {
5243
+ const installed = installedNames.has(
5244
+ (0, import_python_analysis5.normalizePackageName)(quirk.dependency)
5245
+ );
5246
+ if (!installed) {
5247
+ (0, import_build_utils10.debug)(`Quirk "${quirk.dependency}": not installed, skipping`);
5248
+ }
5249
+ return installed;
5250
+ });
5251
+ const sorted = toposortQuirks(activated);
5252
+ for (const quirk of sorted) {
5253
+ (0, import_build_utils10.debug)(`Quirk "${quirk.dependency}": detected, running fix-up`);
5254
+ const result = await quirk.run(ctx);
5255
+ if (result.env) {
5256
+ Object.assign(mergedEnv, result.env);
5257
+ }
5258
+ if (result.buildEnv) {
5259
+ Object.assign(mergedBuildEnv, result.buildEnv);
5260
+ Object.assign(process.env, result.buildEnv);
5261
+ }
5262
+ if (result.alwaysBundlePackages) {
5263
+ mergedAlwaysBundle.push(...result.alwaysBundlePackages);
5264
+ }
5265
+ }
5266
+ return {
5267
+ env: mergedEnv,
5268
+ buildEnv: mergedBuildEnv,
5269
+ alwaysBundlePackages: mergedAlwaysBundle
5270
+ };
5271
+ }
5272
+
4814
5273
  // src/index.ts
4815
- var readFile2 = (0, import_util2.promisify)(import_fs6.default.readFile);
4816
- var writeFile = (0, import_util2.promisify)(import_fs6.default.writeFile);
5274
+ var readFile2 = (0, import_util2.promisify)(import_fs7.default.readFile);
5275
+ var writeFile = (0, import_util2.promisify)(import_fs7.default.writeFile);
4817
5276
  var version = 3;
4818
5277
  async function downloadFilesInWorkPath({
4819
5278
  entrypoint,
@@ -4821,13 +5280,13 @@ async function downloadFilesInWorkPath({
4821
5280
  files,
4822
5281
  meta = {}
4823
5282
  }) {
4824
- (0, import_build_utils9.debug)("Downloading user files...");
4825
- let downloadedFiles = await (0, import_build_utils9.download)(files, workPath, meta);
5283
+ (0, import_build_utils11.debug)("Downloading user files...");
5284
+ let downloadedFiles = await (0, import_build_utils11.download)(files, workPath, meta);
4826
5285
  if (meta.isDev) {
4827
- const { devCacheDir = (0, import_path8.join)(workPath, ".now", "cache") } = meta;
4828
- const destCache = (0, import_path8.join)(devCacheDir, (0, import_path8.basename)(entrypoint, ".py"));
4829
- await (0, import_build_utils9.download)(downloadedFiles, destCache);
4830
- downloadedFiles = await (0, import_build_utils9.glob)("**", destCache);
5286
+ const { devCacheDir = (0, import_path9.join)(workPath, ".now", "cache") } = meta;
5287
+ const destCache = (0, import_path9.join)(devCacheDir, (0, import_path9.basename)(entrypoint, ".py"));
5288
+ await (0, import_build_utils11.download)(downloadedFiles, destCache);
5289
+ downloadedFiles = await (0, import_build_utils11.glob)("**", destCache);
4831
5290
  workPath = destCache;
4832
5291
  }
4833
5292
  return workPath;
@@ -4844,7 +5303,7 @@ var build = async ({
4844
5303
  let spawnEnv;
4845
5304
  let projectInstallCommand;
4846
5305
  let hasCustomCommand = false;
4847
- (0, import_build_utils9.debug)(`workPath: ${workPath}`);
5306
+ (0, import_build_utils11.debug)(`workPath: ${workPath}`);
4848
5307
  workPath = await downloadFilesInWorkPath({
4849
5308
  workPath,
4850
5309
  files: originalFiles,
@@ -4853,72 +5312,28 @@ var build = async ({
4853
5312
  });
4854
5313
  try {
4855
5314
  if (meta.isDev) {
4856
- const setupCfg = (0, import_path8.join)(workPath, "setup.cfg");
5315
+ const setupCfg = (0, import_path9.join)(workPath, "setup.cfg");
4857
5316
  await writeFile(setupCfg, "[install]\nprefix=\n");
4858
5317
  }
4859
5318
  } catch (err) {
4860
5319
  console.log('Failed to create "setup.cfg" file');
4861
5320
  throw err;
4862
5321
  }
4863
- if ((0, import_build_utils9.isPythonFramework)(framework)) {
4864
- const {
4865
- cliType,
4866
- lockfileVersion,
4867
- packageJsonPackageManager,
4868
- turboSupportsCorepackHome
4869
- } = await (0, import_build_utils9.scanParentDirs)(workPath, true);
4870
- spawnEnv = (0, import_build_utils9.getEnvForPackageManager)({
4871
- cliType,
4872
- lockfileVersion,
4873
- packageJsonPackageManager,
4874
- env: process.env,
4875
- turboSupportsCorepackHome,
4876
- projectCreatedAt: config?.projectSettings?.createdAt
4877
- });
4878
- const installCommand = config?.projectSettings?.installCommand;
4879
- if (typeof installCommand === "string") {
4880
- const trimmed = installCommand.trim();
4881
- if (trimmed) {
4882
- projectInstallCommand = trimmed;
4883
- } else {
4884
- console.log('Skipping "install" command...');
4885
- }
4886
- }
4887
- const projectBuildCommand = config?.projectSettings?.buildCommand ?? // fallback if provided directly on config (some callers set this)
4888
- config?.buildCommand;
4889
- if (projectBuildCommand) {
4890
- console.log(`Running "${projectBuildCommand}"`);
4891
- await (0, import_build_utils9.execCommand)(projectBuildCommand, {
4892
- env: spawnEnv,
4893
- cwd: workPath
4894
- });
4895
- hasCustomCommand = true;
4896
- } else {
4897
- const ranBuildScript = await runPyprojectScript(
4898
- workPath,
4899
- ["vercel-build", "now-build", "build"],
4900
- spawnEnv
4901
- );
4902
- if (ranBuildScript) {
4903
- hasCustomCommand = true;
4904
- }
4905
- }
4906
- }
4907
- let fsFiles = await (0, import_build_utils9.glob)("**", workPath);
4908
- if ((0, import_build_utils9.isPythonFramework)(framework) && (!fsFiles[entrypoint] || !entrypoint.endsWith(".py"))) {
5322
+ let fsFiles = await (0, import_build_utils11.glob)("**", workPath);
5323
+ if ((0, import_build_utils11.isPythonFramework)(framework) && (!fsFiles[entrypoint] || !entrypoint.endsWith(".py"))) {
4909
5324
  const detected = await detectPythonEntrypoint(
4910
5325
  config.framework,
4911
5326
  workPath,
4912
5327
  entrypoint
4913
5328
  );
4914
5329
  if (detected) {
4915
- (0, import_build_utils9.debug)(
5330
+ (0, import_build_utils11.debug)(
4916
5331
  `Resolved Python entrypoint to "${detected}" (configured "${entrypoint}" not found).`
4917
5332
  );
4918
5333
  entrypoint = detected;
4919
5334
  } else {
4920
5335
  const searchedList = PYTHON_CANDIDATE_ENTRYPOINTS.join(", ");
4921
- throw new import_build_utils9.NowBuildError({
5336
+ throw new import_build_utils11.NowBuildError({
4922
5337
  code: `${framework.toUpperCase()}_ENTRYPOINT_NOT_FOUND`,
4923
5338
  message: `No ${framework} entrypoint found. Add an 'app' script in pyproject.toml or define an entrypoint in one of: ${searchedList}.`,
4924
5339
  link: `https://vercel.com/docs/frameworks/backend/${framework}#exporting-the-${framework}-application`,
@@ -4926,7 +5341,7 @@ var build = async ({
4926
5341
  });
4927
5342
  }
4928
5343
  }
4929
- const entryDirectory = (0, import_path8.dirname)(entrypoint);
5344
+ const entryDirectory = (0, import_path9.dirname)(entrypoint);
4930
5345
  const pyprojectDir = findDir({
4931
5346
  file: "pyproject.toml",
4932
5347
  entryDirectory,
@@ -4949,37 +5364,37 @@ var build = async ({
4949
5364
  if (pythonVersionFileDir) {
4950
5365
  try {
4951
5366
  const content = await readFile2(
4952
- (0, import_path8.join)(pythonVersionFileDir, ".python-version"),
5367
+ (0, import_path9.join)(pythonVersionFileDir, ".python-version"),
4953
5368
  "utf8"
4954
5369
  );
4955
5370
  const version2 = parsePythonVersionFile(content);
4956
5371
  if (version2) {
4957
5372
  declaredPythonVersion = { version: version2, source: ".python-version" };
4958
- (0, import_build_utils9.debug)(`Found Python version ${version2} in .python-version`);
5373
+ (0, import_build_utils11.debug)(`Found Python version ${version2} in .python-version`);
4959
5374
  }
4960
5375
  } catch (err) {
4961
- (0, import_build_utils9.debug)("Failed to read .python-version file", err);
5376
+ (0, import_build_utils11.debug)("Failed to read .python-version file", err);
4962
5377
  }
4963
5378
  }
4964
5379
  if (!declaredPythonVersion && pyprojectDir) {
4965
5380
  let requiresPython;
4966
5381
  try {
4967
- const pyproject = await (0, import_build_utils10.readConfigFile)((0, import_path8.join)(pyprojectDir, "pyproject.toml"));
5382
+ const pyproject = await (0, import_build_utils12.readConfigFile)((0, import_path9.join)(pyprojectDir, "pyproject.toml"));
4968
5383
  requiresPython = pyproject?.project?.["requires-python"];
4969
5384
  } catch (err) {
4970
- (0, import_build_utils9.debug)("Failed to parse pyproject.toml", err);
5385
+ (0, import_build_utils11.debug)("Failed to parse pyproject.toml", err);
4971
5386
  }
4972
5387
  if (typeof requiresPython === "string" && requiresPython.trim()) {
4973
5388
  declaredPythonVersion = {
4974
5389
  version: requiresPython.trim(),
4975
5390
  source: "pyproject.toml"
4976
5391
  };
4977
- (0, import_build_utils9.debug)(`Found requires-python "${requiresPython}" in pyproject.toml`);
5392
+ (0, import_build_utils11.debug)(`Found requires-python "${requiresPython}" in pyproject.toml`);
4978
5393
  }
4979
5394
  }
4980
5395
  if (!declaredPythonVersion && pipfileLockDir) {
4981
5396
  let lock = {};
4982
- const pipfileLockPath = (0, import_path8.join)(pipfileLockDir, "Pipfile.lock");
5397
+ const pipfileLockPath = (0, import_path9.join)(pipfileLockDir, "Pipfile.lock");
4983
5398
  try {
4984
5399
  const pipfileLockContent = await readFile2(pipfileLockPath, "utf8");
4985
5400
  try {
@@ -4992,7 +5407,7 @@ ${pipfileLockContent}`
4992
5407
  throw err;
4993
5408
  }
4994
5409
  } catch (err) {
4995
- throw new import_build_utils9.NowBuildError({
5410
+ throw new import_build_utils11.NowBuildError({
4996
5411
  code: "INVALID_PIPFILE_LOCK",
4997
5412
  message: "Unable to parse Pipfile.lock"
4998
5413
  });
@@ -5000,7 +5415,7 @@ ${pipfileLockContent}`
5000
5415
  const pyFromLock = lock?._meta?.requires?.python_version;
5001
5416
  if (pyFromLock) {
5002
5417
  declaredPythonVersion = { version: pyFromLock, source: "Pipfile.lock" };
5003
- (0, import_build_utils9.debug)(`Found Python version ${pyFromLock} in Pipfile.lock`);
5418
+ (0, import_build_utils11.debug)(`Found Python version ${pyFromLock} in Pipfile.lock`);
5004
5419
  }
5005
5420
  }
5006
5421
  const pythonVersion = getSupportedPythonVersion({
@@ -5010,26 +5425,51 @@ ${pipfileLockContent}`
5010
5425
  const selectedVersionTuple = parseVersionTuple(pythonVersion.version);
5011
5426
  const defaultVersionTuple = parseVersionTuple(DEFAULT_PYTHON_VERSION);
5012
5427
  if (!pythonVersionFileDir && pyprojectDir && declaredPythonVersion?.source === "pyproject.toml" && selectedVersionTuple && defaultVersionTuple && compareTuples(selectedVersionTuple, defaultVersionTuple) <= 0) {
5013
- const pythonVersionFilePath = (0, import_path8.join)(pyprojectDir, ".python-version");
5428
+ const pythonVersionFilePath = (0, import_path9.join)(pyprojectDir, ".python-version");
5014
5429
  await writeFile(pythonVersionFilePath, `${pythonVersion.version}
5015
5430
  `);
5016
5431
  console.log(
5017
5432
  `Writing .python-version file with version ${pythonVersion.version}`
5018
5433
  );
5019
5434
  }
5020
- fsFiles = await (0, import_build_utils9.glob)("**", workPath);
5021
- const venvPath = (0, import_path8.join)(workPath, ".vercel", "python", ".venv");
5435
+ fsFiles = await (0, import_build_utils11.glob)("**", workPath);
5436
+ const venvPath = (0, import_path9.join)(workPath, ".vercel", "python", ".venv");
5022
5437
  await ensureVenv({
5023
5438
  pythonPath: pythonVersion.pythonPath,
5024
5439
  venvPath
5025
5440
  });
5441
+ if ((0, import_build_utils11.isPythonFramework)(framework)) {
5442
+ const {
5443
+ cliType,
5444
+ lockfileVersion,
5445
+ packageJsonPackageManager,
5446
+ turboSupportsCorepackHome
5447
+ } = await (0, import_build_utils11.scanParentDirs)(workPath, true);
5448
+ spawnEnv = (0, import_build_utils11.getEnvForPackageManager)({
5449
+ cliType,
5450
+ lockfileVersion,
5451
+ packageJsonPackageManager,
5452
+ env: process.env,
5453
+ turboSupportsCorepackHome,
5454
+ projectCreatedAt: config?.projectSettings?.createdAt
5455
+ });
5456
+ const installCommand = config?.projectSettings?.installCommand;
5457
+ if (typeof installCommand === "string") {
5458
+ const trimmed = installCommand.trim();
5459
+ if (trimmed) {
5460
+ projectInstallCommand = trimmed;
5461
+ } else {
5462
+ console.log('Skipping "install" command...');
5463
+ }
5464
+ }
5465
+ }
5026
5466
  const baseEnv = spawnEnv || process.env;
5027
5467
  const pythonEnv = createVenvEnv(venvPath, baseEnv);
5028
5468
  pythonEnv.VERCEL_PYTHON_VENV_PATH = venvPath;
5029
5469
  let assumeDepsInstalled = false;
5030
5470
  if (projectInstallCommand) {
5031
5471
  console.log(`Running "install" command: \`${projectInstallCommand}\`...`);
5032
- await (0, import_build_utils9.execCommand)(projectInstallCommand, {
5472
+ await (0, import_build_utils11.execCommand)(projectInstallCommand, {
5033
5473
  env: pythonEnv,
5034
5474
  cwd: workPath
5035
5475
  });
@@ -5090,7 +5530,7 @@ ${pipfileLockContent}`
5090
5530
  });
5091
5531
  } catch (err) {
5092
5532
  noBuildCheckFailed = true;
5093
- (0, import_build_utils9.debug)(
5533
+ (0, import_build_utils11.debug)(
5094
5534
  `--no-build check failed: ${err instanceof Error ? err.message : String(err)}`
5095
5535
  );
5096
5536
  }
@@ -5102,19 +5542,40 @@ ${pipfileLockContent}`
5102
5542
  locked: !lockFileProvidedByUser
5103
5543
  });
5104
5544
  }
5545
+ if ((0, import_build_utils11.isPythonFramework)(framework)) {
5546
+ const projectBuildCommand = config?.projectSettings?.buildCommand ?? // fallback if provided directly on config (some callers set this)
5547
+ config?.buildCommand;
5548
+ if (projectBuildCommand) {
5549
+ console.log(`Running "${projectBuildCommand}"`);
5550
+ await (0, import_build_utils11.execCommand)(projectBuildCommand, {
5551
+ env: pythonEnv,
5552
+ cwd: workPath
5553
+ });
5554
+ } else {
5555
+ await runPyprojectScript(
5556
+ workPath,
5557
+ ["vercel-build", "now-build", "build"],
5558
+ pythonEnv
5559
+ );
5560
+ }
5561
+ }
5105
5562
  const runtimeDep = baseEnv.VERCEL_RUNTIME_PYTHON || `vercel-runtime==${VERCEL_RUNTIME_VERSION}`;
5106
- (0, import_build_utils9.debug)(`Installing ${runtimeDep}`);
5563
+ (0, import_build_utils11.debug)(`Installing ${runtimeDep}`);
5107
5564
  await uv.pip({
5108
5565
  venvPath,
5109
- projectDir: (0, import_path8.join)(workPath, entryDirectory),
5566
+ projectDir: (0, import_path9.join)(workPath, entryDirectory),
5110
5567
  args: ["install", runtimeDep]
5111
5568
  });
5112
- (0, import_build_utils9.debug)("Entrypoint is", entrypoint);
5569
+ const quirksResult = await runQuirks({ venvPath, pythonEnv, workPath });
5570
+ if (quirksResult.buildEnv) {
5571
+ Object.assign(pythonEnv, quirksResult.buildEnv);
5572
+ }
5573
+ (0, import_build_utils11.debug)("Entrypoint is", entrypoint);
5113
5574
  const moduleName = entrypoint.replace(/\//g, ".").replace(/\.py$/i, "");
5114
5575
  const vendorDir = resolveVendorDir();
5115
5576
  const suffix = meta.isDev && !entrypoint.endsWith(".py") ? ".py" : "";
5116
5577
  const entrypointWithSuffix = `${entrypoint}${suffix}`;
5117
- (0, import_build_utils9.debug)("Entrypoint with suffix is", entrypointWithSuffix);
5578
+ (0, import_build_utils11.debug)("Entrypoint with suffix is", entrypointWithSuffix);
5118
5579
  const runtimeTrampoline = `
5119
5580
  import importlib
5120
5581
  import os
@@ -5173,11 +5634,12 @@ from vercel_runtime.vc_init import vc_handler
5173
5634
  ];
5174
5635
  const lambdaEnv = {};
5175
5636
  lambdaEnv.PYTHONPATH = vendorDir;
5637
+ Object.assign(lambdaEnv, quirksResult.env);
5176
5638
  const globOptions = {
5177
5639
  cwd: workPath,
5178
5640
  ignore: config && typeof config.excludeFiles === "string" ? [...predefinedExcludes, config.excludeFiles] : predefinedExcludes
5179
5641
  };
5180
- const files = await (0, import_build_utils9.glob)("**", globOptions);
5642
+ const files = await (0, import_build_utils11.glob)("**", globOptions);
5181
5643
  const depExternalizer = new PythonDependencyExternalizer({
5182
5644
  venvPath,
5183
5645
  vendorDir,
@@ -5187,7 +5649,8 @@ from vercel_runtime.vc_init import vc_handler
5187
5649
  projectName,
5188
5650
  noBuildCheckFailed,
5189
5651
  pythonPath: pythonVersion.pythonPath,
5190
- hasCustomCommand
5652
+ hasCustomCommand,
5653
+ alwaysBundlePackages: quirksResult.alwaysBundlePackages
5191
5654
  });
5192
5655
  const { runtimeInstallEnabled, allVendorFiles } = await depExternalizer.analyze(files);
5193
5656
  if (runtimeInstallEnabled) {
@@ -5198,12 +5661,12 @@ from vercel_runtime.vc_init import vc_handler
5198
5661
  }
5199
5662
  }
5200
5663
  const handlerPyFilename = "vc__handler__python";
5201
- files[`${handlerPyFilename}.py`] = new import_build_utils9.FileBlob({ data: runtimeTrampoline });
5664
+ files[`${handlerPyFilename}.py`] = new import_build_utils11.FileBlob({ data: runtimeTrampoline });
5202
5665
  if (config.framework === "fasthtml") {
5203
5666
  const { SESSKEY = "" } = process.env;
5204
- files[".sesskey"] = new import_build_utils9.FileBlob({ data: `"${SESSKEY}"` });
5667
+ files[".sesskey"] = new import_build_utils11.FileBlob({ data: `"${SESSKEY}"` });
5205
5668
  }
5206
- const output = new import_build_utils9.Lambda({
5669
+ const output = new import_build_utils11.Lambda({
5207
5670
  files,
5208
5671
  handler: `${handlerPyFilename}.vc_handler`,
5209
5672
  runtime: pythonVersion.runtime,
@@ -5214,7 +5677,7 @@ from vercel_runtime.vc_init import vc_handler
5214
5677
  };
5215
5678
  var shouldServe = (opts) => {
5216
5679
  const framework = opts.config.framework;
5217
- if ((0, import_build_utils9.isPythonFramework)(framework)) {
5680
+ if ((0, import_build_utils11.isPythonFramework)(framework)) {
5218
5681
  const requestPath = opts.requestPath.replace(/\/$/, "");
5219
5682
  if (requestPath.startsWith("api") && opts.hasMatched) {
5220
5683
  return false;
@@ -5233,7 +5696,7 @@ var defaultShouldServe = ({
5233
5696
  if (entrypoint === requestPath && hasProp(files, entrypoint)) {
5234
5697
  return true;
5235
5698
  }
5236
- const { dir, name } = (0, import_path8.parse)(entrypoint);
5699
+ const { dir, name } = (0, import_path9.parse)(entrypoint);
5237
5700
  if (name === "index" && dir === requestPath && hasProp(files, entrypoint)) {
5238
5701
  return true;
5239
5702
  }