@vercel/python 6.3.2 → 6.4.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 +795 -689
  2. package/package.json +1 -1
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 fs4 = require("fs");
51
+ var fs5 = 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
- fs4.stat(path, function(er, stat) {
76
+ fs5.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(fs4.statSync(path), path, options);
81
+ return checkStat(fs5.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 fs4 = require("fs");
91
+ var fs5 = require("fs");
92
92
  function isexe(path, options, cb) {
93
- fs4.stat(path, function(er, stat) {
93
+ fs5.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(fs4.statSync(path), options);
98
+ return checkStat(fs5.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 fs4 = require("fs");
122
+ var fs5 = require("fs");
123
123
  var core;
124
124
  if (process.platform === "win32" || global.TESTING_WINDOWS) {
125
125
  core = require_windows();
@@ -174,8 +174,8 @@ var require_isexe = __commonJS({
174
174
  // ../../node_modules/.pnpm/which@1.3.1/node_modules/which/which.js
175
175
  var require_which = __commonJS({
176
176
  "../../node_modules/.pnpm/which@1.3.1/node_modules/which/which.js"(exports, module2) {
177
- module2.exports = which3;
178
- which3.sync = whichSync;
177
+ module2.exports = which2;
178
+ which2.sync = whichSync;
179
179
  var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
180
180
  var path = require("path");
181
181
  var COLON = isWindows ? ";" : ":";
@@ -206,7 +206,7 @@ var require_which = __commonJS({
206
206
  extExe: pathExtExe
207
207
  };
208
208
  }
209
- function which3(cmd, opt, cb) {
209
+ function which2(cmd, opt, cb) {
210
210
  if (typeof opt === "function") {
211
211
  cb = opt;
212
212
  opt = {};
@@ -307,7 +307,7 @@ var require_resolveCommand = __commonJS({
307
307
  "../../node_modules/.pnpm/cross-spawn@6.0.5/node_modules/cross-spawn/lib/util/resolveCommand.js"(exports, module2) {
308
308
  "use strict";
309
309
  var path = require("path");
310
- var which3 = require_which();
310
+ var which2 = require_which();
311
311
  var pathKey = require_path_key()();
312
312
  function resolveCommandAttempt(parsed, withoutPathExt) {
313
313
  const cwd = process.cwd();
@@ -320,7 +320,7 @@ var require_resolveCommand = __commonJS({
320
320
  }
321
321
  let resolved;
322
322
  try {
323
- resolved = which3.sync(parsed.command, {
323
+ resolved = which2.sync(parsed.command, {
324
324
  path: (parsed.options.env || process.env)[pathKey],
325
325
  pathExt: withoutPathExt ? path.delimiter : void 0
326
326
  });
@@ -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 fs4 = require("fs");
398
+ var fs5 = 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 = fs4.openSync(command, "r");
412
- fs4.readSync(fd, buffer, 0, size, 0);
413
- fs4.closeSync(fd);
411
+ fd = fs5.openSync(command, "r");
412
+ fs5.readSync(fd, buffer, 0, size, 0);
413
+ fs5.closeSync(fd);
414
414
  } catch (e) {
415
415
  }
416
416
  return shebangCommand(buffer.toString());
@@ -1498,7 +1498,7 @@ var require_parse = __commonJS({
1498
1498
  var escape = require_escape();
1499
1499
  var readShebang = require_readShebang();
1500
1500
  var semver = require_semver();
1501
- var isWin3 = process.platform === "win32";
1501
+ var isWin4 = process.platform === "win32";
1502
1502
  var isExecutableRegExp = /\.(?:com|exe)$/i;
1503
1503
  var isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;
1504
1504
  var supportsShellOption = niceTry(() => semver.satisfies(process.version, "^4.8.0 || ^5.7.0 || >= 6.0.0", true)) || false;
@@ -1513,7 +1513,7 @@ var require_parse = __commonJS({
1513
1513
  return parsed.file;
1514
1514
  }
1515
1515
  function parseNonShell(parsed) {
1516
- if (!isWin3) {
1516
+ if (!isWin4) {
1517
1517
  return parsed;
1518
1518
  }
1519
1519
  const commandFile = detectShebang(parsed);
@@ -1535,7 +1535,7 @@ var require_parse = __commonJS({
1535
1535
  return parsed;
1536
1536
  }
1537
1537
  const shellCommand = [parsed.command].concat(parsed.args).join(" ");
1538
- if (isWin3) {
1538
+ if (isWin4) {
1539
1539
  parsed.command = typeof parsed.options.shell === "string" ? parsed.options.shell : process.env.comspec || "cmd.exe";
1540
1540
  parsed.args = ["/d", "/s", "/c", `"${shellCommand}"`];
1541
1541
  parsed.options.windowsVerbatimArguments = true;
@@ -1578,7 +1578,7 @@ var require_parse = __commonJS({
1578
1578
  var require_enoent = __commonJS({
1579
1579
  "../../node_modules/.pnpm/cross-spawn@6.0.5/node_modules/cross-spawn/lib/enoent.js"(exports, module2) {
1580
1580
  "use strict";
1581
- var isWin3 = process.platform === "win32";
1581
+ var isWin4 = process.platform === "win32";
1582
1582
  function notFoundError(original, syscall) {
1583
1583
  return Object.assign(new Error(`${syscall} ${original.command} ENOENT`), {
1584
1584
  code: "ENOENT",
@@ -1589,7 +1589,7 @@ var require_enoent = __commonJS({
1589
1589
  });
1590
1590
  }
1591
1591
  function hookChildProcess(cp, parsed) {
1592
- if (!isWin3) {
1592
+ if (!isWin4) {
1593
1593
  return;
1594
1594
  }
1595
1595
  const originalEmit = cp.emit;
@@ -1604,13 +1604,13 @@ var require_enoent = __commonJS({
1604
1604
  };
1605
1605
  }
1606
1606
  function verifyENOENT(status, parsed) {
1607
- if (isWin3 && status === 1 && !parsed.file) {
1607
+ if (isWin4 && status === 1 && !parsed.file) {
1608
1608
  return notFoundError(parsed.original, "spawn");
1609
1609
  }
1610
1610
  return null;
1611
1611
  }
1612
1612
  function verifyENOENTSync(status, parsed) {
1613
- if (isWin3 && status === 1 && !parsed.file) {
1613
+ if (isWin4 && status === 1 && !parsed.file) {
1614
1614
  return notFoundError(parsed.original, "spawnSync");
1615
1615
  }
1616
1616
  return null;
@@ -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 fs4;
1898
+ var fs5;
1899
1899
  try {
1900
- fs4 = require("fs");
1900
+ fs5 = 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 (!fs4)
1912
+ if (!fs5)
1913
1913
  return false;
1914
- return (stream instanceof (fs4.ReadStream || noop) || stream instanceof (fs4.WriteStream || noop)) && isFn(stream.close);
1914
+ return (stream instanceof (fs5.ReadStream || noop) || stream instanceof (fs5.WriteStream || noop)) && isFn(stream.close);
1915
1915
  };
1916
1916
  var isRequest = function(stream) {
1917
1917
  return stream.setHeader && isFn(stream.abort);
@@ -2143,7 +2143,7 @@ var require_signal_exit = __commonJS({
2143
2143
  } else {
2144
2144
  assert = require("assert");
2145
2145
  signals = require_signals();
2146
- isWin3 = /^win/i.test(process2.platform);
2146
+ isWin4 = /^win/i.test(process2.platform);
2147
2147
  EE = require("events");
2148
2148
  if (typeof EE !== "function") {
2149
2149
  EE = EE.EventEmitter;
@@ -2215,7 +2215,7 @@ var require_signal_exit = __commonJS({
2215
2215
  unload();
2216
2216
  emit("exit", null, sig);
2217
2217
  emit("afterexit", null, sig);
2218
- if (isWin3 && sig === "SIGHUP") {
2218
+ if (isWin4 && sig === "SIGHUP") {
2219
2219
  sig = "SIGINT";
2220
2220
  }
2221
2221
  process2.kill(process2.pid, sig);
@@ -2272,7 +2272,7 @@ var require_signal_exit = __commonJS({
2272
2272
  }
2273
2273
  var assert;
2274
2274
  var signals;
2275
- var isWin3;
2275
+ var isWin4;
2276
2276
  var EE;
2277
2277
  var emitter;
2278
2278
  var unload;
@@ -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: join6, delimiter, sep, posix } = require("path");
2654
+ var { join: join7, delimiter, sep, posix } = require("path");
2655
2655
  var isWindows = process.platform === "win32";
2656
2656
  var rSlash = new RegExp(`[${posix.sep}${sep === posix.sep ? "" : sep}]`.replace(/(\\)/g, "\\$1"));
2657
2657
  var rRel = new RegExp(`^\\.${rSlash.source}`);
@@ -2680,9 +2680,9 @@ 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 + join6(pathPart, cmd);
2683
+ return prefix + join7(pathPart, cmd);
2684
2684
  };
2685
- var which3 = async (cmd, opt = {}) => {
2685
+ var which2 = async (cmd, opt = {}) => {
2686
2686
  const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
2687
2687
  const found = [];
2688
2688
  for (const envPart of pathEnv) {
@@ -2730,8 +2730,8 @@ var require_lib = __commonJS({
2730
2730
  }
2731
2731
  throw getNotFoundError(cmd);
2732
2732
  };
2733
- module2.exports = which3;
2734
- which3.sync = whichSync;
2733
+ module2.exports = which2;
2734
+ which2.sync = whichSync;
2735
2735
  }
2736
2736
  });
2737
2737
 
@@ -2748,55 +2748,279 @@ __export(src_exports, {
2748
2748
  version: () => version
2749
2749
  });
2750
2750
  module.exports = __toCommonJS(src_exports);
2751
- var import_fs4 = __toESM(require("fs"));
2751
+ var import_fs5 = __toESM(require("fs"));
2752
2752
  var import_util = require("util");
2753
- var import_path5 = require("path");
2754
- var import_build_utils7 = require("@vercel/build-utils");
2753
+ var import_path7 = require("path");
2754
+ var import_build_utils8 = require("@vercel/build-utils");
2755
2755
 
2756
2756
  // src/install.ts
2757
- var import_execa2 = __toESM(require_execa());
2757
+ var import_execa3 = __toESM(require_execa());
2758
+ var import_fs3 = __toESM(require("fs"));
2759
+ var import_os2 = __toESM(require("os"));
2760
+ var import_path4 = require("path");
2761
+ var import_build_utils4 = require("@vercel/build-utils");
2762
+
2763
+ // src/utils.ts
2758
2764
  var import_fs2 = __toESM(require("fs"));
2759
- var import_os = __toESM(require("os"));
2760
- var import_path2 = require("path");
2761
- var import_which = __toESM(require_lib());
2765
+ var import_path3 = require("path");
2762
2766
  var import_build_utils2 = require("@vercel/build-utils");
2767
+ var import_execa2 = __toESM(require_execa());
2763
2768
 
2764
- // src/utils.ts
2765
- var import_fs = __toESM(require("fs"));
2769
+ // src/uv.ts
2770
+ var import_child_process = require("child_process");
2766
2771
  var import_path = require("path");
2767
- var import_build_utils = require("@vercel/build-utils");
2772
+ var import_path2 = require("path");
2768
2773
  var import_execa = __toESM(require_execa());
2769
- var isWin = process.platform === "win32";
2774
+ var import_fs = __toESM(require("fs"));
2775
+ var import_os = __toESM(require("os"));
2776
+ var import_which = __toESM(require_lib());
2777
+ var import_build_utils = require("@vercel/build-utils");
2778
+ var UV_VERSION = "0.9.22";
2779
+ var UV_PYTHON_PATH_PREFIX = "/uv/python/";
2770
2780
  var UV_PYTHON_DOWNLOADS_MODE = "automatic";
2781
+ var isWin = process.platform === "win32";
2782
+ var uvExec = isWin ? "uv.exe" : "uv";
2783
+ function findUvInPath() {
2784
+ return import_which.default.sync("uv", { nothrow: true });
2785
+ }
2786
+ var UvRunner = class {
2787
+ constructor(uvPath) {
2788
+ this.uvPath = uvPath;
2789
+ }
2790
+ getPath() {
2791
+ return this.uvPath;
2792
+ }
2793
+ /**
2794
+ * List installed Python versions managed by uv.
2795
+ * Excludes system Python.
2796
+ */
2797
+ listInstalledPythons() {
2798
+ let output;
2799
+ try {
2800
+ output = (0, import_child_process.execSync)(
2801
+ `${this.uvPath} python list --only-installed --output-format json`,
2802
+ { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }
2803
+ );
2804
+ } catch (err) {
2805
+ throw new Error(
2806
+ `Failed to run 'uv python list': ${err instanceof Error ? err.message : String(err)}`
2807
+ );
2808
+ }
2809
+ if (!output || output.trim() === "" || output.trim() === "[]") {
2810
+ return /* @__PURE__ */ new Set();
2811
+ }
2812
+ let pyList;
2813
+ try {
2814
+ pyList = JSON.parse(output);
2815
+ } catch (err) {
2816
+ throw new Error(
2817
+ `Failed to parse 'uv python list' output: ${err instanceof Error ? err.message : String(err)}`
2818
+ );
2819
+ }
2820
+ return new Set(
2821
+ pyList.filter(
2822
+ (entry) => entry.path !== null && entry.path.startsWith(UV_PYTHON_PATH_PREFIX) && entry.implementation === "cpython"
2823
+ ).map(
2824
+ (entry) => `${entry.version_parts.major}.${entry.version_parts.minor}`
2825
+ )
2826
+ );
2827
+ }
2828
+ async sync(options) {
2829
+ const { venvPath, projectDir, locked } = options;
2830
+ const args = ["sync", "--active", "--no-dev", "--link-mode", "copy"];
2831
+ if (locked) {
2832
+ args.push("--locked");
2833
+ }
2834
+ args.push("--no-editable");
2835
+ await this.runUvCmd(args, projectDir, venvPath);
2836
+ }
2837
+ async lock(projectDir) {
2838
+ const args = ["lock"];
2839
+ const pretty = `uv ${args.join(" ")}`;
2840
+ (0, import_build_utils.debug)(`Running "${pretty}" in ${projectDir}...`);
2841
+ try {
2842
+ await (0, import_execa.default)(this.uvPath, args, {
2843
+ cwd: projectDir,
2844
+ env: getProtectedUvEnv(process.env)
2845
+ });
2846
+ } catch (err) {
2847
+ throw new Error(
2848
+ `Failed to run "${pretty}": ${err instanceof Error ? err.message : String(err)}`
2849
+ );
2850
+ }
2851
+ }
2852
+ async addDependencies(options) {
2853
+ const { venvPath, projectDir, dependencies } = options;
2854
+ const toAdd = dependencies.filter(Boolean);
2855
+ if (!toAdd.length)
2856
+ return;
2857
+ const args = ["add", "--active", ...toAdd];
2858
+ (0, import_build_utils.debug)(`Running "uv ${args.join(" ")}" in ${projectDir}...`);
2859
+ await this.runUvCmd(args, projectDir, venvPath);
2860
+ }
2861
+ async addFromFile(options) {
2862
+ const { venvPath, projectDir, requirementsPath } = options;
2863
+ const args = ["add", "--active", "-r", requirementsPath];
2864
+ (0, import_build_utils.debug)(`Running "uv ${args.join(" ")}" in ${projectDir}...`);
2865
+ await this.runUvCmd(args, projectDir, venvPath);
2866
+ }
2867
+ async runUvCmd(args, cwd, venvPath) {
2868
+ const pretty = `uv ${args.join(" ")}`;
2869
+ (0, import_build_utils.debug)(`Running "${pretty}"...`);
2870
+ try {
2871
+ await (0, import_execa.default)(this.uvPath, args, {
2872
+ cwd,
2873
+ env: this.getVenvEnv(venvPath)
2874
+ });
2875
+ } catch (err) {
2876
+ throw new Error(
2877
+ `Failed to run "${pretty}": ${err instanceof Error ? err.message : String(err)}`
2878
+ );
2879
+ }
2880
+ }
2881
+ getVenvEnv(venvPath) {
2882
+ const binDir = isWin ? (0, import_path.join)(venvPath, "Scripts") : (0, import_path.join)(venvPath, "bin");
2883
+ const existingPath = process.env.PATH || "";
2884
+ return {
2885
+ ...getProtectedUvEnv(process.env),
2886
+ VIRTUAL_ENV: venvPath,
2887
+ PATH: existingPath ? `${binDir}${import_path2.delimiter}${existingPath}` : binDir
2888
+ };
2889
+ }
2890
+ };
2891
+ async function getGlobalScriptsDir(pythonPath) {
2892
+ const code = `import sysconfig; print(sysconfig.get_path('scripts'))`;
2893
+ try {
2894
+ const { stdout } = await (0, import_execa.default)(pythonPath, ["-c", code]);
2895
+ const out = stdout.trim();
2896
+ return out || null;
2897
+ } catch (err) {
2898
+ (0, import_build_utils.debug)("Failed to resolve Python global scripts directory", err);
2899
+ return null;
2900
+ }
2901
+ }
2902
+ async function getUserScriptsDir(pythonPath) {
2903
+ const code = `import sys, sysconfig; print(sysconfig.get_path('scripts', scheme=('nt_user' if sys.platform == 'win32' else 'posix_user')))`.replace(
2904
+ /\n/g,
2905
+ " "
2906
+ );
2907
+ try {
2908
+ const { stdout } = await (0, import_execa.default)(pythonPath, ["-c", code]);
2909
+ const out = stdout.trim();
2910
+ return out || null;
2911
+ } catch (err) {
2912
+ (0, import_build_utils.debug)("Failed to resolve Python user scripts directory", err);
2913
+ return null;
2914
+ }
2915
+ }
2916
+ async function findUvBinary(pythonPath) {
2917
+ const found = import_which.default.sync("uv", { nothrow: true });
2918
+ if (found)
2919
+ return found;
2920
+ try {
2921
+ const globalScriptsDir = await getGlobalScriptsDir(pythonPath);
2922
+ if (globalScriptsDir) {
2923
+ const uvPath = (0, import_path.join)(globalScriptsDir, uvExec);
2924
+ if (import_fs.default.existsSync(uvPath))
2925
+ return uvPath;
2926
+ }
2927
+ } catch (err) {
2928
+ (0, import_build_utils.debug)("Failed to resolve Python global scripts directory", err);
2929
+ }
2930
+ try {
2931
+ const userScriptsDir = await getUserScriptsDir(pythonPath);
2932
+ if (userScriptsDir) {
2933
+ const uvPath = (0, import_path.join)(userScriptsDir, uvExec);
2934
+ if (import_fs.default.existsSync(uvPath))
2935
+ return uvPath;
2936
+ }
2937
+ } catch (err) {
2938
+ (0, import_build_utils.debug)("Failed to resolve Python user scripts directory", err);
2939
+ }
2940
+ try {
2941
+ const candidates = [];
2942
+ if (!isWin) {
2943
+ candidates.push((0, import_path.join)(import_os.default.homedir(), ".local", "bin", "uv"));
2944
+ candidates.push("/usr/local/bin/uv");
2945
+ candidates.push("/opt/homebrew/bin/uv");
2946
+ } else {
2947
+ candidates.push("C:\\Users\\Public\\uv\\uv.exe");
2948
+ }
2949
+ for (const p of candidates) {
2950
+ if (import_fs.default.existsSync(p))
2951
+ return p;
2952
+ }
2953
+ } catch (err) {
2954
+ (0, import_build_utils.debug)("Failed to resolve uv fallback paths", err);
2955
+ }
2956
+ return null;
2957
+ }
2958
+ async function getUvBinaryOrInstall(pythonPath) {
2959
+ const uvBin = await findUvBinary(pythonPath);
2960
+ if (uvBin)
2961
+ return uvBin;
2962
+ try {
2963
+ console.log("Installing uv...");
2964
+ await (0, import_execa.default)(
2965
+ pythonPath,
2966
+ [
2967
+ "-m",
2968
+ "pip",
2969
+ "install",
2970
+ "--disable-pip-version-check",
2971
+ "--no-cache-dir",
2972
+ "--user",
2973
+ `uv==${UV_VERSION}`
2974
+ ],
2975
+ { env: { ...process.env, PIP_USER: "1" } }
2976
+ );
2977
+ } catch (err) {
2978
+ throw new Error(
2979
+ `Failed to install uv via pip: ${err instanceof Error ? err.message : String(err)}`
2980
+ );
2981
+ }
2982
+ const resolvedUvBin = await findUvBinary(pythonPath);
2983
+ if (!resolvedUvBin) {
2984
+ throw new Error("Unable to resolve uv binary after pip install");
2985
+ }
2986
+ console.log(`Installed uv at "${resolvedUvBin}"`);
2987
+ return resolvedUvBin;
2988
+ }
2989
+ function filterUnsafeUvPipArgs(args) {
2990
+ return args.filter((arg) => arg !== "--no-warn-script-location");
2991
+ }
2992
+ function getProtectedUvEnv(baseEnv = process.env) {
2993
+ return {
2994
+ ...baseEnv,
2995
+ UV_PYTHON_DOWNLOADS: UV_PYTHON_DOWNLOADS_MODE
2996
+ };
2997
+ }
2998
+
2999
+ // src/utils.ts
3000
+ var isWin2 = process.platform === "win32";
2771
3001
  var isInVirtualEnv = () => {
2772
3002
  return process.env.VIRTUAL_ENV;
2773
3003
  };
2774
3004
  function getVenvBinDir(venvPath) {
2775
- return (0, import_path.join)(venvPath, isWin ? "Scripts" : "bin");
3005
+ return (0, import_path3.join)(venvPath, isWin2 ? "Scripts" : "bin");
2776
3006
  }
2777
3007
  function useVirtualEnv(workPath, env, systemPython) {
2778
3008
  const venvDirs = [".venv", "venv"];
2779
3009
  let pythonCmd = systemPython;
2780
3010
  for (const venv of venvDirs) {
2781
- const venvRoot = (0, import_path.join)(workPath, venv);
2782
- const binDir = process.platform === "win32" ? (0, import_path.join)(venvRoot, "Scripts") : (0, import_path.join)(venvRoot, "bin");
2783
- const candidates = process.platform === "win32" ? [(0, import_path.join)(binDir, "python.exe"), (0, import_path.join)(binDir, "python")] : [(0, import_path.join)(binDir, "python3"), (0, import_path.join)(binDir, "python")];
2784
- const found = candidates.find((p) => import_fs.default.existsSync(p));
3011
+ const venvRoot = (0, import_path3.join)(workPath, venv);
3012
+ const binDir = process.platform === "win32" ? (0, import_path3.join)(venvRoot, "Scripts") : (0, import_path3.join)(venvRoot, "bin");
3013
+ const candidates = process.platform === "win32" ? [(0, import_path3.join)(binDir, "python.exe"), (0, import_path3.join)(binDir, "python")] : [(0, import_path3.join)(binDir, "python3"), (0, import_path3.join)(binDir, "python")];
3014
+ const found = candidates.find((p) => import_fs2.default.existsSync(p));
2785
3015
  if (found) {
2786
3016
  pythonCmd = found;
2787
3017
  env.VIRTUAL_ENV = venvRoot;
2788
- env.PATH = `${binDir}${import_path.delimiter}${env.PATH || ""}`;
3018
+ env.PATH = `${binDir}${import_path3.delimiter}${env.PATH || ""}`;
2789
3019
  return { pythonCmd, venvRoot };
2790
3020
  }
2791
3021
  }
2792
3022
  return { pythonCmd };
2793
3023
  }
2794
- function getProtectedUvEnv(baseEnv = process.env) {
2795
- return {
2796
- ...baseEnv,
2797
- UV_PYTHON_DOWNLOADS: UV_PYTHON_DOWNLOADS_MODE
2798
- };
2799
- }
2800
3024
  function createVenvEnv(venvPath, baseEnv = process.env) {
2801
3025
  const env = {
2802
3026
  ...getProtectedUvEnv(baseEnv),
@@ -2804,118 +3028,345 @@ function createVenvEnv(venvPath, baseEnv = process.env) {
2804
3028
  };
2805
3029
  const binDir = getVenvBinDir(venvPath);
2806
3030
  const existingPath = env.PATH || process.env.PATH || "";
2807
- env.PATH = existingPath ? `${binDir}${import_path.delimiter}${existingPath}` : binDir;
3031
+ env.PATH = existingPath ? `${binDir}${import_path3.delimiter}${existingPath}` : binDir;
2808
3032
  return env;
2809
3033
  }
2810
3034
  async function ensureVenv({
2811
3035
  pythonPath,
2812
3036
  venvPath
2813
3037
  }) {
2814
- const marker = (0, import_path.join)(venvPath, "pyvenv.cfg");
3038
+ const marker = (0, import_path3.join)(venvPath, "pyvenv.cfg");
2815
3039
  try {
2816
- await import_fs.default.promises.access(marker);
3040
+ await import_fs2.default.promises.access(marker);
2817
3041
  return;
2818
3042
  } catch {
2819
3043
  }
2820
- await import_fs.default.promises.mkdir(venvPath, { recursive: true });
2821
- console.log(`Creating virtual environment at "${venvPath}"...`);
2822
- await (0, import_execa.default)(pythonPath, ["-m", "venv", venvPath]);
2823
- }
2824
- function getVenvPythonBin(venvPath) {
2825
- return (0, import_path.join)(getVenvBinDir(venvPath), isWin ? "python.exe" : "python");
3044
+ await import_fs2.default.promises.mkdir(venvPath, { recursive: true });
3045
+ console.log(`Creating virtual environment at "${venvPath}"...`);
3046
+ await (0, import_execa2.default)(pythonPath, ["-m", "venv", venvPath]);
3047
+ }
3048
+ function getVenvPythonBin(venvPath) {
3049
+ return (0, import_path3.join)(getVenvBinDir(venvPath), isWin2 ? "python.exe" : "python");
3050
+ }
3051
+ async function runPyprojectScript(workPath, scriptNames, env, useUserVirtualEnv = true) {
3052
+ const pyprojectPath = (0, import_path3.join)(workPath, "pyproject.toml");
3053
+ if (!import_fs2.default.existsSync(pyprojectPath))
3054
+ return false;
3055
+ let pyproject = null;
3056
+ try {
3057
+ pyproject = await (0, import_build_utils2.readConfigFile)(pyprojectPath);
3058
+ } catch {
3059
+ console.error("Failed to parse pyproject.toml");
3060
+ return false;
3061
+ }
3062
+ const scripts = pyproject?.tool?.vercel?.scripts || {};
3063
+ const candidates = typeof scriptNames === "string" ? [scriptNames] : Array.from(scriptNames);
3064
+ const scriptToRun = candidates.find((name) => Boolean(scripts[name]));
3065
+ if (!scriptToRun)
3066
+ return false;
3067
+ const systemPython = process.platform === "win32" ? "python" : "python3";
3068
+ const finalEnv = { ...process.env, ...env };
3069
+ if (useUserVirtualEnv) {
3070
+ useVirtualEnv(workPath, finalEnv, systemPython);
3071
+ }
3072
+ const scriptCommand = scripts[scriptToRun];
3073
+ if (typeof scriptCommand === "string" && scriptCommand.trim()) {
3074
+ console.log(`Executing: ${scriptCommand}`);
3075
+ await (0, import_build_utils2.execCommand)(scriptCommand, {
3076
+ cwd: workPath,
3077
+ env: finalEnv
3078
+ });
3079
+ return true;
3080
+ }
3081
+ return false;
3082
+ }
3083
+ function findDir({
3084
+ file,
3085
+ entryDirectory,
3086
+ workPath,
3087
+ fsFiles
3088
+ }) {
3089
+ if (fsFiles[(0, import_path3.join)(entryDirectory, file)]) {
3090
+ return (0, import_path3.join)(workPath, entryDirectory);
3091
+ }
3092
+ if (fsFiles[file]) {
3093
+ return workPath;
3094
+ }
3095
+ return null;
3096
+ }
3097
+
3098
+ // src/version.ts
3099
+ var import_build_utils3 = require("@vercel/build-utils");
3100
+ var DEFAULT_PYTHON_VERSION = "3.12";
3101
+ var allOptions = [
3102
+ {
3103
+ version: "3.14",
3104
+ pipPath: "pip3.14",
3105
+ pythonPath: "python3.14",
3106
+ runtime: "python3.14"
3107
+ },
3108
+ {
3109
+ version: "3.13",
3110
+ pipPath: "pip3.13",
3111
+ pythonPath: "python3.13",
3112
+ runtime: "python3.13"
3113
+ },
3114
+ {
3115
+ version: "3.12",
3116
+ pipPath: "pip3.12",
3117
+ pythonPath: "python3.12",
3118
+ runtime: "python3.12"
3119
+ },
3120
+ {
3121
+ version: "3.11",
3122
+ pipPath: "pip3.11",
3123
+ pythonPath: "python3.11",
3124
+ runtime: "python3.11"
3125
+ },
3126
+ {
3127
+ version: "3.10",
3128
+ pipPath: "pip3.10",
3129
+ pythonPath: "python3.10",
3130
+ runtime: "python3.10"
3131
+ },
3132
+ {
3133
+ version: "3.9",
3134
+ pipPath: "pip3.9",
3135
+ pythonPath: "python3.9",
3136
+ runtime: "python3.9"
3137
+ },
3138
+ {
3139
+ version: "3.6",
3140
+ pipPath: "pip3.6",
3141
+ pythonPath: "python3.6",
3142
+ runtime: "python3.6",
3143
+ discontinueDate: /* @__PURE__ */ new Date("2022-07-18")
3144
+ }
3145
+ ];
3146
+ function getDevPythonVersion() {
3147
+ return {
3148
+ version: "3",
3149
+ pipPath: "pip3",
3150
+ pythonPath: "python3",
3151
+ runtime: "python3"
3152
+ };
3153
+ }
3154
+ function getDefaultPythonVersion({
3155
+ isDev
3156
+ }) {
3157
+ if (isDev) {
3158
+ return getDevPythonVersion();
3159
+ }
3160
+ const defaultOption = allOptions.find(
3161
+ (opt) => opt.version === DEFAULT_PYTHON_VERSION && isInstalled(opt)
3162
+ );
3163
+ if (defaultOption) {
3164
+ return defaultOption;
3165
+ }
3166
+ const selection = allOptions.find(isInstalled);
3167
+ if (!selection) {
3168
+ throw new import_build_utils3.NowBuildError({
3169
+ code: "PYTHON_NOT_FOUND",
3170
+ link: "https://vercel.link/python-version",
3171
+ message: `Unable to find any supported Python versions.`
3172
+ });
3173
+ }
3174
+ return selection;
3175
+ }
3176
+ function parseVersionTuple(input) {
3177
+ const cleaned = input.trim().replace(/\s+/g, "");
3178
+ const m = cleaned.match(/^(\d+)(?:\.(\d+))?/);
3179
+ if (!m)
3180
+ return null;
3181
+ const major = Number(m[1]);
3182
+ const minor = m[2] !== void 0 ? Number(m[2]) : 0;
3183
+ if (Number.isNaN(major) || Number.isNaN(minor))
3184
+ return null;
3185
+ return [major, minor];
3186
+ }
3187
+ function compareTuples(a, b) {
3188
+ if (a[0] !== b[0])
3189
+ return a[0] - b[0];
3190
+ return a[1] - b[1];
3191
+ }
3192
+ function parseSpecifier(spec) {
3193
+ const s = spec.trim();
3194
+ const m = s.match(
3195
+ /^(<=|>=|==|!=|~=|<|>)\s*([0-9]+(?:\.[0-9]+)?)(?:\.[0-9]+)?(?:\.\*)?$/
3196
+ ) || // Bare version like "3.11" or "3.11.4" -> implied ==
3197
+ s.match(/^()([0-9]+(?:\.[0-9]+)?)(?:\.[0-9]+)?(?:\.\*)?$/);
3198
+ if (!m)
3199
+ return null;
3200
+ const op = m[1] || "==";
3201
+ const vt = parseVersionTuple(m[2]);
3202
+ if (!vt)
3203
+ return null;
3204
+ return { op, ver: vt };
3205
+ }
3206
+ function satisfies(candidate, spec) {
3207
+ const cmp = compareTuples(candidate, spec.ver);
3208
+ switch (spec.op) {
3209
+ case "==":
3210
+ return cmp === 0;
3211
+ case "!=":
3212
+ return cmp !== 0;
3213
+ case "<":
3214
+ return cmp < 0;
3215
+ case "<=":
3216
+ return cmp <= 0;
3217
+ case ">":
3218
+ return cmp > 0;
3219
+ case ">=":
3220
+ return cmp >= 0;
3221
+ case "~=": {
3222
+ const lowerOk = cmp >= 0;
3223
+ const upper = [spec.ver[0], spec.ver[1] + 1];
3224
+ return lowerOk && compareTuples(candidate, upper) < 0;
3225
+ }
3226
+ default:
3227
+ return false;
3228
+ }
2826
3229
  }
2827
- async function runPyprojectScript(workPath, scriptNames, env, useUserVirtualEnv = true) {
2828
- const pyprojectPath = (0, import_path.join)(workPath, "pyproject.toml");
2829
- if (!import_fs.default.existsSync(pyprojectPath))
2830
- return false;
2831
- let pyproject = null;
2832
- try {
2833
- pyproject = await (0, import_build_utils.readConfigFile)(pyprojectPath);
2834
- } catch {
2835
- console.error("Failed to parse pyproject.toml");
2836
- return false;
3230
+ function selectFromRequiresPython(expr) {
3231
+ const raw = expr.trim();
3232
+ if (!raw)
3233
+ return void 0;
3234
+ const parts = raw.split(",").map((p) => p.trim()).filter(Boolean);
3235
+ const specifiers = [];
3236
+ for (const p of parts) {
3237
+ const sp = parseSpecifier(p);
3238
+ if (sp)
3239
+ specifiers.push(sp);
2837
3240
  }
2838
- const scripts = pyproject?.tool?.vercel?.scripts || {};
2839
- const candidates = typeof scriptNames === "string" ? [scriptNames] : Array.from(scriptNames);
2840
- const scriptToRun = candidates.find((name) => Boolean(scripts[name]));
2841
- if (!scriptToRun)
2842
- return false;
2843
- const systemPython = process.platform === "win32" ? "python" : "python3";
2844
- const finalEnv = { ...process.env, ...env };
2845
- if (useUserVirtualEnv) {
2846
- useVirtualEnv(workPath, finalEnv, systemPython);
3241
+ if (specifiers.length === 0) {
3242
+ return allOptions.find((o) => o.version === raw);
2847
3243
  }
2848
- const scriptCommand = scripts[scriptToRun];
2849
- if (typeof scriptCommand === "string" && scriptCommand.trim()) {
2850
- console.log(`Executing: ${scriptCommand}`);
2851
- await (0, import_build_utils.execCommand)(scriptCommand, {
2852
- cwd: workPath,
2853
- env: finalEnv
2854
- });
2855
- return true;
3244
+ const matches = allOptions.filter((opt) => {
3245
+ const vt = parseVersionTuple(opt.version);
3246
+ return specifiers.every((sp) => satisfies(vt, sp));
3247
+ });
3248
+ if (matches.length === 0)
3249
+ return void 0;
3250
+ const defaultMatch = matches.find(
3251
+ (opt) => opt.version === DEFAULT_PYTHON_VERSION && isInstalled(opt)
3252
+ );
3253
+ if (defaultMatch) {
3254
+ return defaultMatch;
2856
3255
  }
2857
- return false;
3256
+ const installedMatch = matches.find(isInstalled);
3257
+ return installedMatch ?? matches[0];
2858
3258
  }
2859
- async function runUvCommand(options) {
2860
- const { uvPath, args, cwd, venvPath } = options;
2861
- const pretty = `uv ${args.join(" ")}`;
2862
- (0, import_build_utils.debug)(`Running "${pretty}"...`);
2863
- if (!uvPath) {
2864
- throw new Error(`uv is required to run "${pretty}" but is not available`);
3259
+ function getSupportedPythonVersion({
3260
+ isDev,
3261
+ declaredPythonVersion
3262
+ }) {
3263
+ if (isDev) {
3264
+ return getDevPythonVersion();
2865
3265
  }
2866
- try {
2867
- await (0, import_execa.default)(uvPath, args, {
2868
- cwd,
2869
- env: createVenvEnv(venvPath)
2870
- });
2871
- return true;
2872
- } catch (err) {
2873
- const error = new Error(
2874
- `Failed to run "${pretty}": ${err instanceof Error ? err.message : String(err)}`
2875
- );
2876
- if (err && typeof err === "object") {
2877
- if ("code" in err) {
2878
- error.code = err.code;
2879
- } else if ("signal" in err) {
2880
- error.code = err.signal;
3266
+ let selection = getDefaultPythonVersion({ isDev: false });
3267
+ if (declaredPythonVersion) {
3268
+ const { version: version2, source } = declaredPythonVersion;
3269
+ let requested;
3270
+ if (source === "pyproject.toml" || source === ".python-version") {
3271
+ requested = selectFromRequiresPython(version2);
3272
+ } else {
3273
+ requested = allOptions.find((o) => o.version === version2);
3274
+ }
3275
+ if (requested) {
3276
+ if (isDiscontinued(requested)) {
3277
+ throw new import_build_utils3.NowBuildError({
3278
+ code: "BUILD_UTILS_PYTHON_VERSION_DISCONTINUED",
3279
+ link: "https://vercel.link/python-version",
3280
+ message: `Python version "${requested.version}" detected in ${source} is discontinued and must be upgraded.`
3281
+ });
3282
+ }
3283
+ if (isInstalled(requested)) {
3284
+ selection = requested;
3285
+ console.log(`Using Python ${selection.version} from ${source}`);
3286
+ } else {
3287
+ console.warn(
3288
+ `Warning: Python version "${version2}" detected in ${source} is not installed and will be ignored. https://vercel.link/python-version`
3289
+ );
3290
+ console.log(`Using python version: ${selection.version}`);
2881
3291
  }
3292
+ } else {
3293
+ console.warn(
3294
+ `Warning: Python version "${version2}" detected in ${source} is invalid and will be ignored. https://vercel.link/python-version`
3295
+ );
3296
+ console.log(`Using python version: ${selection.version}`);
2882
3297
  }
2883
- throw error;
3298
+ } else {
3299
+ console.log(
3300
+ `No Python version specified in .python-version, pyproject.toml, or Pipfile.lock. Using python version: ${selection.version}`
3301
+ );
2884
3302
  }
3303
+ if (isDiscontinued(selection)) {
3304
+ throw new import_build_utils3.NowBuildError({
3305
+ code: "BUILD_UTILS_PYTHON_VERSION_DISCONTINUED",
3306
+ link: "https://vercel.link/python-version",
3307
+ message: `Python version "${selection.version}" declared in project configuration is discontinued and must be upgraded.`
3308
+ });
3309
+ }
3310
+ if (selection.discontinueDate) {
3311
+ const d = selection.discontinueDate.toISOString().split("T")[0];
3312
+ const srcSuffix = declaredPythonVersion ? `detected in ${declaredPythonVersion.source}` : "selected by runtime";
3313
+ console.warn(
3314
+ `Error: Python version "${selection.version}" ${srcSuffix} has reached End-of-Life. Deployments created on or after ${d} will fail to build. https://vercel.link/python-version`
3315
+ );
3316
+ }
3317
+ return selection;
2885
3318
  }
2886
- function findDir({
2887
- file,
2888
- entryDirectory,
2889
- workPath,
2890
- fsFiles
2891
- }) {
2892
- if (fsFiles[(0, import_path.join)(entryDirectory, file)]) {
2893
- return (0, import_path.join)(workPath, entryDirectory);
3319
+ function isDiscontinued({ discontinueDate }) {
3320
+ const today = Date.now();
3321
+ return discontinueDate !== void 0 && discontinueDate.getTime() <= today;
3322
+ }
3323
+ var installedPythonsCache = null;
3324
+ function getInstalledPythons() {
3325
+ if (installedPythonsCache !== null) {
3326
+ return installedPythonsCache;
2894
3327
  }
2895
- if (fsFiles[file]) {
2896
- return workPath;
3328
+ const uvPath = findUvInPath();
3329
+ if (!uvPath) {
3330
+ throw new import_build_utils3.NowBuildError({
3331
+ code: "UV_ERROR",
3332
+ link: "https://vercel.link/python-version",
3333
+ message: "uv is required but was not found in PATH."
3334
+ });
3335
+ }
3336
+ const uv = new UvRunner(uvPath);
3337
+ installedPythonsCache = uv.listInstalledPythons();
3338
+ return installedPythonsCache;
3339
+ }
3340
+ function isInstalled({ version: version2 }) {
3341
+ try {
3342
+ const installed = getInstalledPythons();
3343
+ return installed.has(version2);
3344
+ } catch (err) {
3345
+ throw new import_build_utils3.NowBuildError({
3346
+ code: "UV_ERROR",
3347
+ link: "https://vercel.link/python-version",
3348
+ message: err instanceof Error ? err.message : String(err)
3349
+ });
2897
3350
  }
2898
- return null;
2899
3351
  }
2900
3352
 
2901
3353
  // src/install.ts
2902
- var isWin2 = process.platform === "win32";
2903
- var uvExec = isWin2 ? "uv.exe" : "uv";
3354
+ var isWin3 = process.platform === "win32";
2904
3355
  var makeDependencyCheckCode = (dependency) => `
2905
3356
  from importlib import util
2906
3357
  dep = '${dependency}'.replace('-', '_')
2907
3358
  spec = util.find_spec(dep)
2908
3359
  print(spec.origin)
2909
3360
  `;
2910
- async function isInstalled(pythonPath, dependency, cwd) {
3361
+ async function isInstalled2(pythonPath, dependency, cwd) {
2911
3362
  try {
2912
- const { stdout } = await (0, import_execa2.default)(
3363
+ const { stdout } = await (0, import_execa3.default)(
2913
3364
  pythonPath,
2914
3365
  ["-c", makeDependencyCheckCode(dependency)],
2915
3366
  {
2916
3367
  stdio: "pipe",
2917
3368
  cwd,
2918
- env: { ...process.env, PYTHONPATH: (0, import_path2.join)(cwd, resolveVendorDir()) }
3369
+ env: { ...process.env, PYTHONPATH: (0, import_path4.join)(cwd, resolveVendorDir()) }
2919
3370
  }
2920
3371
  );
2921
3372
  return stdout.startsWith(cwd);
@@ -2932,13 +3383,13 @@ pkg_resources.require(dependencies)
2932
3383
  `;
2933
3384
  async function areRequirementsInstalled(pythonPath, requirementsPath, cwd) {
2934
3385
  try {
2935
- await (0, import_execa2.default)(
3386
+ await (0, import_execa3.default)(
2936
3387
  pythonPath,
2937
3388
  ["-c", makeRequirementsCheckCode(requirementsPath)],
2938
3389
  {
2939
3390
  stdio: "pipe",
2940
3391
  cwd,
2941
- env: { ...process.env, PYTHONPATH: (0, import_path2.join)(cwd, resolveVendorDir()) }
3392
+ env: { ...process.env, PYTHONPATH: (0, import_path4.join)(cwd, resolveVendorDir()) }
2942
3393
  }
2943
3394
  );
2944
3395
  return true;
@@ -2946,24 +3397,6 @@ async function areRequirementsInstalled(pythonPath, requirementsPath, cwd) {
2946
3397
  return false;
2947
3398
  }
2948
3399
  }
2949
- async function runUvSync({
2950
- uvPath,
2951
- venvPath,
2952
- projectDir,
2953
- locked
2954
- }) {
2955
- const args = ["sync", "--active", "--no-dev", "--link-mode", "copy"];
2956
- if (locked) {
2957
- args.push("--locked");
2958
- }
2959
- args.push("--no-editable");
2960
- await runUvCommand({
2961
- uvPath,
2962
- args,
2963
- cwd: projectDir,
2964
- venvPath
2965
- });
2966
- }
2967
3400
  async function getSitePackagesDirs(pythonBin) {
2968
3401
  const code = `
2969
3402
  import json
@@ -2975,14 +3408,14 @@ for key in ("purelib", "platlib"):
2975
3408
  paths.append(candidate)
2976
3409
  print(json.dumps(paths))
2977
3410
  `.trim();
2978
- const { stdout } = await (0, import_execa2.default)(pythonBin, ["-c", code]);
3411
+ const { stdout } = await (0, import_execa3.default)(pythonBin, ["-c", code]);
2979
3412
  try {
2980
3413
  const parsed = JSON.parse(stdout);
2981
3414
  if (Array.isArray(parsed)) {
2982
3415
  return parsed.filter((p) => typeof p === "string");
2983
3416
  }
2984
3417
  } catch (err) {
2985
- (0, import_build_utils2.debug)("Failed to parse site-packages output", err);
3418
+ (0, import_build_utils4.debug)("Failed to parse site-packages output", err);
2986
3419
  }
2987
3420
  return [];
2988
3421
  }
@@ -3033,26 +3466,26 @@ async function detectInstallSource({
3033
3466
  let manifestType = null;
3034
3467
  if (uvLockDir && pyprojectDir) {
3035
3468
  manifestType = "uv.lock";
3036
- manifestPath = (0, import_path2.join)(uvLockDir, "uv.lock");
3469
+ manifestPath = (0, import_path4.join)(uvLockDir, "uv.lock");
3037
3470
  } else if (pyprojectDir) {
3038
3471
  manifestType = "pyproject.toml";
3039
- manifestPath = (0, import_path2.join)(pyprojectDir, "pyproject.toml");
3472
+ manifestPath = (0, import_path4.join)(pyprojectDir, "pyproject.toml");
3040
3473
  } else if (pipfileLockDir) {
3041
3474
  manifestType = "Pipfile.lock";
3042
- manifestPath = (0, import_path2.join)(pipfileLockDir, "Pipfile.lock");
3475
+ manifestPath = (0, import_path4.join)(pipfileLockDir, "Pipfile.lock");
3043
3476
  } else if (pipfileDir) {
3044
3477
  manifestType = "Pipfile";
3045
- manifestPath = (0, import_path2.join)(pipfileDir, "Pipfile");
3478
+ manifestPath = (0, import_path4.join)(pipfileDir, "Pipfile");
3046
3479
  } else if (requirementsDir) {
3047
3480
  manifestType = "requirements.txt";
3048
- manifestPath = (0, import_path2.join)(requirementsDir, "requirements.txt");
3481
+ manifestPath = (0, import_path4.join)(requirementsDir, "requirements.txt");
3049
3482
  }
3050
3483
  let manifestContent;
3051
3484
  if (manifestPath) {
3052
3485
  try {
3053
- manifestContent = await import_fs2.default.promises.readFile(manifestPath, "utf8");
3486
+ manifestContent = await import_fs3.default.promises.readFile(manifestPath, "utf8");
3054
3487
  } catch (err) {
3055
- (0, import_build_utils2.debug)("Failed to read install manifest contents", err);
3488
+ (0, import_build_utils4.debug)("Failed to read install manifest contents", err);
3056
3489
  }
3057
3490
  }
3058
3491
  return { manifestPath, manifestType, manifestContent };
@@ -3062,7 +3495,7 @@ async function createPyprojectToml({
3062
3495
  pyprojectPath,
3063
3496
  dependencies
3064
3497
  }) {
3065
- const requiresPython = ">=3.12";
3498
+ const requiresPython = `~=${DEFAULT_PYTHON_VERSION}`;
3066
3499
  const depsToml = dependencies.length > 0 ? [
3067
3500
  "dependencies = [",
3068
3501
  ...dependencies.map((dep) => ` "${dep}",`),
@@ -3079,47 +3512,7 @@ async function createPyprojectToml({
3079
3512
  depsToml,
3080
3513
  ""
3081
3514
  ].join("\n");
3082
- await import_fs2.default.promises.writeFile(pyprojectPath, content);
3083
- }
3084
- async function uvLock({
3085
- projectDir,
3086
- uvPath
3087
- }) {
3088
- const args = ["lock"];
3089
- const pretty = `${uvPath} ${args.join(" ")}`;
3090
- (0, import_build_utils2.debug)(`Running "${pretty}" in ${projectDir}...`);
3091
- try {
3092
- await (0, import_execa2.default)(uvPath, args, { cwd: projectDir, env: getProtectedUvEnv() });
3093
- } catch (err) {
3094
- throw new Error(
3095
- `Failed to run "${pretty}": ${err instanceof Error ? err.message : String(err)}`
3096
- );
3097
- }
3098
- }
3099
- async function uvAddDependencies({
3100
- projectDir,
3101
- uvPath,
3102
- venvPath,
3103
- dependencies
3104
- }) {
3105
- const toAdd = dependencies.filter(Boolean);
3106
- if (!toAdd.length)
3107
- return;
3108
- const args = ["add", "--active", ...toAdd];
3109
- const pretty = `${uvPath} ${args.join(" ")}`;
3110
- (0, import_build_utils2.debug)(`Running "${pretty}" in ${projectDir}...`);
3111
- await runUvCommand({ uvPath, args, cwd: projectDir, venvPath });
3112
- }
3113
- async function uvAddFromFile({
3114
- projectDir,
3115
- uvPath,
3116
- venvPath,
3117
- requirementsPath
3118
- }) {
3119
- const args = ["add", "--active", "-r", requirementsPath];
3120
- const pretty = `${uvPath} ${args.join(" ")}`;
3121
- (0, import_build_utils2.debug)(`Running "${pretty}" in ${projectDir}...`);
3122
- await runUvCommand({ uvPath, args, cwd: projectDir, venvPath });
3515
+ await import_fs3.default.promises.writeFile(pyprojectPath, content);
3123
3516
  }
3124
3517
  function getDependencyName(spec) {
3125
3518
  const match = spec.match(/^[A-Za-z0-9_.-]+/);
@@ -3131,10 +3524,10 @@ async function filterMissingRuntimeDependencies({
3131
3524
  }) {
3132
3525
  let declared = [];
3133
3526
  try {
3134
- const config = await (0, import_build_utils2.readConfigFile)(pyprojectPath);
3527
+ const config = await (0, import_build_utils4.readConfigFile)(pyprojectPath);
3135
3528
  declared = config?.project?.dependencies || [];
3136
3529
  } catch (err) {
3137
- (0, import_build_utils2.debug)("Failed to parse pyproject.toml when filtering runtime deps", err);
3530
+ (0, import_build_utils4.debug)("Failed to parse pyproject.toml when filtering runtime deps", err);
3138
3531
  }
3139
3532
  const declaredNames = new Set(declared.map(getDependencyName));
3140
3533
  return runtimeDependencies.filter((spec) => {
@@ -3143,12 +3536,12 @@ async function filterMissingRuntimeDependencies({
3143
3536
  });
3144
3537
  }
3145
3538
  function findUvLockUpwards(startDir, repoRootPath) {
3146
- const start = (0, import_path2.resolve)(startDir);
3147
- const base = repoRootPath ? (0, import_path2.resolve)(repoRootPath) : void 0;
3148
- for (const dir of (0, import_build_utils2.traverseUpDirectories)({ start, base })) {
3149
- const lockPath = (0, import_path2.join)(dir, "uv.lock");
3150
- const pyprojectPath = (0, import_path2.join)(dir, "pyproject.toml");
3151
- if (import_fs2.default.existsSync(lockPath) && import_fs2.default.existsSync(pyprojectPath)) {
3539
+ const start = (0, import_path4.resolve)(startDir);
3540
+ const base = repoRootPath ? (0, import_path4.resolve)(repoRootPath) : void 0;
3541
+ for (const dir of (0, import_build_utils4.traverseUpDirectories)({ start, base })) {
3542
+ const lockPath = (0, import_path4.join)(dir, "uv.lock");
3543
+ const pyprojectPath = (0, import_path4.join)(dir, "pyproject.toml");
3544
+ if (import_fs3.default.existsSync(lockPath) && import_fs3.default.existsSync(pyprojectPath)) {
3152
3545
  return lockPath;
3153
3546
  }
3154
3547
  }
@@ -3161,11 +3554,12 @@ async function ensureUvProject({
3161
3554
  repoRootPath,
3162
3555
  pythonPath,
3163
3556
  pipPath,
3164
- uvPath,
3557
+ uv,
3165
3558
  venvPath,
3166
3559
  meta,
3167
3560
  runtimeDependencies
3168
3561
  }) {
3562
+ const uvPath = uv.getPath();
3169
3563
  const installInfo = await detectInstallSource({
3170
3564
  workPath,
3171
3565
  entryDirectory,
@@ -3179,9 +3573,9 @@ async function ensureUvProject({
3179
3573
  if (!manifestPath) {
3180
3574
  throw new Error("Expected uv.lock path to be resolved, but it was null");
3181
3575
  }
3182
- projectDir = (0, import_path2.dirname)(manifestPath);
3183
- pyprojectPath = (0, import_path2.join)(projectDir, "pyproject.toml");
3184
- if (!import_fs2.default.existsSync(pyprojectPath)) {
3576
+ projectDir = (0, import_path4.dirname)(manifestPath);
3577
+ pyprojectPath = (0, import_path4.join)(projectDir, "pyproject.toml");
3578
+ if (!import_fs3.default.existsSync(pyprojectPath)) {
3185
3579
  throw new Error(
3186
3580
  `Expected "pyproject.toml" next to "uv.lock" in "${projectDir}"`
3187
3581
  );
@@ -3194,14 +3588,14 @@ async function ensureUvProject({
3194
3588
  "Expected pyproject.toml path to be resolved, but it was null"
3195
3589
  );
3196
3590
  }
3197
- projectDir = (0, import_path2.dirname)(manifestPath);
3591
+ projectDir = (0, import_path4.dirname)(manifestPath);
3198
3592
  pyprojectPath = manifestPath;
3199
3593
  console.log("Installing required dependencies from pyproject.toml...");
3200
3594
  const workspaceLock = findUvLockUpwards(projectDir, repoRootPath);
3201
3595
  if (workspaceLock) {
3202
3596
  lockPath = workspaceLock;
3203
3597
  } else {
3204
- await uvLock({ projectDir, uvPath });
3598
+ await uv.lock(projectDir);
3205
3599
  }
3206
3600
  } else if (manifestType === "Pipfile.lock" || manifestType === "Pipfile") {
3207
3601
  if (!manifestPath) {
@@ -3209,7 +3603,7 @@ async function ensureUvProject({
3209
3603
  "Expected Pipfile/Pipfile.lock path to be resolved, but it was null"
3210
3604
  );
3211
3605
  }
3212
- projectDir = (0, import_path2.dirname)(manifestPath);
3606
+ projectDir = (0, import_path4.dirname)(manifestPath);
3213
3607
  console.log(`Installing required dependencies from ${manifestType}...`);
3214
3608
  const exportedReq = await exportRequirementsFromPipfile({
3215
3609
  pythonPath,
@@ -3218,18 +3612,17 @@ async function ensureUvProject({
3218
3612
  projectDir,
3219
3613
  meta
3220
3614
  });
3221
- pyprojectPath = (0, import_path2.join)(projectDir, "pyproject.toml");
3222
- if (!import_fs2.default.existsSync(pyprojectPath)) {
3615
+ pyprojectPath = (0, import_path4.join)(projectDir, "pyproject.toml");
3616
+ if (!import_fs3.default.existsSync(pyprojectPath)) {
3223
3617
  await createPyprojectToml({
3224
3618
  projectName: "app",
3225
3619
  pyprojectPath,
3226
3620
  dependencies: []
3227
3621
  });
3228
3622
  }
3229
- await uvAddFromFile({
3230
- projectDir,
3231
- uvPath,
3623
+ await uv.addFromFile({
3232
3624
  venvPath,
3625
+ projectDir,
3233
3626
  requirementsPath: exportedReq
3234
3627
  });
3235
3628
  } else if (manifestType === "requirements.txt") {
@@ -3238,27 +3631,26 @@ async function ensureUvProject({
3238
3631
  "Expected requirements.txt path to be resolved, but it was null"
3239
3632
  );
3240
3633
  }
3241
- projectDir = (0, import_path2.dirname)(manifestPath);
3242
- pyprojectPath = (0, import_path2.join)(projectDir, "pyproject.toml");
3634
+ projectDir = (0, import_path4.dirname)(manifestPath);
3635
+ pyprojectPath = (0, import_path4.join)(projectDir, "pyproject.toml");
3243
3636
  console.log(
3244
3637
  "Installing required dependencies from requirements.txt with uv..."
3245
3638
  );
3246
- if (!import_fs2.default.existsSync(pyprojectPath)) {
3639
+ if (!import_fs3.default.existsSync(pyprojectPath)) {
3247
3640
  await createPyprojectToml({
3248
3641
  projectName: "app",
3249
3642
  pyprojectPath,
3250
3643
  dependencies: []
3251
3644
  });
3252
3645
  }
3253
- await uvAddFromFile({
3254
- projectDir,
3255
- uvPath,
3646
+ await uv.addFromFile({
3256
3647
  venvPath,
3648
+ projectDir,
3257
3649
  requirementsPath: manifestPath
3258
3650
  });
3259
3651
  } else {
3260
3652
  projectDir = workPath;
3261
- pyprojectPath = (0, import_path2.join)(projectDir, "pyproject.toml");
3653
+ pyprojectPath = (0, import_path4.join)(projectDir, "pyproject.toml");
3262
3654
  console.log(
3263
3655
  "No Python manifest found; creating an empty pyproject.toml and uv.lock..."
3264
3656
  );
@@ -3267,7 +3659,7 @@ async function ensureUvProject({
3267
3659
  pyprojectPath,
3268
3660
  dependencies: []
3269
3661
  });
3270
- await uvLock({ projectDir, uvPath });
3662
+ await uv.lock(projectDir);
3271
3663
  }
3272
3664
  if (runtimeDependencies.length) {
3273
3665
  const missingRuntimeDeps = await filterMissingRuntimeDependencies({
@@ -3275,44 +3667,18 @@ async function ensureUvProject({
3275
3667
  runtimeDependencies
3276
3668
  });
3277
3669
  if (missingRuntimeDeps.length) {
3278
- await uvAddDependencies({
3279
- projectDir,
3280
- uvPath,
3670
+ await uv.addDependencies({
3281
3671
  venvPath,
3672
+ projectDir,
3282
3673
  dependencies: missingRuntimeDeps
3283
3674
  });
3284
3675
  }
3285
3676
  }
3286
- const resolvedLockPath = lockPath && import_fs2.default.existsSync(lockPath) ? lockPath : findUvLockUpwards(projectDir, repoRootPath) || (0, import_path2.join)(projectDir, "uv.lock");
3677
+ const resolvedLockPath = lockPath && import_fs3.default.existsSync(lockPath) ? lockPath : findUvLockUpwards(projectDir, repoRootPath) || (0, import_path4.join)(projectDir, "uv.lock");
3287
3678
  return { projectDir, pyprojectPath, lockPath: resolvedLockPath };
3288
3679
  }
3289
- async function getGlobalScriptsDir(pythonPath) {
3290
- const code = `import sysconfig; print(sysconfig.get_path('scripts'))`;
3291
- try {
3292
- const { stdout } = await (0, import_execa2.default)(pythonPath, ["-c", code]);
3293
- const out = stdout.trim();
3294
- return out || null;
3295
- } catch (err) {
3296
- (0, import_build_utils2.debug)("Failed to resolve Python global scripts directory", err);
3297
- return null;
3298
- }
3299
- }
3300
- async function getUserScriptsDir(pythonPath) {
3301
- const code = `import sys, sysconfig; print(sysconfig.get_path('scripts', scheme=('nt_user' if sys.platform == 'win32' else 'posix_user')))`.replace(
3302
- /\n/g,
3303
- " "
3304
- );
3305
- try {
3306
- const { stdout } = await (0, import_execa2.default)(pythonPath, ["-c", code]);
3307
- const out = stdout.trim();
3308
- return out || null;
3309
- } catch (err) {
3310
- (0, import_build_utils2.debug)("Failed to resolve Python user scripts directory", err);
3311
- return null;
3312
- }
3313
- }
3314
3680
  async function pipInstall(pipPath, uvPath, workPath, args, targetDir) {
3315
- const target = targetDir ? (0, import_path2.join)(targetDir, resolveVendorDir()) : resolveVendorDir();
3681
+ const target = targetDir ? (0, import_path4.join)(targetDir, resolveVendorDir()) : resolveVendorDir();
3316
3682
  process.env.PIP_USER = "0";
3317
3683
  if (uvPath) {
3318
3684
  const uvArgs = [
@@ -3325,111 +3691,38 @@ async function pipInstall(pipPath, uvPath, workPath, args, targetDir) {
3325
3691
  ...filterUnsafeUvPipArgs(args)
3326
3692
  ];
3327
3693
  const prettyUv = `${uvPath} ${uvArgs.join(" ")}`;
3328
- (0, import_build_utils2.debug)(`Running "${prettyUv}"...`);
3694
+ (0, import_build_utils4.debug)(`Running "${prettyUv}"...`);
3329
3695
  try {
3330
- await (0, import_execa2.default)(uvPath, uvArgs, {
3696
+ await (0, import_execa3.default)(uvPath, uvArgs, {
3331
3697
  cwd: workPath,
3332
3698
  env: getProtectedUvEnv()
3333
3699
  });
3334
3700
  return;
3335
3701
  } catch (err) {
3336
3702
  console.log(`Failed to run "${prettyUv}", falling back to pip`);
3337
- (0, import_build_utils2.debug)(`error: ${err}`);
3703
+ (0, import_build_utils4.debug)(`error: ${err}`);
3338
3704
  }
3339
3705
  }
3340
3706
  const cmdArgs = [
3341
3707
  "install",
3342
3708
  "--disable-pip-version-check",
3343
3709
  "--no-compile",
3344
- "--no-cache-dir",
3345
- "--target",
3346
- target,
3347
- ...args
3348
- ];
3349
- const pretty = `${pipPath} ${cmdArgs.join(" ")}`;
3350
- (0, import_build_utils2.debug)(`Running "${pretty}"...`);
3351
- try {
3352
- await (0, import_execa2.default)(pipPath, cmdArgs, {
3353
- cwd: workPath
3354
- });
3355
- } catch (err) {
3356
- console.log(`Failed to run "${pretty}"`);
3357
- (0, import_build_utils2.debug)(`error: ${err}`);
3358
- throw err;
3359
- }
3360
- }
3361
- async function maybeFindUvBin(pythonPath) {
3362
- const found = import_which.default.sync("uv", { nothrow: true });
3363
- if (found)
3364
- return found;
3365
- try {
3366
- const globalScriptsDir = await getGlobalScriptsDir(pythonPath);
3367
- if (globalScriptsDir) {
3368
- const uvPath = (0, import_path2.join)(globalScriptsDir, uvExec);
3369
- if (import_fs2.default.existsSync(uvPath))
3370
- return uvPath;
3371
- }
3372
- } catch (err) {
3373
- (0, import_build_utils2.debug)("Failed to resolve Python global scripts directory", err);
3374
- }
3375
- try {
3376
- const userScriptsDir = await getUserScriptsDir(pythonPath);
3377
- if (userScriptsDir) {
3378
- const uvPath = (0, import_path2.join)(userScriptsDir, uvExec);
3379
- if (import_fs2.default.existsSync(uvPath))
3380
- return uvPath;
3381
- }
3382
- } catch (err) {
3383
- (0, import_build_utils2.debug)("Failed to resolve Python user scripts directory", err);
3384
- }
3385
- try {
3386
- const candidates = [];
3387
- if (!isWin2) {
3388
- candidates.push((0, import_path2.join)(import_os.default.homedir(), ".local", "bin", "uv"));
3389
- candidates.push("/usr/local/bin/uv");
3390
- candidates.push("/opt/homebrew/bin/uv");
3391
- } else {
3392
- candidates.push("C:\\Users\\Public\\uv\\uv.exe");
3393
- }
3394
- for (const p of candidates) {
3395
- if (import_fs2.default.existsSync(p))
3396
- return p;
3397
- }
3398
- } catch (err) {
3399
- (0, import_build_utils2.debug)("Failed to resolve uv fallback paths", err);
3400
- }
3401
- return null;
3402
- }
3403
- async function getUvBinaryOrInstall(pythonPath) {
3404
- const uvBin = await maybeFindUvBin(pythonPath);
3405
- if (uvBin)
3406
- return uvBin;
3407
- try {
3408
- console.log("Installing uv...");
3409
- await (0, import_execa2.default)(
3410
- pythonPath,
3411
- [
3412
- "-m",
3413
- "pip",
3414
- "install",
3415
- "--disable-pip-version-check",
3416
- "--no-cache-dir",
3417
- "--user",
3418
- "uv==0.8.18"
3419
- ],
3420
- { env: { ...process.env, PIP_USER: "1" } }
3421
- );
3710
+ "--no-cache-dir",
3711
+ "--target",
3712
+ target,
3713
+ ...args
3714
+ ];
3715
+ const pretty = `${pipPath} ${cmdArgs.join(" ")}`;
3716
+ (0, import_build_utils4.debug)(`Running "${pretty}"...`);
3717
+ try {
3718
+ await (0, import_execa3.default)(pipPath, cmdArgs, {
3719
+ cwd: workPath
3720
+ });
3422
3721
  } catch (err) {
3423
- throw new Error(
3424
- `Failed to install uv via pip: ${err instanceof Error ? err.message : String(err)}`
3425
- );
3426
- }
3427
- const resolvedUvBin = await maybeFindUvBin(pythonPath);
3428
- if (!resolvedUvBin) {
3429
- throw new Error("Unable to resolve uv binary after pip install");
3722
+ console.log(`Failed to run "${pretty}"`);
3723
+ (0, import_build_utils4.debug)(`error: ${err}`);
3724
+ throw err;
3430
3725
  }
3431
- console.log(`Installed uv at "${resolvedUvBin}"`);
3432
- return resolvedUvBin;
3433
3726
  }
3434
3727
  async function installRequirement({
3435
3728
  pythonPath,
@@ -3443,8 +3736,8 @@ async function installRequirement({
3443
3736
  args = []
3444
3737
  }) {
3445
3738
  const actualTargetDir = targetDir || workPath;
3446
- if (meta.isDev && await isInstalled(pythonPath, dependency, actualTargetDir)) {
3447
- (0, import_build_utils2.debug)(
3739
+ if (meta.isDev && await isInstalled2(pythonPath, dependency, actualTargetDir)) {
3740
+ (0, import_build_utils4.debug)(
3448
3741
  `Skipping ${dependency} dependency installation, already installed in ${actualTargetDir}`
3449
3742
  );
3450
3743
  return;
@@ -3464,7 +3757,7 @@ async function installRequirementsFile({
3464
3757
  }) {
3465
3758
  const actualTargetDir = targetDir || workPath;
3466
3759
  if (meta.isDev && await areRequirementsInstalled(pythonPath, filePath, actualTargetDir)) {
3467
- (0, import_build_utils2.debug)(`Skipping requirements file installation, already installed`);
3760
+ (0, import_build_utils4.debug)(`Skipping requirements file installation, already installed`);
3468
3761
  return;
3469
3762
  }
3470
3763
  await pipInstall(
@@ -3475,9 +3768,6 @@ async function installRequirementsFile({
3475
3768
  targetDir
3476
3769
  );
3477
3770
  }
3478
- function filterUnsafeUvPipArgs(args) {
3479
- return args.filter((arg) => arg !== "--no-warn-script-location");
3480
- }
3481
3771
  async function exportRequirementsFromPipfile({
3482
3772
  pythonPath,
3483
3773
  pipPath,
@@ -3485,8 +3775,8 @@ async function exportRequirementsFromPipfile({
3485
3775
  projectDir,
3486
3776
  meta
3487
3777
  }) {
3488
- const tempDir = await import_fs2.default.promises.mkdtemp(
3489
- (0, import_path2.join)(import_os.default.tmpdir(), "vercel-pipenv-")
3778
+ const tempDir = await import_fs3.default.promises.mkdtemp(
3779
+ (0, import_path4.join)(import_os2.default.tmpdir(), "vercel-pipenv-")
3490
3780
  );
3491
3781
  await installRequirement({
3492
3782
  pythonPath,
@@ -3498,12 +3788,12 @@ async function exportRequirementsFromPipfile({
3498
3788
  args: ["--no-warn-script-location"],
3499
3789
  uvPath
3500
3790
  });
3501
- const tempVendorDir = (0, import_path2.join)(tempDir, resolveVendorDir());
3502
- const convertCmd = isWin2 ? (0, import_path2.join)(tempVendorDir, "Scripts", "pipfile2req.exe") : (0, import_path2.join)(tempVendorDir, "bin", "pipfile2req");
3503
- (0, import_build_utils2.debug)(`Running "${convertCmd}" in ${projectDir}...`);
3791
+ const tempVendorDir = (0, import_path4.join)(tempDir, resolveVendorDir());
3792
+ const convertCmd = isWin3 ? (0, import_path4.join)(tempVendorDir, "Scripts", "pipfile2req.exe") : (0, import_path4.join)(tempVendorDir, "bin", "pipfile2req");
3793
+ (0, import_build_utils4.debug)(`Running "${convertCmd}" in ${projectDir}...`);
3504
3794
  let stdout;
3505
3795
  try {
3506
- const { stdout: out } = await (0, import_execa2.default)(convertCmd, [], {
3796
+ const { stdout: out } = await (0, import_execa3.default)(convertCmd, [], {
3507
3797
  cwd: projectDir,
3508
3798
  env: { ...process.env, PYTHONPATH: tempVendorDir }
3509
3799
  });
@@ -3513,9 +3803,9 @@ async function exportRequirementsFromPipfile({
3513
3803
  `Failed to run "${convertCmd}": ${err instanceof Error ? err.message : String(err)}`
3514
3804
  );
3515
3805
  }
3516
- const outPath = (0, import_path2.join)(tempDir, "requirements.pipenv.txt");
3517
- await import_fs2.default.promises.writeFile(outPath, stdout);
3518
- (0, import_build_utils2.debug)(`Exported pipfile requirements to ${outPath}`);
3806
+ const outPath = (0, import_path4.join)(tempDir, "requirements.pipenv.txt");
3807
+ await import_fs3.default.promises.writeFile(outPath, stdout);
3808
+ (0, import_build_utils4.debug)(`Exported pipfile requirements to ${outPath}`);
3519
3809
  return outPath;
3520
3810
  }
3521
3811
  async function mirrorSitePackagesIntoVendor({
@@ -3526,19 +3816,19 @@ async function mirrorSitePackagesIntoVendor({
3526
3816
  try {
3527
3817
  const sitePackageDirs = await getVenvSitePackagesDirs(venvPath);
3528
3818
  for (const dir of sitePackageDirs) {
3529
- if (!import_fs2.default.existsSync(dir))
3819
+ if (!import_fs3.default.existsSync(dir))
3530
3820
  continue;
3531
- const dirFiles = await (0, import_build_utils2.glob)("**", dir);
3821
+ const dirFiles = await (0, import_build_utils4.glob)("**", dir);
3532
3822
  for (const relativePath of Object.keys(dirFiles)) {
3533
3823
  if (relativePath.endsWith(".pyc") || relativePath.includes("__pycache__")) {
3534
3824
  continue;
3535
3825
  }
3536
- const srcFsPath = (0, import_path2.join)(dir, relativePath);
3537
- const bundlePath = (0, import_path2.join)(vendorDirName, relativePath).replace(
3826
+ const srcFsPath = (0, import_path4.join)(dir, relativePath);
3827
+ const bundlePath = (0, import_path4.join)(vendorDirName, relativePath).replace(
3538
3828
  /\\/g,
3539
3829
  "/"
3540
3830
  );
3541
- vendorFiles[bundlePath] = new import_build_utils2.FileFsRef({ fsPath: srcFsPath });
3831
+ vendorFiles[bundlePath] = new import_build_utils4.FileFsRef({ fsPath: srcFsPath });
3542
3832
  }
3543
3833
  }
3544
3834
  } catch (err) {
@@ -3549,244 +3839,18 @@ async function mirrorSitePackagesIntoVendor({
3549
3839
  }
3550
3840
 
3551
3841
  // src/index.ts
3552
- var import_build_utils8 = require("@vercel/build-utils");
3553
-
3554
- // src/version.ts
3555
- var import_build_utils3 = require("@vercel/build-utils");
3556
- var import_which2 = __toESM(require_lib());
3557
- var DEFAULT_PYTHON_VERSION = "3.12";
3558
- var allOptions = [
3559
- {
3560
- version: "3.14",
3561
- pipPath: "pip3.14",
3562
- pythonPath: "python3.14",
3563
- runtime: "python3.14"
3564
- },
3565
- {
3566
- version: "3.13",
3567
- pipPath: "pip3.13",
3568
- pythonPath: "python3.13",
3569
- runtime: "python3.13"
3570
- },
3571
- {
3572
- version: "3.12",
3573
- pipPath: "pip3.12",
3574
- pythonPath: "python3.12",
3575
- runtime: "python3.12"
3576
- },
3577
- {
3578
- version: "3.11",
3579
- pipPath: "pip3.11",
3580
- pythonPath: "python3.11",
3581
- runtime: "python3.11"
3582
- },
3583
- {
3584
- version: "3.10",
3585
- pipPath: "pip3.10",
3586
- pythonPath: "python3.10",
3587
- runtime: "python3.10"
3588
- },
3589
- {
3590
- version: "3.9",
3591
- pipPath: "pip3.9",
3592
- pythonPath: "python3.9",
3593
- runtime: "python3.9"
3594
- },
3595
- {
3596
- version: "3.6",
3597
- pipPath: "pip3.6",
3598
- pythonPath: "python3.6",
3599
- runtime: "python3.6",
3600
- discontinueDate: /* @__PURE__ */ new Date("2022-07-18")
3601
- }
3602
- ];
3603
- function getDevPythonVersion() {
3604
- return {
3605
- version: "3",
3606
- pipPath: "pip3",
3607
- pythonPath: "python3",
3608
- runtime: "python3"
3609
- };
3610
- }
3611
- function getLatestPythonVersion({
3612
- isDev
3613
- }) {
3614
- if (isDev) {
3615
- return getDevPythonVersion();
3616
- }
3617
- const defaultOption = allOptions.find(
3618
- (opt) => opt.version === DEFAULT_PYTHON_VERSION
3619
- );
3620
- if (defaultOption && isInstalled2(defaultOption)) {
3621
- return defaultOption;
3622
- }
3623
- const selection = allOptions.find(isInstalled2);
3624
- if (!selection) {
3625
- throw new import_build_utils3.NowBuildError({
3626
- code: "PYTHON_NOT_FOUND",
3627
- link: "https://vercel.link/python-version",
3628
- message: `Unable to find any supported Python versions.`
3629
- });
3630
- }
3631
- return selection;
3632
- }
3633
- function parseVersionTuple(input) {
3634
- const cleaned = input.trim().replace(/\s+/g, "");
3635
- const m = cleaned.match(/^(\d+)(?:\.(\d+))?/);
3636
- if (!m)
3637
- return null;
3638
- const major = Number(m[1]);
3639
- const minor = m[2] !== void 0 ? Number(m[2]) : 0;
3640
- if (Number.isNaN(major) || Number.isNaN(minor))
3641
- return null;
3642
- return [major, minor];
3643
- }
3644
- function compareTuples(a, b) {
3645
- if (a[0] !== b[0])
3646
- return a[0] - b[0];
3647
- return a[1] - b[1];
3648
- }
3649
- function parseSpecifier(spec) {
3650
- const s = spec.trim();
3651
- const m = s.match(/^(<=|>=|==|!=|~=|<|>)\s*([0-9]+(?:\.[0-9]+)?)(?:\.\*)?$/) || // Bare version like "3.11" -> implied ==
3652
- s.match(/^()([0-9]+(?:\.[0-9]+)?)(?:\.\*)?$/);
3653
- if (!m)
3654
- return null;
3655
- const op = m[1] || "==";
3656
- const vt = parseVersionTuple(m[2]);
3657
- if (!vt)
3658
- return null;
3659
- return { op, ver: vt };
3660
- }
3661
- function satisfies(candidate, spec) {
3662
- const cmp = compareTuples(candidate, spec.ver);
3663
- switch (spec.op) {
3664
- case "==":
3665
- return cmp === 0;
3666
- case "!=":
3667
- return cmp !== 0;
3668
- case "<":
3669
- return cmp < 0;
3670
- case "<=":
3671
- return cmp <= 0;
3672
- case ">":
3673
- return cmp > 0;
3674
- case ">=":
3675
- return cmp >= 0;
3676
- case "~=": {
3677
- const lowerOk = cmp >= 0;
3678
- const upper = [spec.ver[0], spec.ver[1] + 1];
3679
- return lowerOk && compareTuples(candidate, upper) < 0;
3680
- }
3681
- default:
3682
- return false;
3683
- }
3684
- }
3685
- function selectFromRequiresPython(expr) {
3686
- const raw = expr.trim();
3687
- if (!raw)
3688
- return void 0;
3689
- const parts = raw.split(",").map((p) => p.trim()).filter(Boolean);
3690
- const specifiers = [];
3691
- for (const p of parts) {
3692
- const sp = parseSpecifier(p);
3693
- if (sp)
3694
- specifiers.push(sp);
3695
- }
3696
- if (specifiers.length === 0) {
3697
- return allOptions.find((o) => o.version === raw);
3698
- }
3699
- const matches = allOptions.filter((opt) => {
3700
- const vt = parseVersionTuple(opt.version);
3701
- return specifiers.every((sp) => satisfies(vt, sp));
3702
- });
3703
- if (matches.length === 0)
3704
- return void 0;
3705
- const installedMatch = matches.find(isInstalled2);
3706
- return installedMatch ?? matches[0];
3707
- }
3708
- function getSupportedPythonVersion({
3709
- isDev,
3710
- declaredPythonVersion
3711
- }) {
3712
- if (isDev) {
3713
- return getDevPythonVersion();
3714
- }
3715
- let selection = getLatestPythonVersion({ isDev: false });
3716
- if (declaredPythonVersion) {
3717
- const { version: version2, source } = declaredPythonVersion;
3718
- let requested;
3719
- if (source === "pyproject.toml") {
3720
- requested = selectFromRequiresPython(version2);
3721
- } else {
3722
- requested = allOptions.find((o) => o.version === version2);
3723
- }
3724
- if (requested) {
3725
- if (isDiscontinued(requested)) {
3726
- throw new import_build_utils3.NowBuildError({
3727
- code: "BUILD_UTILS_PYTHON_VERSION_DISCONTINUED",
3728
- link: "https://vercel.link/python-version",
3729
- message: `Python version "${requested.version}" detected in ${source} is discontinued and must be upgraded.`
3730
- });
3731
- }
3732
- if (isInstalled2(requested)) {
3733
- selection = requested;
3734
- console.log(`Using Python ${selection.version} from ${source}`);
3735
- } else {
3736
- console.warn(
3737
- `Warning: Python version "${version2}" detected in ${source} is not installed and will be ignored. https://vercel.link/python-version`
3738
- );
3739
- console.log(
3740
- `Falling back to latest installed version: ${selection.version}`
3741
- );
3742
- }
3743
- } else {
3744
- console.warn(
3745
- `Warning: Python version "${version2}" detected in ${source} is invalid and will be ignored. https://vercel.link/python-version`
3746
- );
3747
- console.log(
3748
- `Falling back to latest installed version: ${selection.version}`
3749
- );
3750
- }
3751
- } else {
3752
- console.log(
3753
- `No Python version specified in pyproject.toml or Pipfile.lock. Using latest installed version: ${selection.version}`
3754
- );
3755
- }
3756
- if (isDiscontinued(selection)) {
3757
- throw new import_build_utils3.NowBuildError({
3758
- code: "BUILD_UTILS_PYTHON_VERSION_DISCONTINUED",
3759
- link: "https://vercel.link/python-version",
3760
- message: `Python version "${selection.version}" declared in project configuration is discontinued and must be upgraded.`
3761
- });
3762
- }
3763
- if (selection.discontinueDate) {
3764
- const d = selection.discontinueDate.toISOString().split("T")[0];
3765
- const srcSuffix = declaredPythonVersion ? `detected in ${declaredPythonVersion.source}` : "selected by runtime";
3766
- console.warn(
3767
- `Error: Python version "${selection.version}" ${srcSuffix} has reached End-of-Life. Deployments created on or after ${d} will fail to build. https://vercel.link/python-version`
3768
- );
3769
- }
3770
- return selection;
3771
- }
3772
- function isDiscontinued({ discontinueDate }) {
3773
- const today = Date.now();
3774
- return discontinueDate !== void 0 && discontinueDate.getTime() <= today;
3775
- }
3776
- function isInstalled2({ pipPath, pythonPath }) {
3777
- return Boolean(import_which2.default.sync(pipPath, { nothrow: true })) && Boolean(import_which2.default.sync(pythonPath, { nothrow: true }));
3778
- }
3842
+ var import_build_utils9 = require("@vercel/build-utils");
3779
3843
 
3780
3844
  // src/start-dev-server.ts
3781
- var import_child_process = require("child_process");
3782
- var import_fs3 = require("fs");
3783
- var import_path4 = require("path");
3784
- var import_build_utils6 = require("@vercel/build-utils");
3845
+ var import_child_process2 = require("child_process");
3846
+ var import_fs4 = require("fs");
3847
+ var import_path6 = require("path");
3848
+ var import_build_utils7 = require("@vercel/build-utils");
3785
3849
 
3786
3850
  // src/entrypoint.ts
3787
- var import_path3 = require("path");
3788
- var import_build_utils4 = require("@vercel/build-utils");
3851
+ var import_path5 = require("path");
3789
3852
  var import_build_utils5 = require("@vercel/build-utils");
3853
+ var import_build_utils6 = require("@vercel/build-utils");
3790
3854
  var PYTHON_ENTRYPOINT_FILENAMES = [
3791
3855
  "app",
3792
3856
  "index",
@@ -3798,11 +3862,11 @@ var PYTHON_ENTRYPOINT_FILENAMES = [
3798
3862
  var PYTHON_ENTRYPOINT_DIRS = ["", "src", "app", "api"];
3799
3863
  var PYTHON_CANDIDATE_ENTRYPOINTS = PYTHON_ENTRYPOINT_FILENAMES.flatMap(
3800
3864
  (filename) => PYTHON_ENTRYPOINT_DIRS.map(
3801
- (dir) => import_path3.posix.join(dir, `${filename}.py`)
3865
+ (dir) => import_path5.posix.join(dir, `${filename}.py`)
3802
3866
  )
3803
3867
  );
3804
3868
  async function getPyprojectEntrypoint(workPath) {
3805
- const pyprojectData = await (0, import_build_utils5.readConfigFile)((0, import_path3.join)(workPath, "pyproject.toml"));
3869
+ const pyprojectData = await (0, import_build_utils6.readConfigFile)((0, import_path5.join)(workPath, "pyproject.toml"));
3806
3870
  if (!pyprojectData)
3807
3871
  return null;
3808
3872
  const scripts = pyprojectData.project?.scripts;
@@ -3815,7 +3879,7 @@ async function getPyprojectEntrypoint(workPath) {
3815
3879
  const modulePath = match[1];
3816
3880
  const relPath = modulePath.replace(/\./g, "/");
3817
3881
  try {
3818
- const fsFiles = await (0, import_build_utils4.glob)("**", workPath);
3882
+ const fsFiles = await (0, import_build_utils5.glob)("**", workPath);
3819
3883
  const candidates = [`${relPath}.py`, `${relPath}/__init__.py`];
3820
3884
  for (const candidate of candidates) {
3821
3885
  if (fsFiles[candidate])
@@ -3823,18 +3887,18 @@ async function getPyprojectEntrypoint(workPath) {
3823
3887
  }
3824
3888
  return null;
3825
3889
  } catch {
3826
- (0, import_build_utils4.debug)("Failed to discover Python entrypoint from pyproject.toml");
3890
+ (0, import_build_utils5.debug)("Failed to discover Python entrypoint from pyproject.toml");
3827
3891
  return null;
3828
3892
  }
3829
3893
  }
3830
3894
  async function detectGenericPythonEntrypoint(workPath, configuredEntrypoint) {
3831
3895
  const entry = configuredEntrypoint.endsWith(".py") ? configuredEntrypoint : `${configuredEntrypoint}.py`;
3832
3896
  try {
3833
- const fsFiles = await (0, import_build_utils4.glob)("**", workPath);
3897
+ const fsFiles = await (0, import_build_utils5.glob)("**", workPath);
3834
3898
  if (fsFiles[entry]) {
3835
- const isValid = await (0, import_build_utils4.isPythonEntrypoint)(fsFiles[entry]);
3899
+ const isValid = await (0, import_build_utils5.isPythonEntrypoint)(fsFiles[entry]);
3836
3900
  if (isValid) {
3837
- (0, import_build_utils4.debug)(`Using configured Python entrypoint: ${entry}`);
3901
+ (0, import_build_utils5.debug)(`Using configured Python entrypoint: ${entry}`);
3838
3902
  return entry;
3839
3903
  }
3840
3904
  }
@@ -3842,15 +3906,15 @@ async function detectGenericPythonEntrypoint(workPath, configuredEntrypoint) {
3842
3906
  (c) => !!fsFiles[c]
3843
3907
  );
3844
3908
  for (const candidate of candidates) {
3845
- const isValid = await (0, import_build_utils4.isPythonEntrypoint)(fsFiles[candidate]);
3909
+ const isValid = await (0, import_build_utils5.isPythonEntrypoint)(fsFiles[candidate]);
3846
3910
  if (isValid) {
3847
- (0, import_build_utils4.debug)(`Detected Python entrypoint: ${candidate}`);
3911
+ (0, import_build_utils5.debug)(`Detected Python entrypoint: ${candidate}`);
3848
3912
  return candidate;
3849
3913
  }
3850
3914
  }
3851
3915
  return null;
3852
3916
  } catch {
3853
- (0, import_build_utils4.debug)("Failed to discover Python entrypoint");
3917
+ (0, import_build_utils5.debug)("Failed to discover Python entrypoint");
3854
3918
  return null;
3855
3919
  }
3856
3920
  }
@@ -3907,12 +3971,12 @@ function installGlobalCleanupHandlers() {
3907
3971
  try {
3908
3972
  process.kill(info.pid, "SIGTERM");
3909
3973
  } catch (err) {
3910
- (0, import_build_utils6.debug)(`Error sending SIGTERM to ${info.pid}: ${err}`);
3974
+ (0, import_build_utils7.debug)(`Error sending SIGTERM to ${info.pid}: ${err}`);
3911
3975
  }
3912
3976
  try {
3913
3977
  process.kill(info.pid, "SIGKILL");
3914
3978
  } catch (err) {
3915
- (0, import_build_utils6.debug)(`Error sending SIGKILL to ${info.pid}: ${err}`);
3979
+ (0, import_build_utils7.debug)(`Error sending SIGKILL to ${info.pid}: ${err}`);
3916
3980
  }
3917
3981
  PERSISTENT_SERVERS.delete(key);
3918
3982
  }
@@ -3920,7 +3984,7 @@ function installGlobalCleanupHandlers() {
3920
3984
  try {
3921
3985
  restoreWarnings();
3922
3986
  } catch (err) {
3923
- (0, import_build_utils6.debug)(`Error restoring warnings: ${err}`);
3987
+ (0, import_build_utils7.debug)(`Error restoring warnings: ${err}`);
3924
3988
  }
3925
3989
  restoreWarnings = null;
3926
3990
  }
@@ -3939,33 +4003,33 @@ function installGlobalCleanupHandlers() {
3939
4003
  }
3940
4004
  function createDevAsgiShim(workPath, modulePath) {
3941
4005
  try {
3942
- const vercelPythonDir = (0, import_path4.join)(workPath, ".vercel", "python");
3943
- (0, import_fs3.mkdirSync)(vercelPythonDir, { recursive: true });
3944
- const shimPath = (0, import_path4.join)(vercelPythonDir, `${ASGI_SHIM_MODULE}.py`);
3945
- const templatePath = (0, import_path4.join)(__dirname, "..", `${ASGI_SHIM_MODULE}.py`);
3946
- const template = (0, import_fs3.readFileSync)(templatePath, "utf8");
4006
+ const vercelPythonDir = (0, import_path6.join)(workPath, ".vercel", "python");
4007
+ (0, import_fs4.mkdirSync)(vercelPythonDir, { recursive: true });
4008
+ const shimPath = (0, import_path6.join)(vercelPythonDir, `${ASGI_SHIM_MODULE}.py`);
4009
+ const templatePath = (0, import_path6.join)(__dirname, "..", `${ASGI_SHIM_MODULE}.py`);
4010
+ const template = (0, import_fs4.readFileSync)(templatePath, "utf8");
3947
4011
  const shimSource = template.replace(/__VC_DEV_MODULE_PATH__/g, modulePath);
3948
- (0, import_fs3.writeFileSync)(shimPath, shimSource, "utf8");
3949
- (0, import_build_utils6.debug)(`Prepared Python dev static shim at ${shimPath}`);
4012
+ (0, import_fs4.writeFileSync)(shimPath, shimSource, "utf8");
4013
+ (0, import_build_utils7.debug)(`Prepared Python dev static shim at ${shimPath}`);
3950
4014
  return ASGI_SHIM_MODULE;
3951
4015
  } catch (err) {
3952
- (0, import_build_utils6.debug)(`Failed to prepare dev static shim: ${err?.message || err}`);
4016
+ (0, import_build_utils7.debug)(`Failed to prepare dev static shim: ${err?.message || err}`);
3953
4017
  return null;
3954
4018
  }
3955
4019
  }
3956
4020
  function createDevWsgiShim(workPath, modulePath) {
3957
4021
  try {
3958
- const vercelPythonDir = (0, import_path4.join)(workPath, ".vercel", "python");
3959
- (0, import_fs3.mkdirSync)(vercelPythonDir, { recursive: true });
3960
- const shimPath = (0, import_path4.join)(vercelPythonDir, `${WSGI_SHIM_MODULE}.py`);
3961
- const templatePath = (0, import_path4.join)(__dirname, "..", `${WSGI_SHIM_MODULE}.py`);
3962
- const template = (0, import_fs3.readFileSync)(templatePath, "utf8");
4022
+ const vercelPythonDir = (0, import_path6.join)(workPath, ".vercel", "python");
4023
+ (0, import_fs4.mkdirSync)(vercelPythonDir, { recursive: true });
4024
+ const shimPath = (0, import_path6.join)(vercelPythonDir, `${WSGI_SHIM_MODULE}.py`);
4025
+ const templatePath = (0, import_path6.join)(__dirname, "..", `${WSGI_SHIM_MODULE}.py`);
4026
+ const template = (0, import_fs4.readFileSync)(templatePath, "utf8");
3963
4027
  const shimSource = template.replace(/__VC_DEV_MODULE_PATH__/g, modulePath);
3964
- (0, import_fs3.writeFileSync)(shimPath, shimSource, "utf8");
3965
- (0, import_build_utils6.debug)(`Prepared Python dev WSGI shim at ${shimPath}`);
4028
+ (0, import_fs4.writeFileSync)(shimPath, shimSource, "utf8");
4029
+ (0, import_build_utils7.debug)(`Prepared Python dev WSGI shim at ${shimPath}`);
3966
4030
  return WSGI_SHIM_MODULE;
3967
4031
  } catch (err) {
3968
- (0, import_build_utils6.debug)(`Failed to prepare dev WSGI shim: ${err?.message || err}`);
4032
+ (0, import_build_utils7.debug)(`Failed to prepare dev WSGI shim: ${err?.message || err}`);
3969
4033
  return null;
3970
4034
  }
3971
4035
  }
@@ -3985,7 +4049,7 @@ var startDevServer = async (opts) => {
3985
4049
  );
3986
4050
  if (!entry) {
3987
4051
  const searched = PYTHON_CANDIDATE_ENTRYPOINTS.join(", ");
3988
- throw new import_build_utils6.NowBuildError({
4052
+ throw new import_build_utils7.NowBuildError({
3989
4053
  code: "PYTHON_ENTRYPOINT_NOT_FOUND",
3990
4054
  message: `No ${framework} entrypoint found. Add an 'app' script in pyproject.toml or define an entrypoint in one of: ${searched}.`,
3991
4055
  link: `https://vercel.com/docs/frameworks/backend/${framework?.toLowerCase()}#exporting-the-${framework?.toLowerCase()}-application`,
@@ -4031,11 +4095,11 @@ var startDevServer = async (opts) => {
4031
4095
  try {
4032
4096
  await new Promise((resolve2, reject) => {
4033
4097
  let resolved = false;
4034
- const { pythonPath: systemPython } = getLatestPythonVersion(meta);
4098
+ const { pythonPath: systemPython } = getDefaultPythonVersion(meta);
4035
4099
  let pythonCmd = systemPython;
4036
4100
  const venv = isInVirtualEnv();
4037
4101
  if (venv) {
4038
- (0, import_build_utils6.debug)(`Running in virtualenv at ${venv}`);
4102
+ (0, import_build_utils7.debug)(`Running in virtualenv at ${venv}`);
4039
4103
  } else {
4040
4104
  const { pythonCmd: venvPythonCmd, venvRoot } = useVirtualEnv(
4041
4105
  workPath,
@@ -4044,9 +4108,9 @@ var startDevServer = async (opts) => {
4044
4108
  );
4045
4109
  pythonCmd = venvPythonCmd;
4046
4110
  if (venvRoot) {
4047
- (0, import_build_utils6.debug)(`Using virtualenv at ${venvRoot}`);
4111
+ (0, import_build_utils7.debug)(`Using virtualenv at ${venvRoot}`);
4048
4112
  } else {
4049
- (0, import_build_utils6.debug)("No virtualenv found");
4113
+ (0, import_build_utils7.debug)("No virtualenv found");
4050
4114
  try {
4051
4115
  const yellow = "\x1B[33m";
4052
4116
  const reset = "\x1B[0m";
@@ -4063,16 +4127,16 @@ If you are using a virtual environment, activate it before running "vercel dev",
4063
4127
  if (framework !== "flask") {
4064
4128
  const devShimModule = createDevAsgiShim(workPath, modulePath);
4065
4129
  if (devShimModule) {
4066
- const vercelPythonDir = (0, import_path4.join)(workPath, ".vercel", "python");
4130
+ const vercelPythonDir = (0, import_path6.join)(workPath, ".vercel", "python");
4067
4131
  const existingPythonPath = env.PYTHONPATH || "";
4068
4132
  env.PYTHONPATH = existingPythonPath ? `${vercelPythonDir}:${existingPythonPath}` : vercelPythonDir;
4069
4133
  }
4070
4134
  const moduleToRun = devShimModule || modulePath;
4071
4135
  const argv = ["-u", "-m", moduleToRun];
4072
- (0, import_build_utils6.debug)(
4136
+ (0, import_build_utils7.debug)(
4073
4137
  `Starting ASGI dev server (${framework}): ${pythonCmd} ${argv.join(" ")}`
4074
4138
  );
4075
- const child = (0, import_child_process.spawn)(pythonCmd, argv, {
4139
+ const child = (0, import_child_process2.spawn)(pythonCmd, argv, {
4076
4140
  cwd: workPath,
4077
4141
  env,
4078
4142
  stdio: ["inherit", "pipe", "pipe"]
@@ -4143,14 +4207,14 @@ If you are using a virtual environment, activate it before running "vercel dev",
4143
4207
  } else {
4144
4208
  const devShimModule = createDevWsgiShim(workPath, modulePath);
4145
4209
  if (devShimModule) {
4146
- const vercelPythonDir = (0, import_path4.join)(workPath, ".vercel", "python");
4210
+ const vercelPythonDir = (0, import_path6.join)(workPath, ".vercel", "python");
4147
4211
  const existingPythonPath = env.PYTHONPATH || "";
4148
4212
  env.PYTHONPATH = existingPythonPath ? `${vercelPythonDir}:${existingPythonPath}` : vercelPythonDir;
4149
4213
  }
4150
4214
  const moduleToRun = devShimModule || modulePath;
4151
4215
  const argv = ["-u", "-m", moduleToRun];
4152
- (0, import_build_utils6.debug)(`Starting Flask dev server: ${pythonCmd} ${argv.join(" ")}`);
4153
- const child = (0, import_child_process.spawn)(pythonCmd, argv, {
4216
+ (0, import_build_utils7.debug)(`Starting Flask dev server: ${pythonCmd} ${argv.join(" ")}`);
4217
+ const child = (0, import_child_process2.spawn)(pythonCmd, argv, {
4154
4218
  cwd: workPath,
4155
4219
  env,
4156
4220
  stdio: ["inherit", "pipe", "pipe"]
@@ -4236,8 +4300,8 @@ If you are using a virtual environment, activate it before running "vercel dev",
4236
4300
  };
4237
4301
 
4238
4302
  // src/index.ts
4239
- var readFile = (0, import_util.promisify)(import_fs4.default.readFile);
4240
- var writeFile = (0, import_util.promisify)(import_fs4.default.writeFile);
4303
+ var readFile = (0, import_util.promisify)(import_fs5.default.readFile);
4304
+ var writeFile = (0, import_util.promisify)(import_fs5.default.writeFile);
4241
4305
  var version = 3;
4242
4306
  async function downloadFilesInWorkPath({
4243
4307
  entrypoint,
@@ -4245,13 +4309,13 @@ async function downloadFilesInWorkPath({
4245
4309
  files,
4246
4310
  meta = {}
4247
4311
  }) {
4248
- (0, import_build_utils7.debug)("Downloading user files...");
4249
- let downloadedFiles = await (0, import_build_utils7.download)(files, workPath, meta);
4312
+ (0, import_build_utils8.debug)("Downloading user files...");
4313
+ let downloadedFiles = await (0, import_build_utils8.download)(files, workPath, meta);
4250
4314
  if (meta.isDev) {
4251
- const { devCacheDir = (0, import_path5.join)(workPath, ".now", "cache") } = meta;
4252
- const destCache = (0, import_path5.join)(devCacheDir, (0, import_path5.basename)(entrypoint, ".py"));
4253
- await (0, import_build_utils7.download)(downloadedFiles, destCache);
4254
- downloadedFiles = await (0, import_build_utils7.glob)("**", destCache);
4315
+ const { devCacheDir = (0, import_path7.join)(workPath, ".now", "cache") } = meta;
4316
+ const destCache = (0, import_path7.join)(devCacheDir, (0, import_path7.basename)(entrypoint, ".py"));
4317
+ await (0, import_build_utils8.download)(downloadedFiles, destCache);
4318
+ downloadedFiles = await (0, import_build_utils8.glob)("**", destCache);
4255
4319
  workPath = destCache;
4256
4320
  }
4257
4321
  return workPath;
@@ -4275,21 +4339,21 @@ var build = async ({
4275
4339
  });
4276
4340
  try {
4277
4341
  if (meta.isDev) {
4278
- const setupCfg = (0, import_path5.join)(workPath, "setup.cfg");
4342
+ const setupCfg = (0, import_path7.join)(workPath, "setup.cfg");
4279
4343
  await writeFile(setupCfg, "[install]\nprefix=\n");
4280
4344
  }
4281
4345
  } catch (err) {
4282
4346
  console.log('Failed to create "setup.cfg" file');
4283
4347
  throw err;
4284
4348
  }
4285
- if ((0, import_build_utils7.isPythonFramework)(framework)) {
4349
+ if ((0, import_build_utils8.isPythonFramework)(framework)) {
4286
4350
  const {
4287
4351
  cliType,
4288
4352
  lockfileVersion,
4289
4353
  packageJsonPackageManager,
4290
4354
  turboSupportsCorepackHome
4291
- } = await (0, import_build_utils7.scanParentDirs)(workPath, true);
4292
- spawnEnv = (0, import_build_utils7.getEnvForPackageManager)({
4355
+ } = await (0, import_build_utils8.scanParentDirs)(workPath, true);
4356
+ spawnEnv = (0, import_build_utils8.getEnvForPackageManager)({
4293
4357
  cliType,
4294
4358
  lockfileVersion,
4295
4359
  packageJsonPackageManager,
@@ -4310,7 +4374,7 @@ var build = async ({
4310
4374
  config?.buildCommand;
4311
4375
  if (projectBuildCommand) {
4312
4376
  console.log(`Running "${projectBuildCommand}"`);
4313
- await (0, import_build_utils7.execCommand)(projectBuildCommand, {
4377
+ await (0, import_build_utils8.execCommand)(projectBuildCommand, {
4314
4378
  env: spawnEnv,
4315
4379
  cwd: workPath
4316
4380
  });
@@ -4322,21 +4386,21 @@ var build = async ({
4322
4386
  );
4323
4387
  }
4324
4388
  }
4325
- let fsFiles = await (0, import_build_utils7.glob)("**", workPath);
4326
- if ((0, import_build_utils7.isPythonFramework)(framework) && (!fsFiles[entrypoint] || !entrypoint.endsWith(".py"))) {
4389
+ let fsFiles = await (0, import_build_utils8.glob)("**", workPath);
4390
+ if ((0, import_build_utils8.isPythonFramework)(framework) && (!fsFiles[entrypoint] || !entrypoint.endsWith(".py"))) {
4327
4391
  const detected = await detectPythonEntrypoint(
4328
4392
  config.framework,
4329
4393
  workPath,
4330
4394
  entrypoint
4331
4395
  );
4332
4396
  if (detected) {
4333
- (0, import_build_utils7.debug)(
4397
+ (0, import_build_utils8.debug)(
4334
4398
  `Resolved Python entrypoint to "${detected}" (configured "${entrypoint}" not found).`
4335
4399
  );
4336
4400
  entrypoint = detected;
4337
4401
  } else {
4338
4402
  const searchedList = PYTHON_CANDIDATE_ENTRYPOINTS.join(", ");
4339
- throw new import_build_utils7.NowBuildError({
4403
+ throw new import_build_utils8.NowBuildError({
4340
4404
  code: `${framework.toUpperCase()}_ENTRYPOINT_NOT_FOUND`,
4341
4405
  message: `No ${framework} entrypoint found. Add an 'app' script in pyproject.toml or define an entrypoint in one of: ${searchedList}.`,
4342
4406
  link: `https://vercel.com/docs/frameworks/backend/${framework}#exporting-the-${framework}-application`,
@@ -4344,7 +4408,7 @@ var build = async ({
4344
4408
  });
4345
4409
  }
4346
4410
  }
4347
- const entryDirectory = (0, import_path5.dirname)(entrypoint);
4411
+ const entryDirectory = (0, import_path7.dirname)(entrypoint);
4348
4412
  const pyprojectDir = findDir({
4349
4413
  file: "pyproject.toml",
4350
4414
  entryDirectory,
@@ -4357,29 +4421,51 @@ var build = async ({
4357
4421
  workPath,
4358
4422
  fsFiles
4359
4423
  });
4424
+ const pythonVersionFileDir = findDir({
4425
+ file: ".python-version",
4426
+ entryDirectory,
4427
+ workPath,
4428
+ fsFiles
4429
+ });
4360
4430
  let declaredPythonVersion;
4361
- if (pyprojectDir) {
4431
+ if (pythonVersionFileDir) {
4432
+ try {
4433
+ const content = await readFile(
4434
+ (0, import_path7.join)(pythonVersionFileDir, ".python-version"),
4435
+ "utf8"
4436
+ );
4437
+ const version2 = parsePythonVersionFile(content);
4438
+ if (version2) {
4439
+ declaredPythonVersion = { version: version2, source: ".python-version" };
4440
+ (0, import_build_utils8.debug)(`Found Python version ${version2} in .python-version`);
4441
+ }
4442
+ } catch (err) {
4443
+ (0, import_build_utils8.debug)("Failed to read .python-version file", err);
4444
+ }
4445
+ }
4446
+ if (!declaredPythonVersion && pyprojectDir) {
4362
4447
  let requiresPython;
4363
4448
  try {
4364
- const pyproject = await (0, import_build_utils8.readConfigFile)((0, import_path5.join)(pyprojectDir, "pyproject.toml"));
4449
+ const pyproject = await (0, import_build_utils9.readConfigFile)((0, import_path7.join)(pyprojectDir, "pyproject.toml"));
4365
4450
  requiresPython = pyproject?.project?.["requires-python"];
4366
4451
  } catch (err) {
4367
- (0, import_build_utils7.debug)("Failed to parse pyproject.toml", err);
4452
+ (0, import_build_utils8.debug)("Failed to parse pyproject.toml", err);
4368
4453
  }
4369
4454
  if (typeof requiresPython === "string" && requiresPython.trim()) {
4370
4455
  declaredPythonVersion = {
4371
4456
  version: requiresPython.trim(),
4372
4457
  source: "pyproject.toml"
4373
4458
  };
4374
- (0, import_build_utils7.debug)(`Found requires-python "${requiresPython}" in pyproject.toml`);
4459
+ (0, import_build_utils8.debug)(`Found requires-python "${requiresPython}" in pyproject.toml`);
4375
4460
  }
4376
- } else if (pipfileLockDir) {
4461
+ }
4462
+ if (!declaredPythonVersion && pipfileLockDir) {
4377
4463
  let lock = {};
4378
4464
  try {
4379
- const json = await readFile((0, import_path5.join)(pipfileLockDir, "Pipfile.lock"), "utf8");
4465
+ const json = await readFile((0, import_path7.join)(pipfileLockDir, "Pipfile.lock"), "utf8");
4380
4466
  lock = JSON.parse(json);
4381
4467
  } catch (err) {
4382
- throw new import_build_utils7.NowBuildError({
4468
+ throw new import_build_utils8.NowBuildError({
4383
4469
  code: "INVALID_PIPFILE_LOCK",
4384
4470
  message: "Unable to parse Pipfile.lock"
4385
4471
  });
@@ -4387,20 +4473,30 @@ var build = async ({
4387
4473
  const pyFromLock = lock?._meta?.requires?.python_version;
4388
4474
  if (pyFromLock) {
4389
4475
  declaredPythonVersion = { version: pyFromLock, source: "Pipfile.lock" };
4390
- (0, import_build_utils7.debug)(`Found Python version ${pyFromLock} in Pipfile.lock`);
4476
+ (0, import_build_utils8.debug)(`Found Python version ${pyFromLock} in Pipfile.lock`);
4391
4477
  }
4392
4478
  }
4393
4479
  const pythonVersion = getSupportedPythonVersion({
4394
4480
  isDev: meta.isDev,
4395
4481
  declaredPythonVersion
4396
4482
  });
4397
- fsFiles = await (0, import_build_utils7.glob)("**", workPath);
4398
- const venvPath = (0, import_path5.join)(workPath, ".vercel", "python", ".venv");
4483
+ const selectedVersionTuple = parseVersionTuple(pythonVersion.version);
4484
+ const defaultVersionTuple = parseVersionTuple(DEFAULT_PYTHON_VERSION);
4485
+ if (!pythonVersionFileDir && pyprojectDir && declaredPythonVersion?.source === "pyproject.toml" && selectedVersionTuple && defaultVersionTuple && compareTuples(selectedVersionTuple, defaultVersionTuple) <= 0) {
4486
+ const pythonVersionFilePath = (0, import_path7.join)(pyprojectDir, ".python-version");
4487
+ await writeFile(pythonVersionFilePath, `${pythonVersion.version}
4488
+ `);
4489
+ console.log(
4490
+ `Writing .python-version file with version ${pythonVersion.version}`
4491
+ );
4492
+ }
4493
+ fsFiles = await (0, import_build_utils8.glob)("**", workPath);
4494
+ const venvPath = (0, import_path7.join)(workPath, ".vercel", "python", ".venv");
4399
4495
  await ensureVenv({
4400
4496
  pythonPath: pythonVersion.pythonPath,
4401
4497
  venvPath
4402
4498
  });
4403
- const hasCustomInstallCommand = (0, import_build_utils7.isPythonFramework)(framework) && !!projectInstallCommand;
4499
+ const hasCustomInstallCommand = (0, import_build_utils8.isPythonFramework)(framework) && !!projectInstallCommand;
4404
4500
  let useRuntime = false;
4405
4501
  if (hasCustomInstallCommand) {
4406
4502
  const baseEnv = spawnEnv || process.env;
@@ -4408,13 +4504,13 @@ var build = async ({
4408
4504
  pythonEnv.VERCEL_PYTHON_VENV_PATH = venvPath;
4409
4505
  const installCommand = projectInstallCommand;
4410
4506
  console.log(`Running "install" command: \`${installCommand}\`...`);
4411
- await (0, import_build_utils7.execCommand)(installCommand, {
4507
+ await (0, import_build_utils8.execCommand)(installCommand, {
4412
4508
  env: pythonEnv,
4413
4509
  cwd: workPath
4414
4510
  });
4415
4511
  } else {
4416
4512
  let ranPyprojectInstall = false;
4417
- if ((0, import_build_utils7.isPythonFramework)(framework)) {
4513
+ if ((0, import_build_utils8.isPythonFramework)(framework)) {
4418
4514
  const baseEnv = spawnEnv || process.env;
4419
4515
  const pythonEnv = createVenvEnv(venvPath, baseEnv);
4420
4516
  pythonEnv.VERCEL_PYTHON_VENV_PATH = venvPath;
@@ -4427,10 +4523,11 @@ var build = async ({
4427
4523
  );
4428
4524
  }
4429
4525
  if (!ranPyprojectInstall) {
4430
- let uvPath;
4526
+ let uv;
4431
4527
  try {
4432
- uvPath = await getUvBinaryOrInstall(pythonVersion.pythonPath);
4528
+ const uvPath = await getUvBinaryOrInstall(pythonVersion.pythonPath);
4433
4529
  console.log(`Using uv at "${uvPath}"`);
4530
+ uv = new UvRunner(uvPath);
4434
4531
  } catch (err) {
4435
4532
  console.log("Failed to install or locate uv");
4436
4533
  throw new Error(
@@ -4456,25 +4553,24 @@ var build = async ({
4456
4553
  repoRootPath,
4457
4554
  pythonPath: pythonVersion.pythonPath,
4458
4555
  pipPath: pythonVersion.pipPath,
4459
- uvPath,
4556
+ uv,
4460
4557
  venvPath,
4461
4558
  meta,
4462
4559
  runtimeDependencies
4463
4560
  });
4464
- await runUvSync({
4465
- uvPath,
4561
+ await uv.sync({
4466
4562
  venvPath,
4467
4563
  projectDir,
4468
4564
  locked: true
4469
4565
  });
4470
4566
  }
4471
4567
  }
4472
- (0, import_build_utils7.debug)("Entrypoint is", entrypoint);
4568
+ (0, import_build_utils8.debug)("Entrypoint is", entrypoint);
4473
4569
  const moduleName = entrypoint.replace(/\//g, ".").replace(/\.py$/i, "");
4474
4570
  const vendorDir = resolveVendorDir();
4475
4571
  const suffix = meta.isDev && !entrypoint.endsWith(".py") ? ".py" : "";
4476
4572
  const entrypointWithSuffix = `${entrypoint}${suffix}`;
4477
- (0, import_build_utils7.debug)("Entrypoint with suffix is", entrypointWithSuffix);
4573
+ (0, import_build_utils8.debug)("Entrypoint with suffix is", entrypointWithSuffix);
4478
4574
  let handlerPyContents;
4479
4575
  if (useRuntime) {
4480
4576
  handlerPyContents = `
@@ -4516,7 +4612,7 @@ if os.path.isdir(_vendor):
4516
4612
  from vercel_runtime.vc_init import vc_handler
4517
4613
  `;
4518
4614
  } else {
4519
- const originalPyPath = (0, import_path5.join)(__dirname, "..", "vc_init.py");
4615
+ const originalPyPath = (0, import_path7.join)(__dirname, "..", "vc_init.py");
4520
4616
  const originalHandlerPyContents = await readFile(originalPyPath, "utf8");
4521
4617
  handlerPyContents = originalHandlerPyContents.replace(/__VC_HANDLER_MODULE_NAME/g, moduleName).replace(/__VC_HANDLER_ENTRYPOINT/g, entrypointWithSuffix).replace(/__VC_HANDLER_VENDOR_DIR/g, vendorDir);
4522
4618
  }
@@ -4544,7 +4640,7 @@ from vercel_runtime.vc_init import vc_handler
4544
4640
  cwd: workPath,
4545
4641
  ignore: config && typeof config.excludeFiles === "string" ? [...predefinedExcludes, config.excludeFiles] : predefinedExcludes
4546
4642
  };
4547
- const files = await (0, import_build_utils7.glob)("**", globOptions);
4643
+ const files = await (0, import_build_utils8.glob)("**", globOptions);
4548
4644
  const vendorFiles = await mirrorSitePackagesIntoVendor({
4549
4645
  venvPath,
4550
4646
  vendorDirName: vendorDir
@@ -4553,12 +4649,12 @@ from vercel_runtime.vc_init import vc_handler
4553
4649
  files[p] = f;
4554
4650
  }
4555
4651
  const handlerPyFilename = "vc__handler__python";
4556
- files[`${handlerPyFilename}.py`] = new import_build_utils7.FileBlob({ data: handlerPyContents });
4652
+ files[`${handlerPyFilename}.py`] = new import_build_utils8.FileBlob({ data: handlerPyContents });
4557
4653
  if (config.framework === "fasthtml") {
4558
4654
  const { SESSKEY = "" } = process.env;
4559
- files[".sesskey"] = new import_build_utils7.FileBlob({ data: `"${SESSKEY}"` });
4655
+ files[".sesskey"] = new import_build_utils8.FileBlob({ data: `"${SESSKEY}"` });
4560
4656
  }
4561
- const output = new import_build_utils7.Lambda({
4657
+ const output = new import_build_utils8.Lambda({
4562
4658
  files,
4563
4659
  handler: `${handlerPyFilename}.vc_handler`,
4564
4660
  runtime: pythonVersion.runtime,
@@ -4594,7 +4690,7 @@ var defaultShouldServe = ({
4594
4690
  if (entrypoint === requestPath && hasProp(files, entrypoint)) {
4595
4691
  return true;
4596
4692
  }
4597
- const { dir, name } = (0, import_path5.parse)(entrypoint);
4693
+ const { dir, name } = (0, import_path7.parse)(entrypoint);
4598
4694
  if (name === "index" && dir === requestPath && hasProp(files, entrypoint)) {
4599
4695
  return true;
4600
4696
  }
@@ -4603,6 +4699,16 @@ var defaultShouldServe = ({
4603
4699
  function hasProp(obj, key) {
4604
4700
  return Object.hasOwnProperty.call(obj, key);
4605
4701
  }
4702
+ function parsePythonVersionFile(content) {
4703
+ const lines = content.split("\n");
4704
+ for (const line of lines) {
4705
+ const trimmed = line.trim();
4706
+ if (!trimmed || trimmed.startsWith("#"))
4707
+ continue;
4708
+ return trimmed;
4709
+ }
4710
+ return void 0;
4711
+ }
4606
4712
  // Annotate the CommonJS export names for ESM import in node:
4607
4713
  0 && (module.exports = {
4608
4714
  build,