@vercel/python 6.3.2 → 6.4.1

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 +803 -689
  2. package/package.json +3 -3
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,287 @@ __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
+ const error = new Error(
2877
+ `Failed to run "${pretty}": ${err instanceof Error ? err.message : String(err)}`
2878
+ );
2879
+ if (err && typeof err === "object") {
2880
+ if ("code" in err) {
2881
+ error.code = err.code;
2882
+ } else if ("signal" in err) {
2883
+ error.code = err.signal;
2884
+ }
2885
+ }
2886
+ throw error;
2887
+ }
2888
+ }
2889
+ getVenvEnv(venvPath) {
2890
+ const binDir = isWin ? (0, import_path.join)(venvPath, "Scripts") : (0, import_path.join)(venvPath, "bin");
2891
+ const existingPath = process.env.PATH || "";
2892
+ return {
2893
+ ...getProtectedUvEnv(process.env),
2894
+ VIRTUAL_ENV: venvPath,
2895
+ PATH: existingPath ? `${binDir}${import_path2.delimiter}${existingPath}` : binDir
2896
+ };
2897
+ }
2898
+ };
2899
+ async function getGlobalScriptsDir(pythonPath) {
2900
+ const code = `import sysconfig; print(sysconfig.get_path('scripts'))`;
2901
+ try {
2902
+ const { stdout } = await (0, import_execa.default)(pythonPath, ["-c", code]);
2903
+ const out = stdout.trim();
2904
+ return out || null;
2905
+ } catch (err) {
2906
+ (0, import_build_utils.debug)("Failed to resolve Python global scripts directory", err);
2907
+ return null;
2908
+ }
2909
+ }
2910
+ async function getUserScriptsDir(pythonPath) {
2911
+ const code = `import sys, sysconfig; print(sysconfig.get_path('scripts', scheme=('nt_user' if sys.platform == 'win32' else 'posix_user')))`.replace(
2912
+ /\n/g,
2913
+ " "
2914
+ );
2915
+ try {
2916
+ const { stdout } = await (0, import_execa.default)(pythonPath, ["-c", code]);
2917
+ const out = stdout.trim();
2918
+ return out || null;
2919
+ } catch (err) {
2920
+ (0, import_build_utils.debug)("Failed to resolve Python user scripts directory", err);
2921
+ return null;
2922
+ }
2923
+ }
2924
+ async function findUvBinary(pythonPath) {
2925
+ const found = import_which.default.sync("uv", { nothrow: true });
2926
+ if (found)
2927
+ return found;
2928
+ try {
2929
+ const globalScriptsDir = await getGlobalScriptsDir(pythonPath);
2930
+ if (globalScriptsDir) {
2931
+ const uvPath = (0, import_path.join)(globalScriptsDir, uvExec);
2932
+ if (import_fs.default.existsSync(uvPath))
2933
+ return uvPath;
2934
+ }
2935
+ } catch (err) {
2936
+ (0, import_build_utils.debug)("Failed to resolve Python global scripts directory", err);
2937
+ }
2938
+ try {
2939
+ const userScriptsDir = await getUserScriptsDir(pythonPath);
2940
+ if (userScriptsDir) {
2941
+ const uvPath = (0, import_path.join)(userScriptsDir, uvExec);
2942
+ if (import_fs.default.existsSync(uvPath))
2943
+ return uvPath;
2944
+ }
2945
+ } catch (err) {
2946
+ (0, import_build_utils.debug)("Failed to resolve Python user scripts directory", err);
2947
+ }
2948
+ try {
2949
+ const candidates = [];
2950
+ if (!isWin) {
2951
+ candidates.push((0, import_path.join)(import_os.default.homedir(), ".local", "bin", "uv"));
2952
+ candidates.push("/usr/local/bin/uv");
2953
+ candidates.push("/opt/homebrew/bin/uv");
2954
+ } else {
2955
+ candidates.push("C:\\Users\\Public\\uv\\uv.exe");
2956
+ }
2957
+ for (const p of candidates) {
2958
+ if (import_fs.default.existsSync(p))
2959
+ return p;
2960
+ }
2961
+ } catch (err) {
2962
+ (0, import_build_utils.debug)("Failed to resolve uv fallback paths", err);
2963
+ }
2964
+ return null;
2965
+ }
2966
+ async function getUvBinaryOrInstall(pythonPath) {
2967
+ const uvBin = await findUvBinary(pythonPath);
2968
+ if (uvBin)
2969
+ return uvBin;
2970
+ try {
2971
+ console.log("Installing uv...");
2972
+ await (0, import_execa.default)(
2973
+ pythonPath,
2974
+ [
2975
+ "-m",
2976
+ "pip",
2977
+ "install",
2978
+ "--disable-pip-version-check",
2979
+ "--no-cache-dir",
2980
+ "--user",
2981
+ `uv==${UV_VERSION}`
2982
+ ],
2983
+ { env: { ...process.env, PIP_USER: "1" } }
2984
+ );
2985
+ } catch (err) {
2986
+ throw new Error(
2987
+ `Failed to install uv via pip: ${err instanceof Error ? err.message : String(err)}`
2988
+ );
2989
+ }
2990
+ const resolvedUvBin = await findUvBinary(pythonPath);
2991
+ if (!resolvedUvBin) {
2992
+ throw new Error("Unable to resolve uv binary after pip install");
2993
+ }
2994
+ console.log(`Installed uv at "${resolvedUvBin}"`);
2995
+ return resolvedUvBin;
2996
+ }
2997
+ function filterUnsafeUvPipArgs(args) {
2998
+ return args.filter((arg) => arg !== "--no-warn-script-location");
2999
+ }
3000
+ function getProtectedUvEnv(baseEnv = process.env) {
3001
+ return {
3002
+ ...baseEnv,
3003
+ UV_PYTHON_DOWNLOADS: UV_PYTHON_DOWNLOADS_MODE
3004
+ };
3005
+ }
3006
+
3007
+ // src/utils.ts
3008
+ var isWin2 = process.platform === "win32";
2771
3009
  var isInVirtualEnv = () => {
2772
3010
  return process.env.VIRTUAL_ENV;
2773
3011
  };
2774
3012
  function getVenvBinDir(venvPath) {
2775
- return (0, import_path.join)(venvPath, isWin ? "Scripts" : "bin");
3013
+ return (0, import_path3.join)(venvPath, isWin2 ? "Scripts" : "bin");
2776
3014
  }
2777
3015
  function useVirtualEnv(workPath, env, systemPython) {
2778
3016
  const venvDirs = [".venv", "venv"];
2779
3017
  let pythonCmd = systemPython;
2780
3018
  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));
3019
+ const venvRoot = (0, import_path3.join)(workPath, venv);
3020
+ const binDir = process.platform === "win32" ? (0, import_path3.join)(venvRoot, "Scripts") : (0, import_path3.join)(venvRoot, "bin");
3021
+ 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")];
3022
+ const found = candidates.find((p) => import_fs2.default.existsSync(p));
2785
3023
  if (found) {
2786
3024
  pythonCmd = found;
2787
3025
  env.VIRTUAL_ENV = venvRoot;
2788
- env.PATH = `${binDir}${import_path.delimiter}${env.PATH || ""}`;
3026
+ env.PATH = `${binDir}${import_path3.delimiter}${env.PATH || ""}`;
2789
3027
  return { pythonCmd, venvRoot };
2790
3028
  }
2791
3029
  }
2792
3030
  return { pythonCmd };
2793
3031
  }
2794
- function getProtectedUvEnv(baseEnv = process.env) {
2795
- return {
2796
- ...baseEnv,
2797
- UV_PYTHON_DOWNLOADS: UV_PYTHON_DOWNLOADS_MODE
2798
- };
2799
- }
2800
3032
  function createVenvEnv(venvPath, baseEnv = process.env) {
2801
3033
  const env = {
2802
3034
  ...getProtectedUvEnv(baseEnv),
@@ -2804,118 +3036,345 @@ function createVenvEnv(venvPath, baseEnv = process.env) {
2804
3036
  };
2805
3037
  const binDir = getVenvBinDir(venvPath);
2806
3038
  const existingPath = env.PATH || process.env.PATH || "";
2807
- env.PATH = existingPath ? `${binDir}${import_path.delimiter}${existingPath}` : binDir;
3039
+ env.PATH = existingPath ? `${binDir}${import_path3.delimiter}${existingPath}` : binDir;
2808
3040
  return env;
2809
3041
  }
2810
3042
  async function ensureVenv({
2811
3043
  pythonPath,
2812
3044
  venvPath
2813
3045
  }) {
2814
- const marker = (0, import_path.join)(venvPath, "pyvenv.cfg");
3046
+ const marker = (0, import_path3.join)(venvPath, "pyvenv.cfg");
2815
3047
  try {
2816
- await import_fs.default.promises.access(marker);
3048
+ await import_fs2.default.promises.access(marker);
2817
3049
  return;
2818
3050
  } catch {
2819
3051
  }
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");
3052
+ await import_fs2.default.promises.mkdir(venvPath, { recursive: true });
3053
+ console.log(`Creating virtual environment at "${venvPath}"...`);
3054
+ await (0, import_execa2.default)(pythonPath, ["-m", "venv", venvPath]);
3055
+ }
3056
+ function getVenvPythonBin(venvPath) {
3057
+ return (0, import_path3.join)(getVenvBinDir(venvPath), isWin2 ? "python.exe" : "python");
3058
+ }
3059
+ async function runPyprojectScript(workPath, scriptNames, env, useUserVirtualEnv = true) {
3060
+ const pyprojectPath = (0, import_path3.join)(workPath, "pyproject.toml");
3061
+ if (!import_fs2.default.existsSync(pyprojectPath))
3062
+ return false;
3063
+ let pyproject = null;
3064
+ try {
3065
+ pyproject = await (0, import_build_utils2.readConfigFile)(pyprojectPath);
3066
+ } catch {
3067
+ console.error("Failed to parse pyproject.toml");
3068
+ return false;
3069
+ }
3070
+ const scripts = pyproject?.tool?.vercel?.scripts || {};
3071
+ const candidates = typeof scriptNames === "string" ? [scriptNames] : Array.from(scriptNames);
3072
+ const scriptToRun = candidates.find((name) => Boolean(scripts[name]));
3073
+ if (!scriptToRun)
3074
+ return false;
3075
+ const systemPython = process.platform === "win32" ? "python" : "python3";
3076
+ const finalEnv = { ...process.env, ...env };
3077
+ if (useUserVirtualEnv) {
3078
+ useVirtualEnv(workPath, finalEnv, systemPython);
3079
+ }
3080
+ const scriptCommand = scripts[scriptToRun];
3081
+ if (typeof scriptCommand === "string" && scriptCommand.trim()) {
3082
+ console.log(`Executing: ${scriptCommand}`);
3083
+ await (0, import_build_utils2.execCommand)(scriptCommand, {
3084
+ cwd: workPath,
3085
+ env: finalEnv
3086
+ });
3087
+ return true;
3088
+ }
3089
+ return false;
3090
+ }
3091
+ function findDir({
3092
+ file,
3093
+ entryDirectory,
3094
+ workPath,
3095
+ fsFiles
3096
+ }) {
3097
+ if (fsFiles[(0, import_path3.join)(entryDirectory, file)]) {
3098
+ return (0, import_path3.join)(workPath, entryDirectory);
3099
+ }
3100
+ if (fsFiles[file]) {
3101
+ return workPath;
3102
+ }
3103
+ return null;
3104
+ }
3105
+
3106
+ // src/version.ts
3107
+ var import_build_utils3 = require("@vercel/build-utils");
3108
+ var DEFAULT_PYTHON_VERSION = "3.12";
3109
+ var allOptions = [
3110
+ {
3111
+ version: "3.14",
3112
+ pipPath: "pip3.14",
3113
+ pythonPath: "python3.14",
3114
+ runtime: "python3.14"
3115
+ },
3116
+ {
3117
+ version: "3.13",
3118
+ pipPath: "pip3.13",
3119
+ pythonPath: "python3.13",
3120
+ runtime: "python3.13"
3121
+ },
3122
+ {
3123
+ version: "3.12",
3124
+ pipPath: "pip3.12",
3125
+ pythonPath: "python3.12",
3126
+ runtime: "python3.12"
3127
+ },
3128
+ {
3129
+ version: "3.11",
3130
+ pipPath: "pip3.11",
3131
+ pythonPath: "python3.11",
3132
+ runtime: "python3.11"
3133
+ },
3134
+ {
3135
+ version: "3.10",
3136
+ pipPath: "pip3.10",
3137
+ pythonPath: "python3.10",
3138
+ runtime: "python3.10"
3139
+ },
3140
+ {
3141
+ version: "3.9",
3142
+ pipPath: "pip3.9",
3143
+ pythonPath: "python3.9",
3144
+ runtime: "python3.9"
3145
+ },
3146
+ {
3147
+ version: "3.6",
3148
+ pipPath: "pip3.6",
3149
+ pythonPath: "python3.6",
3150
+ runtime: "python3.6",
3151
+ discontinueDate: /* @__PURE__ */ new Date("2022-07-18")
3152
+ }
3153
+ ];
3154
+ function getDevPythonVersion() {
3155
+ return {
3156
+ version: "3",
3157
+ pipPath: "pip3",
3158
+ pythonPath: "python3",
3159
+ runtime: "python3"
3160
+ };
3161
+ }
3162
+ function getDefaultPythonVersion({
3163
+ isDev
3164
+ }) {
3165
+ if (isDev) {
3166
+ return getDevPythonVersion();
3167
+ }
3168
+ const defaultOption = allOptions.find(
3169
+ (opt) => opt.version === DEFAULT_PYTHON_VERSION && isInstalled(opt)
3170
+ );
3171
+ if (defaultOption) {
3172
+ return defaultOption;
3173
+ }
3174
+ const selection = allOptions.find(isInstalled);
3175
+ if (!selection) {
3176
+ throw new import_build_utils3.NowBuildError({
3177
+ code: "PYTHON_NOT_FOUND",
3178
+ link: "https://vercel.link/python-version",
3179
+ message: `Unable to find any supported Python versions.`
3180
+ });
3181
+ }
3182
+ return selection;
3183
+ }
3184
+ function parseVersionTuple(input) {
3185
+ const cleaned = input.trim().replace(/\s+/g, "");
3186
+ const m = cleaned.match(/^(\d+)(?:\.(\d+))?/);
3187
+ if (!m)
3188
+ return null;
3189
+ const major = Number(m[1]);
3190
+ const minor = m[2] !== void 0 ? Number(m[2]) : 0;
3191
+ if (Number.isNaN(major) || Number.isNaN(minor))
3192
+ return null;
3193
+ return [major, minor];
3194
+ }
3195
+ function compareTuples(a, b) {
3196
+ if (a[0] !== b[0])
3197
+ return a[0] - b[0];
3198
+ return a[1] - b[1];
3199
+ }
3200
+ function parseSpecifier(spec) {
3201
+ const s = spec.trim();
3202
+ const m = s.match(
3203
+ /^(<=|>=|==|!=|~=|<|>)\s*([0-9]+(?:\.[0-9]+)?)(?:\.[0-9]+)?(?:\.\*)?$/
3204
+ ) || // Bare version like "3.11" or "3.11.4" -> implied ==
3205
+ s.match(/^()([0-9]+(?:\.[0-9]+)?)(?:\.[0-9]+)?(?:\.\*)?$/);
3206
+ if (!m)
3207
+ return null;
3208
+ const op = m[1] || "==";
3209
+ const vt = parseVersionTuple(m[2]);
3210
+ if (!vt)
3211
+ return null;
3212
+ return { op, ver: vt };
3213
+ }
3214
+ function satisfies(candidate, spec) {
3215
+ const cmp = compareTuples(candidate, spec.ver);
3216
+ switch (spec.op) {
3217
+ case "==":
3218
+ return cmp === 0;
3219
+ case "!=":
3220
+ return cmp !== 0;
3221
+ case "<":
3222
+ return cmp < 0;
3223
+ case "<=":
3224
+ return cmp <= 0;
3225
+ case ">":
3226
+ return cmp > 0;
3227
+ case ">=":
3228
+ return cmp >= 0;
3229
+ case "~=": {
3230
+ const lowerOk = cmp >= 0;
3231
+ const upper = [spec.ver[0], spec.ver[1] + 1];
3232
+ return lowerOk && compareTuples(candidate, upper) < 0;
3233
+ }
3234
+ default:
3235
+ return false;
3236
+ }
2826
3237
  }
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;
3238
+ function selectFromRequiresPython(expr) {
3239
+ const raw = expr.trim();
3240
+ if (!raw)
3241
+ return void 0;
3242
+ const parts = raw.split(",").map((p) => p.trim()).filter(Boolean);
3243
+ const specifiers = [];
3244
+ for (const p of parts) {
3245
+ const sp = parseSpecifier(p);
3246
+ if (sp)
3247
+ specifiers.push(sp);
2837
3248
  }
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);
3249
+ if (specifiers.length === 0) {
3250
+ return allOptions.find((o) => o.version === raw);
2847
3251
  }
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;
3252
+ const matches = allOptions.filter((opt) => {
3253
+ const vt = parseVersionTuple(opt.version);
3254
+ return specifiers.every((sp) => satisfies(vt, sp));
3255
+ });
3256
+ if (matches.length === 0)
3257
+ return void 0;
3258
+ const defaultMatch = matches.find(
3259
+ (opt) => opt.version === DEFAULT_PYTHON_VERSION && isInstalled(opt)
3260
+ );
3261
+ if (defaultMatch) {
3262
+ return defaultMatch;
2856
3263
  }
2857
- return false;
3264
+ const installedMatch = matches.find(isInstalled);
3265
+ return installedMatch ?? matches[0];
2858
3266
  }
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`);
3267
+ function getSupportedPythonVersion({
3268
+ isDev,
3269
+ declaredPythonVersion
3270
+ }) {
3271
+ if (isDev) {
3272
+ return getDevPythonVersion();
2865
3273
  }
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;
3274
+ let selection = getDefaultPythonVersion({ isDev: false });
3275
+ if (declaredPythonVersion) {
3276
+ const { version: version2, source } = declaredPythonVersion;
3277
+ let requested;
3278
+ if (source === "pyproject.toml" || source === ".python-version") {
3279
+ requested = selectFromRequiresPython(version2);
3280
+ } else {
3281
+ requested = allOptions.find((o) => o.version === version2);
3282
+ }
3283
+ if (requested) {
3284
+ if (isDiscontinued(requested)) {
3285
+ throw new import_build_utils3.NowBuildError({
3286
+ code: "BUILD_UTILS_PYTHON_VERSION_DISCONTINUED",
3287
+ link: "https://vercel.link/python-version",
3288
+ message: `Python version "${requested.version}" detected in ${source} is discontinued and must be upgraded.`
3289
+ });
3290
+ }
3291
+ if (isInstalled(requested)) {
3292
+ selection = requested;
3293
+ console.log(`Using Python ${selection.version} from ${source}`);
3294
+ } else {
3295
+ console.warn(
3296
+ `Warning: Python version "${version2}" detected in ${source} is not installed and will be ignored. https://vercel.link/python-version`
3297
+ );
3298
+ console.log(`Using python version: ${selection.version}`);
2881
3299
  }
3300
+ } else {
3301
+ console.warn(
3302
+ `Warning: Python version "${version2}" detected in ${source} is invalid and will be ignored. https://vercel.link/python-version`
3303
+ );
3304
+ console.log(`Using python version: ${selection.version}`);
2882
3305
  }
2883
- throw error;
3306
+ } else {
3307
+ console.log(
3308
+ `No Python version specified in .python-version, pyproject.toml, or Pipfile.lock. Using python version: ${selection.version}`
3309
+ );
2884
3310
  }
3311
+ if (isDiscontinued(selection)) {
3312
+ throw new import_build_utils3.NowBuildError({
3313
+ code: "BUILD_UTILS_PYTHON_VERSION_DISCONTINUED",
3314
+ link: "https://vercel.link/python-version",
3315
+ message: `Python version "${selection.version}" declared in project configuration is discontinued and must be upgraded.`
3316
+ });
3317
+ }
3318
+ if (selection.discontinueDate) {
3319
+ const d = selection.discontinueDate.toISOString().split("T")[0];
3320
+ const srcSuffix = declaredPythonVersion ? `detected in ${declaredPythonVersion.source}` : "selected by runtime";
3321
+ console.warn(
3322
+ `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`
3323
+ );
3324
+ }
3325
+ return selection;
2885
3326
  }
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);
3327
+ function isDiscontinued({ discontinueDate }) {
3328
+ const today = Date.now();
3329
+ return discontinueDate !== void 0 && discontinueDate.getTime() <= today;
3330
+ }
3331
+ var installedPythonsCache = null;
3332
+ function getInstalledPythons() {
3333
+ if (installedPythonsCache !== null) {
3334
+ return installedPythonsCache;
2894
3335
  }
2895
- if (fsFiles[file]) {
2896
- return workPath;
3336
+ const uvPath = findUvInPath();
3337
+ if (!uvPath) {
3338
+ throw new import_build_utils3.NowBuildError({
3339
+ code: "UV_ERROR",
3340
+ link: "https://vercel.link/python-version",
3341
+ message: "uv is required but was not found in PATH."
3342
+ });
3343
+ }
3344
+ const uv = new UvRunner(uvPath);
3345
+ installedPythonsCache = uv.listInstalledPythons();
3346
+ return installedPythonsCache;
3347
+ }
3348
+ function isInstalled({ version: version2 }) {
3349
+ try {
3350
+ const installed = getInstalledPythons();
3351
+ return installed.has(version2);
3352
+ } catch (err) {
3353
+ throw new import_build_utils3.NowBuildError({
3354
+ code: "UV_ERROR",
3355
+ link: "https://vercel.link/python-version",
3356
+ message: err instanceof Error ? err.message : String(err)
3357
+ });
2897
3358
  }
2898
- return null;
2899
3359
  }
2900
3360
 
2901
3361
  // src/install.ts
2902
- var isWin2 = process.platform === "win32";
2903
- var uvExec = isWin2 ? "uv.exe" : "uv";
3362
+ var isWin3 = process.platform === "win32";
2904
3363
  var makeDependencyCheckCode = (dependency) => `
2905
3364
  from importlib import util
2906
3365
  dep = '${dependency}'.replace('-', '_')
2907
3366
  spec = util.find_spec(dep)
2908
3367
  print(spec.origin)
2909
3368
  `;
2910
- async function isInstalled(pythonPath, dependency, cwd) {
3369
+ async function isInstalled2(pythonPath, dependency, cwd) {
2911
3370
  try {
2912
- const { stdout } = await (0, import_execa2.default)(
3371
+ const { stdout } = await (0, import_execa3.default)(
2913
3372
  pythonPath,
2914
3373
  ["-c", makeDependencyCheckCode(dependency)],
2915
3374
  {
2916
3375
  stdio: "pipe",
2917
3376
  cwd,
2918
- env: { ...process.env, PYTHONPATH: (0, import_path2.join)(cwd, resolveVendorDir()) }
3377
+ env: { ...process.env, PYTHONPATH: (0, import_path4.join)(cwd, resolveVendorDir()) }
2919
3378
  }
2920
3379
  );
2921
3380
  return stdout.startsWith(cwd);
@@ -2932,13 +3391,13 @@ pkg_resources.require(dependencies)
2932
3391
  `;
2933
3392
  async function areRequirementsInstalled(pythonPath, requirementsPath, cwd) {
2934
3393
  try {
2935
- await (0, import_execa2.default)(
3394
+ await (0, import_execa3.default)(
2936
3395
  pythonPath,
2937
3396
  ["-c", makeRequirementsCheckCode(requirementsPath)],
2938
3397
  {
2939
3398
  stdio: "pipe",
2940
3399
  cwd,
2941
- env: { ...process.env, PYTHONPATH: (0, import_path2.join)(cwd, resolveVendorDir()) }
3400
+ env: { ...process.env, PYTHONPATH: (0, import_path4.join)(cwd, resolveVendorDir()) }
2942
3401
  }
2943
3402
  );
2944
3403
  return true;
@@ -2946,24 +3405,6 @@ async function areRequirementsInstalled(pythonPath, requirementsPath, cwd) {
2946
3405
  return false;
2947
3406
  }
2948
3407
  }
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
3408
  async function getSitePackagesDirs(pythonBin) {
2968
3409
  const code = `
2969
3410
  import json
@@ -2975,14 +3416,14 @@ for key in ("purelib", "platlib"):
2975
3416
  paths.append(candidate)
2976
3417
  print(json.dumps(paths))
2977
3418
  `.trim();
2978
- const { stdout } = await (0, import_execa2.default)(pythonBin, ["-c", code]);
3419
+ const { stdout } = await (0, import_execa3.default)(pythonBin, ["-c", code]);
2979
3420
  try {
2980
3421
  const parsed = JSON.parse(stdout);
2981
3422
  if (Array.isArray(parsed)) {
2982
3423
  return parsed.filter((p) => typeof p === "string");
2983
3424
  }
2984
3425
  } catch (err) {
2985
- (0, import_build_utils2.debug)("Failed to parse site-packages output", err);
3426
+ (0, import_build_utils4.debug)("Failed to parse site-packages output", err);
2986
3427
  }
2987
3428
  return [];
2988
3429
  }
@@ -3033,26 +3474,26 @@ async function detectInstallSource({
3033
3474
  let manifestType = null;
3034
3475
  if (uvLockDir && pyprojectDir) {
3035
3476
  manifestType = "uv.lock";
3036
- manifestPath = (0, import_path2.join)(uvLockDir, "uv.lock");
3477
+ manifestPath = (0, import_path4.join)(uvLockDir, "uv.lock");
3037
3478
  } else if (pyprojectDir) {
3038
3479
  manifestType = "pyproject.toml";
3039
- manifestPath = (0, import_path2.join)(pyprojectDir, "pyproject.toml");
3480
+ manifestPath = (0, import_path4.join)(pyprojectDir, "pyproject.toml");
3040
3481
  } else if (pipfileLockDir) {
3041
3482
  manifestType = "Pipfile.lock";
3042
- manifestPath = (0, import_path2.join)(pipfileLockDir, "Pipfile.lock");
3483
+ manifestPath = (0, import_path4.join)(pipfileLockDir, "Pipfile.lock");
3043
3484
  } else if (pipfileDir) {
3044
3485
  manifestType = "Pipfile";
3045
- manifestPath = (0, import_path2.join)(pipfileDir, "Pipfile");
3486
+ manifestPath = (0, import_path4.join)(pipfileDir, "Pipfile");
3046
3487
  } else if (requirementsDir) {
3047
3488
  manifestType = "requirements.txt";
3048
- manifestPath = (0, import_path2.join)(requirementsDir, "requirements.txt");
3489
+ manifestPath = (0, import_path4.join)(requirementsDir, "requirements.txt");
3049
3490
  }
3050
3491
  let manifestContent;
3051
3492
  if (manifestPath) {
3052
3493
  try {
3053
- manifestContent = await import_fs2.default.promises.readFile(manifestPath, "utf8");
3494
+ manifestContent = await import_fs3.default.promises.readFile(manifestPath, "utf8");
3054
3495
  } catch (err) {
3055
- (0, import_build_utils2.debug)("Failed to read install manifest contents", err);
3496
+ (0, import_build_utils4.debug)("Failed to read install manifest contents", err);
3056
3497
  }
3057
3498
  }
3058
3499
  return { manifestPath, manifestType, manifestContent };
@@ -3062,7 +3503,7 @@ async function createPyprojectToml({
3062
3503
  pyprojectPath,
3063
3504
  dependencies
3064
3505
  }) {
3065
- const requiresPython = ">=3.12";
3506
+ const requiresPython = `~=${DEFAULT_PYTHON_VERSION}.0`;
3066
3507
  const depsToml = dependencies.length > 0 ? [
3067
3508
  "dependencies = [",
3068
3509
  ...dependencies.map((dep) => ` "${dep}",`),
@@ -3079,47 +3520,7 @@ async function createPyprojectToml({
3079
3520
  depsToml,
3080
3521
  ""
3081
3522
  ].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 });
3523
+ await import_fs3.default.promises.writeFile(pyprojectPath, content);
3123
3524
  }
3124
3525
  function getDependencyName(spec) {
3125
3526
  const match = spec.match(/^[A-Za-z0-9_.-]+/);
@@ -3131,10 +3532,10 @@ async function filterMissingRuntimeDependencies({
3131
3532
  }) {
3132
3533
  let declared = [];
3133
3534
  try {
3134
- const config = await (0, import_build_utils2.readConfigFile)(pyprojectPath);
3535
+ const config = await (0, import_build_utils4.readConfigFile)(pyprojectPath);
3135
3536
  declared = config?.project?.dependencies || [];
3136
3537
  } catch (err) {
3137
- (0, import_build_utils2.debug)("Failed to parse pyproject.toml when filtering runtime deps", err);
3538
+ (0, import_build_utils4.debug)("Failed to parse pyproject.toml when filtering runtime deps", err);
3138
3539
  }
3139
3540
  const declaredNames = new Set(declared.map(getDependencyName));
3140
3541
  return runtimeDependencies.filter((spec) => {
@@ -3143,12 +3544,12 @@ async function filterMissingRuntimeDependencies({
3143
3544
  });
3144
3545
  }
3145
3546
  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)) {
3547
+ const start = (0, import_path4.resolve)(startDir);
3548
+ const base = repoRootPath ? (0, import_path4.resolve)(repoRootPath) : void 0;
3549
+ for (const dir of (0, import_build_utils4.traverseUpDirectories)({ start, base })) {
3550
+ const lockPath = (0, import_path4.join)(dir, "uv.lock");
3551
+ const pyprojectPath = (0, import_path4.join)(dir, "pyproject.toml");
3552
+ if (import_fs3.default.existsSync(lockPath) && import_fs3.default.existsSync(pyprojectPath)) {
3152
3553
  return lockPath;
3153
3554
  }
3154
3555
  }
@@ -3161,11 +3562,12 @@ async function ensureUvProject({
3161
3562
  repoRootPath,
3162
3563
  pythonPath,
3163
3564
  pipPath,
3164
- uvPath,
3565
+ uv,
3165
3566
  venvPath,
3166
3567
  meta,
3167
3568
  runtimeDependencies
3168
3569
  }) {
3570
+ const uvPath = uv.getPath();
3169
3571
  const installInfo = await detectInstallSource({
3170
3572
  workPath,
3171
3573
  entryDirectory,
@@ -3179,9 +3581,9 @@ async function ensureUvProject({
3179
3581
  if (!manifestPath) {
3180
3582
  throw new Error("Expected uv.lock path to be resolved, but it was null");
3181
3583
  }
3182
- projectDir = (0, import_path2.dirname)(manifestPath);
3183
- pyprojectPath = (0, import_path2.join)(projectDir, "pyproject.toml");
3184
- if (!import_fs2.default.existsSync(pyprojectPath)) {
3584
+ projectDir = (0, import_path4.dirname)(manifestPath);
3585
+ pyprojectPath = (0, import_path4.join)(projectDir, "pyproject.toml");
3586
+ if (!import_fs3.default.existsSync(pyprojectPath)) {
3185
3587
  throw new Error(
3186
3588
  `Expected "pyproject.toml" next to "uv.lock" in "${projectDir}"`
3187
3589
  );
@@ -3194,14 +3596,14 @@ async function ensureUvProject({
3194
3596
  "Expected pyproject.toml path to be resolved, but it was null"
3195
3597
  );
3196
3598
  }
3197
- projectDir = (0, import_path2.dirname)(manifestPath);
3599
+ projectDir = (0, import_path4.dirname)(manifestPath);
3198
3600
  pyprojectPath = manifestPath;
3199
3601
  console.log("Installing required dependencies from pyproject.toml...");
3200
3602
  const workspaceLock = findUvLockUpwards(projectDir, repoRootPath);
3201
3603
  if (workspaceLock) {
3202
3604
  lockPath = workspaceLock;
3203
3605
  } else {
3204
- await uvLock({ projectDir, uvPath });
3606
+ await uv.lock(projectDir);
3205
3607
  }
3206
3608
  } else if (manifestType === "Pipfile.lock" || manifestType === "Pipfile") {
3207
3609
  if (!manifestPath) {
@@ -3209,7 +3611,7 @@ async function ensureUvProject({
3209
3611
  "Expected Pipfile/Pipfile.lock path to be resolved, but it was null"
3210
3612
  );
3211
3613
  }
3212
- projectDir = (0, import_path2.dirname)(manifestPath);
3614
+ projectDir = (0, import_path4.dirname)(manifestPath);
3213
3615
  console.log(`Installing required dependencies from ${manifestType}...`);
3214
3616
  const exportedReq = await exportRequirementsFromPipfile({
3215
3617
  pythonPath,
@@ -3218,18 +3620,17 @@ async function ensureUvProject({
3218
3620
  projectDir,
3219
3621
  meta
3220
3622
  });
3221
- pyprojectPath = (0, import_path2.join)(projectDir, "pyproject.toml");
3222
- if (!import_fs2.default.existsSync(pyprojectPath)) {
3623
+ pyprojectPath = (0, import_path4.join)(projectDir, "pyproject.toml");
3624
+ if (!import_fs3.default.existsSync(pyprojectPath)) {
3223
3625
  await createPyprojectToml({
3224
3626
  projectName: "app",
3225
3627
  pyprojectPath,
3226
3628
  dependencies: []
3227
3629
  });
3228
3630
  }
3229
- await uvAddFromFile({
3230
- projectDir,
3231
- uvPath,
3631
+ await uv.addFromFile({
3232
3632
  venvPath,
3633
+ projectDir,
3233
3634
  requirementsPath: exportedReq
3234
3635
  });
3235
3636
  } else if (manifestType === "requirements.txt") {
@@ -3238,27 +3639,26 @@ async function ensureUvProject({
3238
3639
  "Expected requirements.txt path to be resolved, but it was null"
3239
3640
  );
3240
3641
  }
3241
- projectDir = (0, import_path2.dirname)(manifestPath);
3242
- pyprojectPath = (0, import_path2.join)(projectDir, "pyproject.toml");
3642
+ projectDir = (0, import_path4.dirname)(manifestPath);
3643
+ pyprojectPath = (0, import_path4.join)(projectDir, "pyproject.toml");
3243
3644
  console.log(
3244
3645
  "Installing required dependencies from requirements.txt with uv..."
3245
3646
  );
3246
- if (!import_fs2.default.existsSync(pyprojectPath)) {
3647
+ if (!import_fs3.default.existsSync(pyprojectPath)) {
3247
3648
  await createPyprojectToml({
3248
3649
  projectName: "app",
3249
3650
  pyprojectPath,
3250
3651
  dependencies: []
3251
3652
  });
3252
3653
  }
3253
- await uvAddFromFile({
3254
- projectDir,
3255
- uvPath,
3654
+ await uv.addFromFile({
3256
3655
  venvPath,
3656
+ projectDir,
3257
3657
  requirementsPath: manifestPath
3258
3658
  });
3259
3659
  } else {
3260
3660
  projectDir = workPath;
3261
- pyprojectPath = (0, import_path2.join)(projectDir, "pyproject.toml");
3661
+ pyprojectPath = (0, import_path4.join)(projectDir, "pyproject.toml");
3262
3662
  console.log(
3263
3663
  "No Python manifest found; creating an empty pyproject.toml and uv.lock..."
3264
3664
  );
@@ -3267,7 +3667,7 @@ async function ensureUvProject({
3267
3667
  pyprojectPath,
3268
3668
  dependencies: []
3269
3669
  });
3270
- await uvLock({ projectDir, uvPath });
3670
+ await uv.lock(projectDir);
3271
3671
  }
3272
3672
  if (runtimeDependencies.length) {
3273
3673
  const missingRuntimeDeps = await filterMissingRuntimeDependencies({
@@ -3275,44 +3675,18 @@ async function ensureUvProject({
3275
3675
  runtimeDependencies
3276
3676
  });
3277
3677
  if (missingRuntimeDeps.length) {
3278
- await uvAddDependencies({
3279
- projectDir,
3280
- uvPath,
3678
+ await uv.addDependencies({
3281
3679
  venvPath,
3680
+ projectDir,
3282
3681
  dependencies: missingRuntimeDeps
3283
3682
  });
3284
3683
  }
3285
3684
  }
3286
- const resolvedLockPath = lockPath && import_fs2.default.existsSync(lockPath) ? lockPath : findUvLockUpwards(projectDir, repoRootPath) || (0, import_path2.join)(projectDir, "uv.lock");
3685
+ const resolvedLockPath = lockPath && import_fs3.default.existsSync(lockPath) ? lockPath : findUvLockUpwards(projectDir, repoRootPath) || (0, import_path4.join)(projectDir, "uv.lock");
3287
3686
  return { projectDir, pyprojectPath, lockPath: resolvedLockPath };
3288
3687
  }
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
3688
  async function pipInstall(pipPath, uvPath, workPath, args, targetDir) {
3315
- const target = targetDir ? (0, import_path2.join)(targetDir, resolveVendorDir()) : resolveVendorDir();
3689
+ const target = targetDir ? (0, import_path4.join)(targetDir, resolveVendorDir()) : resolveVendorDir();
3316
3690
  process.env.PIP_USER = "0";
3317
3691
  if (uvPath) {
3318
3692
  const uvArgs = [
@@ -3325,111 +3699,38 @@ async function pipInstall(pipPath, uvPath, workPath, args, targetDir) {
3325
3699
  ...filterUnsafeUvPipArgs(args)
3326
3700
  ];
3327
3701
  const prettyUv = `${uvPath} ${uvArgs.join(" ")}`;
3328
- (0, import_build_utils2.debug)(`Running "${prettyUv}"...`);
3702
+ (0, import_build_utils4.debug)(`Running "${prettyUv}"...`);
3329
3703
  try {
3330
- await (0, import_execa2.default)(uvPath, uvArgs, {
3704
+ await (0, import_execa3.default)(uvPath, uvArgs, {
3331
3705
  cwd: workPath,
3332
3706
  env: getProtectedUvEnv()
3333
3707
  });
3334
3708
  return;
3335
3709
  } catch (err) {
3336
3710
  console.log(`Failed to run "${prettyUv}", falling back to pip`);
3337
- (0, import_build_utils2.debug)(`error: ${err}`);
3711
+ (0, import_build_utils4.debug)(`error: ${err}`);
3338
3712
  }
3339
3713
  }
3340
3714
  const cmdArgs = [
3341
3715
  "install",
3342
3716
  "--disable-pip-version-check",
3343
3717
  "--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
- );
3718
+ "--no-cache-dir",
3719
+ "--target",
3720
+ target,
3721
+ ...args
3722
+ ];
3723
+ const pretty = `${pipPath} ${cmdArgs.join(" ")}`;
3724
+ (0, import_build_utils4.debug)(`Running "${pretty}"...`);
3725
+ try {
3726
+ await (0, import_execa3.default)(pipPath, cmdArgs, {
3727
+ cwd: workPath
3728
+ });
3422
3729
  } 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");
3730
+ console.log(`Failed to run "${pretty}"`);
3731
+ (0, import_build_utils4.debug)(`error: ${err}`);
3732
+ throw err;
3430
3733
  }
3431
- console.log(`Installed uv at "${resolvedUvBin}"`);
3432
- return resolvedUvBin;
3433
3734
  }
3434
3735
  async function installRequirement({
3435
3736
  pythonPath,
@@ -3443,8 +3744,8 @@ async function installRequirement({
3443
3744
  args = []
3444
3745
  }) {
3445
3746
  const actualTargetDir = targetDir || workPath;
3446
- if (meta.isDev && await isInstalled(pythonPath, dependency, actualTargetDir)) {
3447
- (0, import_build_utils2.debug)(
3747
+ if (meta.isDev && await isInstalled2(pythonPath, dependency, actualTargetDir)) {
3748
+ (0, import_build_utils4.debug)(
3448
3749
  `Skipping ${dependency} dependency installation, already installed in ${actualTargetDir}`
3449
3750
  );
3450
3751
  return;
@@ -3464,7 +3765,7 @@ async function installRequirementsFile({
3464
3765
  }) {
3465
3766
  const actualTargetDir = targetDir || workPath;
3466
3767
  if (meta.isDev && await areRequirementsInstalled(pythonPath, filePath, actualTargetDir)) {
3467
- (0, import_build_utils2.debug)(`Skipping requirements file installation, already installed`);
3768
+ (0, import_build_utils4.debug)(`Skipping requirements file installation, already installed`);
3468
3769
  return;
3469
3770
  }
3470
3771
  await pipInstall(
@@ -3475,9 +3776,6 @@ async function installRequirementsFile({
3475
3776
  targetDir
3476
3777
  );
3477
3778
  }
3478
- function filterUnsafeUvPipArgs(args) {
3479
- return args.filter((arg) => arg !== "--no-warn-script-location");
3480
- }
3481
3779
  async function exportRequirementsFromPipfile({
3482
3780
  pythonPath,
3483
3781
  pipPath,
@@ -3485,8 +3783,8 @@ async function exportRequirementsFromPipfile({
3485
3783
  projectDir,
3486
3784
  meta
3487
3785
  }) {
3488
- const tempDir = await import_fs2.default.promises.mkdtemp(
3489
- (0, import_path2.join)(import_os.default.tmpdir(), "vercel-pipenv-")
3786
+ const tempDir = await import_fs3.default.promises.mkdtemp(
3787
+ (0, import_path4.join)(import_os2.default.tmpdir(), "vercel-pipenv-")
3490
3788
  );
3491
3789
  await installRequirement({
3492
3790
  pythonPath,
@@ -3498,12 +3796,12 @@ async function exportRequirementsFromPipfile({
3498
3796
  args: ["--no-warn-script-location"],
3499
3797
  uvPath
3500
3798
  });
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}...`);
3799
+ const tempVendorDir = (0, import_path4.join)(tempDir, resolveVendorDir());
3800
+ const convertCmd = isWin3 ? (0, import_path4.join)(tempVendorDir, "Scripts", "pipfile2req.exe") : (0, import_path4.join)(tempVendorDir, "bin", "pipfile2req");
3801
+ (0, import_build_utils4.debug)(`Running "${convertCmd}" in ${projectDir}...`);
3504
3802
  let stdout;
3505
3803
  try {
3506
- const { stdout: out } = await (0, import_execa2.default)(convertCmd, [], {
3804
+ const { stdout: out } = await (0, import_execa3.default)(convertCmd, [], {
3507
3805
  cwd: projectDir,
3508
3806
  env: { ...process.env, PYTHONPATH: tempVendorDir }
3509
3807
  });
@@ -3513,9 +3811,9 @@ async function exportRequirementsFromPipfile({
3513
3811
  `Failed to run "${convertCmd}": ${err instanceof Error ? err.message : String(err)}`
3514
3812
  );
3515
3813
  }
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}`);
3814
+ const outPath = (0, import_path4.join)(tempDir, "requirements.pipenv.txt");
3815
+ await import_fs3.default.promises.writeFile(outPath, stdout);
3816
+ (0, import_build_utils4.debug)(`Exported pipfile requirements to ${outPath}`);
3519
3817
  return outPath;
3520
3818
  }
3521
3819
  async function mirrorSitePackagesIntoVendor({
@@ -3526,19 +3824,19 @@ async function mirrorSitePackagesIntoVendor({
3526
3824
  try {
3527
3825
  const sitePackageDirs = await getVenvSitePackagesDirs(venvPath);
3528
3826
  for (const dir of sitePackageDirs) {
3529
- if (!import_fs2.default.existsSync(dir))
3827
+ if (!import_fs3.default.existsSync(dir))
3530
3828
  continue;
3531
- const dirFiles = await (0, import_build_utils2.glob)("**", dir);
3829
+ const dirFiles = await (0, import_build_utils4.glob)("**", dir);
3532
3830
  for (const relativePath of Object.keys(dirFiles)) {
3533
3831
  if (relativePath.endsWith(".pyc") || relativePath.includes("__pycache__")) {
3534
3832
  continue;
3535
3833
  }
3536
- const srcFsPath = (0, import_path2.join)(dir, relativePath);
3537
- const bundlePath = (0, import_path2.join)(vendorDirName, relativePath).replace(
3834
+ const srcFsPath = (0, import_path4.join)(dir, relativePath);
3835
+ const bundlePath = (0, import_path4.join)(vendorDirName, relativePath).replace(
3538
3836
  /\\/g,
3539
3837
  "/"
3540
3838
  );
3541
- vendorFiles[bundlePath] = new import_build_utils2.FileFsRef({ fsPath: srcFsPath });
3839
+ vendorFiles[bundlePath] = new import_build_utils4.FileFsRef({ fsPath: srcFsPath });
3542
3840
  }
3543
3841
  }
3544
3842
  } catch (err) {
@@ -3549,244 +3847,18 @@ async function mirrorSitePackagesIntoVendor({
3549
3847
  }
3550
3848
 
3551
3849
  // 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
- }
3850
+ var import_build_utils9 = require("@vercel/build-utils");
3779
3851
 
3780
3852
  // 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");
3853
+ var import_child_process2 = require("child_process");
3854
+ var import_fs4 = require("fs");
3855
+ var import_path6 = require("path");
3856
+ var import_build_utils7 = require("@vercel/build-utils");
3785
3857
 
3786
3858
  // src/entrypoint.ts
3787
- var import_path3 = require("path");
3788
- var import_build_utils4 = require("@vercel/build-utils");
3859
+ var import_path5 = require("path");
3789
3860
  var import_build_utils5 = require("@vercel/build-utils");
3861
+ var import_build_utils6 = require("@vercel/build-utils");
3790
3862
  var PYTHON_ENTRYPOINT_FILENAMES = [
3791
3863
  "app",
3792
3864
  "index",
@@ -3798,11 +3870,11 @@ var PYTHON_ENTRYPOINT_FILENAMES = [
3798
3870
  var PYTHON_ENTRYPOINT_DIRS = ["", "src", "app", "api"];
3799
3871
  var PYTHON_CANDIDATE_ENTRYPOINTS = PYTHON_ENTRYPOINT_FILENAMES.flatMap(
3800
3872
  (filename) => PYTHON_ENTRYPOINT_DIRS.map(
3801
- (dir) => import_path3.posix.join(dir, `${filename}.py`)
3873
+ (dir) => import_path5.posix.join(dir, `${filename}.py`)
3802
3874
  )
3803
3875
  );
3804
3876
  async function getPyprojectEntrypoint(workPath) {
3805
- const pyprojectData = await (0, import_build_utils5.readConfigFile)((0, import_path3.join)(workPath, "pyproject.toml"));
3877
+ const pyprojectData = await (0, import_build_utils6.readConfigFile)((0, import_path5.join)(workPath, "pyproject.toml"));
3806
3878
  if (!pyprojectData)
3807
3879
  return null;
3808
3880
  const scripts = pyprojectData.project?.scripts;
@@ -3815,7 +3887,7 @@ async function getPyprojectEntrypoint(workPath) {
3815
3887
  const modulePath = match[1];
3816
3888
  const relPath = modulePath.replace(/\./g, "/");
3817
3889
  try {
3818
- const fsFiles = await (0, import_build_utils4.glob)("**", workPath);
3890
+ const fsFiles = await (0, import_build_utils5.glob)("**", workPath);
3819
3891
  const candidates = [`${relPath}.py`, `${relPath}/__init__.py`];
3820
3892
  for (const candidate of candidates) {
3821
3893
  if (fsFiles[candidate])
@@ -3823,18 +3895,18 @@ async function getPyprojectEntrypoint(workPath) {
3823
3895
  }
3824
3896
  return null;
3825
3897
  } catch {
3826
- (0, import_build_utils4.debug)("Failed to discover Python entrypoint from pyproject.toml");
3898
+ (0, import_build_utils5.debug)("Failed to discover Python entrypoint from pyproject.toml");
3827
3899
  return null;
3828
3900
  }
3829
3901
  }
3830
3902
  async function detectGenericPythonEntrypoint(workPath, configuredEntrypoint) {
3831
3903
  const entry = configuredEntrypoint.endsWith(".py") ? configuredEntrypoint : `${configuredEntrypoint}.py`;
3832
3904
  try {
3833
- const fsFiles = await (0, import_build_utils4.glob)("**", workPath);
3905
+ const fsFiles = await (0, import_build_utils5.glob)("**", workPath);
3834
3906
  if (fsFiles[entry]) {
3835
- const isValid = await (0, import_build_utils4.isPythonEntrypoint)(fsFiles[entry]);
3907
+ const isValid = await (0, import_build_utils5.isPythonEntrypoint)(fsFiles[entry]);
3836
3908
  if (isValid) {
3837
- (0, import_build_utils4.debug)(`Using configured Python entrypoint: ${entry}`);
3909
+ (0, import_build_utils5.debug)(`Using configured Python entrypoint: ${entry}`);
3838
3910
  return entry;
3839
3911
  }
3840
3912
  }
@@ -3842,15 +3914,15 @@ async function detectGenericPythonEntrypoint(workPath, configuredEntrypoint) {
3842
3914
  (c) => !!fsFiles[c]
3843
3915
  );
3844
3916
  for (const candidate of candidates) {
3845
- const isValid = await (0, import_build_utils4.isPythonEntrypoint)(fsFiles[candidate]);
3917
+ const isValid = await (0, import_build_utils5.isPythonEntrypoint)(fsFiles[candidate]);
3846
3918
  if (isValid) {
3847
- (0, import_build_utils4.debug)(`Detected Python entrypoint: ${candidate}`);
3919
+ (0, import_build_utils5.debug)(`Detected Python entrypoint: ${candidate}`);
3848
3920
  return candidate;
3849
3921
  }
3850
3922
  }
3851
3923
  return null;
3852
3924
  } catch {
3853
- (0, import_build_utils4.debug)("Failed to discover Python entrypoint");
3925
+ (0, import_build_utils5.debug)("Failed to discover Python entrypoint");
3854
3926
  return null;
3855
3927
  }
3856
3928
  }
@@ -3907,12 +3979,12 @@ function installGlobalCleanupHandlers() {
3907
3979
  try {
3908
3980
  process.kill(info.pid, "SIGTERM");
3909
3981
  } catch (err) {
3910
- (0, import_build_utils6.debug)(`Error sending SIGTERM to ${info.pid}: ${err}`);
3982
+ (0, import_build_utils7.debug)(`Error sending SIGTERM to ${info.pid}: ${err}`);
3911
3983
  }
3912
3984
  try {
3913
3985
  process.kill(info.pid, "SIGKILL");
3914
3986
  } catch (err) {
3915
- (0, import_build_utils6.debug)(`Error sending SIGKILL to ${info.pid}: ${err}`);
3987
+ (0, import_build_utils7.debug)(`Error sending SIGKILL to ${info.pid}: ${err}`);
3916
3988
  }
3917
3989
  PERSISTENT_SERVERS.delete(key);
3918
3990
  }
@@ -3920,7 +3992,7 @@ function installGlobalCleanupHandlers() {
3920
3992
  try {
3921
3993
  restoreWarnings();
3922
3994
  } catch (err) {
3923
- (0, import_build_utils6.debug)(`Error restoring warnings: ${err}`);
3995
+ (0, import_build_utils7.debug)(`Error restoring warnings: ${err}`);
3924
3996
  }
3925
3997
  restoreWarnings = null;
3926
3998
  }
@@ -3939,33 +4011,33 @@ function installGlobalCleanupHandlers() {
3939
4011
  }
3940
4012
  function createDevAsgiShim(workPath, modulePath) {
3941
4013
  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");
4014
+ const vercelPythonDir = (0, import_path6.join)(workPath, ".vercel", "python");
4015
+ (0, import_fs4.mkdirSync)(vercelPythonDir, { recursive: true });
4016
+ const shimPath = (0, import_path6.join)(vercelPythonDir, `${ASGI_SHIM_MODULE}.py`);
4017
+ const templatePath = (0, import_path6.join)(__dirname, "..", `${ASGI_SHIM_MODULE}.py`);
4018
+ const template = (0, import_fs4.readFileSync)(templatePath, "utf8");
3947
4019
  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}`);
4020
+ (0, import_fs4.writeFileSync)(shimPath, shimSource, "utf8");
4021
+ (0, import_build_utils7.debug)(`Prepared Python dev static shim at ${shimPath}`);
3950
4022
  return ASGI_SHIM_MODULE;
3951
4023
  } catch (err) {
3952
- (0, import_build_utils6.debug)(`Failed to prepare dev static shim: ${err?.message || err}`);
4024
+ (0, import_build_utils7.debug)(`Failed to prepare dev static shim: ${err?.message || err}`);
3953
4025
  return null;
3954
4026
  }
3955
4027
  }
3956
4028
  function createDevWsgiShim(workPath, modulePath) {
3957
4029
  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");
4030
+ const vercelPythonDir = (0, import_path6.join)(workPath, ".vercel", "python");
4031
+ (0, import_fs4.mkdirSync)(vercelPythonDir, { recursive: true });
4032
+ const shimPath = (0, import_path6.join)(vercelPythonDir, `${WSGI_SHIM_MODULE}.py`);
4033
+ const templatePath = (0, import_path6.join)(__dirname, "..", `${WSGI_SHIM_MODULE}.py`);
4034
+ const template = (0, import_fs4.readFileSync)(templatePath, "utf8");
3963
4035
  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}`);
4036
+ (0, import_fs4.writeFileSync)(shimPath, shimSource, "utf8");
4037
+ (0, import_build_utils7.debug)(`Prepared Python dev WSGI shim at ${shimPath}`);
3966
4038
  return WSGI_SHIM_MODULE;
3967
4039
  } catch (err) {
3968
- (0, import_build_utils6.debug)(`Failed to prepare dev WSGI shim: ${err?.message || err}`);
4040
+ (0, import_build_utils7.debug)(`Failed to prepare dev WSGI shim: ${err?.message || err}`);
3969
4041
  return null;
3970
4042
  }
3971
4043
  }
@@ -3985,7 +4057,7 @@ var startDevServer = async (opts) => {
3985
4057
  );
3986
4058
  if (!entry) {
3987
4059
  const searched = PYTHON_CANDIDATE_ENTRYPOINTS.join(", ");
3988
- throw new import_build_utils6.NowBuildError({
4060
+ throw new import_build_utils7.NowBuildError({
3989
4061
  code: "PYTHON_ENTRYPOINT_NOT_FOUND",
3990
4062
  message: `No ${framework} entrypoint found. Add an 'app' script in pyproject.toml or define an entrypoint in one of: ${searched}.`,
3991
4063
  link: `https://vercel.com/docs/frameworks/backend/${framework?.toLowerCase()}#exporting-the-${framework?.toLowerCase()}-application`,
@@ -4031,11 +4103,11 @@ var startDevServer = async (opts) => {
4031
4103
  try {
4032
4104
  await new Promise((resolve2, reject) => {
4033
4105
  let resolved = false;
4034
- const { pythonPath: systemPython } = getLatestPythonVersion(meta);
4106
+ const { pythonPath: systemPython } = getDefaultPythonVersion(meta);
4035
4107
  let pythonCmd = systemPython;
4036
4108
  const venv = isInVirtualEnv();
4037
4109
  if (venv) {
4038
- (0, import_build_utils6.debug)(`Running in virtualenv at ${venv}`);
4110
+ (0, import_build_utils7.debug)(`Running in virtualenv at ${venv}`);
4039
4111
  } else {
4040
4112
  const { pythonCmd: venvPythonCmd, venvRoot } = useVirtualEnv(
4041
4113
  workPath,
@@ -4044,9 +4116,9 @@ var startDevServer = async (opts) => {
4044
4116
  );
4045
4117
  pythonCmd = venvPythonCmd;
4046
4118
  if (venvRoot) {
4047
- (0, import_build_utils6.debug)(`Using virtualenv at ${venvRoot}`);
4119
+ (0, import_build_utils7.debug)(`Using virtualenv at ${venvRoot}`);
4048
4120
  } else {
4049
- (0, import_build_utils6.debug)("No virtualenv found");
4121
+ (0, import_build_utils7.debug)("No virtualenv found");
4050
4122
  try {
4051
4123
  const yellow = "\x1B[33m";
4052
4124
  const reset = "\x1B[0m";
@@ -4063,16 +4135,16 @@ If you are using a virtual environment, activate it before running "vercel dev",
4063
4135
  if (framework !== "flask") {
4064
4136
  const devShimModule = createDevAsgiShim(workPath, modulePath);
4065
4137
  if (devShimModule) {
4066
- const vercelPythonDir = (0, import_path4.join)(workPath, ".vercel", "python");
4138
+ const vercelPythonDir = (0, import_path6.join)(workPath, ".vercel", "python");
4067
4139
  const existingPythonPath = env.PYTHONPATH || "";
4068
4140
  env.PYTHONPATH = existingPythonPath ? `${vercelPythonDir}:${existingPythonPath}` : vercelPythonDir;
4069
4141
  }
4070
4142
  const moduleToRun = devShimModule || modulePath;
4071
4143
  const argv = ["-u", "-m", moduleToRun];
4072
- (0, import_build_utils6.debug)(
4144
+ (0, import_build_utils7.debug)(
4073
4145
  `Starting ASGI dev server (${framework}): ${pythonCmd} ${argv.join(" ")}`
4074
4146
  );
4075
- const child = (0, import_child_process.spawn)(pythonCmd, argv, {
4147
+ const child = (0, import_child_process2.spawn)(pythonCmd, argv, {
4076
4148
  cwd: workPath,
4077
4149
  env,
4078
4150
  stdio: ["inherit", "pipe", "pipe"]
@@ -4143,14 +4215,14 @@ If you are using a virtual environment, activate it before running "vercel dev",
4143
4215
  } else {
4144
4216
  const devShimModule = createDevWsgiShim(workPath, modulePath);
4145
4217
  if (devShimModule) {
4146
- const vercelPythonDir = (0, import_path4.join)(workPath, ".vercel", "python");
4218
+ const vercelPythonDir = (0, import_path6.join)(workPath, ".vercel", "python");
4147
4219
  const existingPythonPath = env.PYTHONPATH || "";
4148
4220
  env.PYTHONPATH = existingPythonPath ? `${vercelPythonDir}:${existingPythonPath}` : vercelPythonDir;
4149
4221
  }
4150
4222
  const moduleToRun = devShimModule || modulePath;
4151
4223
  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, {
4224
+ (0, import_build_utils7.debug)(`Starting Flask dev server: ${pythonCmd} ${argv.join(" ")}`);
4225
+ const child = (0, import_child_process2.spawn)(pythonCmd, argv, {
4154
4226
  cwd: workPath,
4155
4227
  env,
4156
4228
  stdio: ["inherit", "pipe", "pipe"]
@@ -4236,8 +4308,8 @@ If you are using a virtual environment, activate it before running "vercel dev",
4236
4308
  };
4237
4309
 
4238
4310
  // 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);
4311
+ var readFile = (0, import_util.promisify)(import_fs5.default.readFile);
4312
+ var writeFile = (0, import_util.promisify)(import_fs5.default.writeFile);
4241
4313
  var version = 3;
4242
4314
  async function downloadFilesInWorkPath({
4243
4315
  entrypoint,
@@ -4245,13 +4317,13 @@ async function downloadFilesInWorkPath({
4245
4317
  files,
4246
4318
  meta = {}
4247
4319
  }) {
4248
- (0, import_build_utils7.debug)("Downloading user files...");
4249
- let downloadedFiles = await (0, import_build_utils7.download)(files, workPath, meta);
4320
+ (0, import_build_utils8.debug)("Downloading user files...");
4321
+ let downloadedFiles = await (0, import_build_utils8.download)(files, workPath, meta);
4250
4322
  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);
4323
+ const { devCacheDir = (0, import_path7.join)(workPath, ".now", "cache") } = meta;
4324
+ const destCache = (0, import_path7.join)(devCacheDir, (0, import_path7.basename)(entrypoint, ".py"));
4325
+ await (0, import_build_utils8.download)(downloadedFiles, destCache);
4326
+ downloadedFiles = await (0, import_build_utils8.glob)("**", destCache);
4255
4327
  workPath = destCache;
4256
4328
  }
4257
4329
  return workPath;
@@ -4275,21 +4347,21 @@ var build = async ({
4275
4347
  });
4276
4348
  try {
4277
4349
  if (meta.isDev) {
4278
- const setupCfg = (0, import_path5.join)(workPath, "setup.cfg");
4350
+ const setupCfg = (0, import_path7.join)(workPath, "setup.cfg");
4279
4351
  await writeFile(setupCfg, "[install]\nprefix=\n");
4280
4352
  }
4281
4353
  } catch (err) {
4282
4354
  console.log('Failed to create "setup.cfg" file');
4283
4355
  throw err;
4284
4356
  }
4285
- if ((0, import_build_utils7.isPythonFramework)(framework)) {
4357
+ if ((0, import_build_utils8.isPythonFramework)(framework)) {
4286
4358
  const {
4287
4359
  cliType,
4288
4360
  lockfileVersion,
4289
4361
  packageJsonPackageManager,
4290
4362
  turboSupportsCorepackHome
4291
- } = await (0, import_build_utils7.scanParentDirs)(workPath, true);
4292
- spawnEnv = (0, import_build_utils7.getEnvForPackageManager)({
4363
+ } = await (0, import_build_utils8.scanParentDirs)(workPath, true);
4364
+ spawnEnv = (0, import_build_utils8.getEnvForPackageManager)({
4293
4365
  cliType,
4294
4366
  lockfileVersion,
4295
4367
  packageJsonPackageManager,
@@ -4310,7 +4382,7 @@ var build = async ({
4310
4382
  config?.buildCommand;
4311
4383
  if (projectBuildCommand) {
4312
4384
  console.log(`Running "${projectBuildCommand}"`);
4313
- await (0, import_build_utils7.execCommand)(projectBuildCommand, {
4385
+ await (0, import_build_utils8.execCommand)(projectBuildCommand, {
4314
4386
  env: spawnEnv,
4315
4387
  cwd: workPath
4316
4388
  });
@@ -4322,21 +4394,21 @@ var build = async ({
4322
4394
  );
4323
4395
  }
4324
4396
  }
4325
- let fsFiles = await (0, import_build_utils7.glob)("**", workPath);
4326
- if ((0, import_build_utils7.isPythonFramework)(framework) && (!fsFiles[entrypoint] || !entrypoint.endsWith(".py"))) {
4397
+ let fsFiles = await (0, import_build_utils8.glob)("**", workPath);
4398
+ if ((0, import_build_utils8.isPythonFramework)(framework) && (!fsFiles[entrypoint] || !entrypoint.endsWith(".py"))) {
4327
4399
  const detected = await detectPythonEntrypoint(
4328
4400
  config.framework,
4329
4401
  workPath,
4330
4402
  entrypoint
4331
4403
  );
4332
4404
  if (detected) {
4333
- (0, import_build_utils7.debug)(
4405
+ (0, import_build_utils8.debug)(
4334
4406
  `Resolved Python entrypoint to "${detected}" (configured "${entrypoint}" not found).`
4335
4407
  );
4336
4408
  entrypoint = detected;
4337
4409
  } else {
4338
4410
  const searchedList = PYTHON_CANDIDATE_ENTRYPOINTS.join(", ");
4339
- throw new import_build_utils7.NowBuildError({
4411
+ throw new import_build_utils8.NowBuildError({
4340
4412
  code: `${framework.toUpperCase()}_ENTRYPOINT_NOT_FOUND`,
4341
4413
  message: `No ${framework} entrypoint found. Add an 'app' script in pyproject.toml or define an entrypoint in one of: ${searchedList}.`,
4342
4414
  link: `https://vercel.com/docs/frameworks/backend/${framework}#exporting-the-${framework}-application`,
@@ -4344,7 +4416,7 @@ var build = async ({
4344
4416
  });
4345
4417
  }
4346
4418
  }
4347
- const entryDirectory = (0, import_path5.dirname)(entrypoint);
4419
+ const entryDirectory = (0, import_path7.dirname)(entrypoint);
4348
4420
  const pyprojectDir = findDir({
4349
4421
  file: "pyproject.toml",
4350
4422
  entryDirectory,
@@ -4357,29 +4429,51 @@ var build = async ({
4357
4429
  workPath,
4358
4430
  fsFiles
4359
4431
  });
4432
+ const pythonVersionFileDir = findDir({
4433
+ file: ".python-version",
4434
+ entryDirectory,
4435
+ workPath,
4436
+ fsFiles
4437
+ });
4360
4438
  let declaredPythonVersion;
4361
- if (pyprojectDir) {
4439
+ if (pythonVersionFileDir) {
4440
+ try {
4441
+ const content = await readFile(
4442
+ (0, import_path7.join)(pythonVersionFileDir, ".python-version"),
4443
+ "utf8"
4444
+ );
4445
+ const version2 = parsePythonVersionFile(content);
4446
+ if (version2) {
4447
+ declaredPythonVersion = { version: version2, source: ".python-version" };
4448
+ (0, import_build_utils8.debug)(`Found Python version ${version2} in .python-version`);
4449
+ }
4450
+ } catch (err) {
4451
+ (0, import_build_utils8.debug)("Failed to read .python-version file", err);
4452
+ }
4453
+ }
4454
+ if (!declaredPythonVersion && pyprojectDir) {
4362
4455
  let requiresPython;
4363
4456
  try {
4364
- const pyproject = await (0, import_build_utils8.readConfigFile)((0, import_path5.join)(pyprojectDir, "pyproject.toml"));
4457
+ const pyproject = await (0, import_build_utils9.readConfigFile)((0, import_path7.join)(pyprojectDir, "pyproject.toml"));
4365
4458
  requiresPython = pyproject?.project?.["requires-python"];
4366
4459
  } catch (err) {
4367
- (0, import_build_utils7.debug)("Failed to parse pyproject.toml", err);
4460
+ (0, import_build_utils8.debug)("Failed to parse pyproject.toml", err);
4368
4461
  }
4369
4462
  if (typeof requiresPython === "string" && requiresPython.trim()) {
4370
4463
  declaredPythonVersion = {
4371
4464
  version: requiresPython.trim(),
4372
4465
  source: "pyproject.toml"
4373
4466
  };
4374
- (0, import_build_utils7.debug)(`Found requires-python "${requiresPython}" in pyproject.toml`);
4467
+ (0, import_build_utils8.debug)(`Found requires-python "${requiresPython}" in pyproject.toml`);
4375
4468
  }
4376
- } else if (pipfileLockDir) {
4469
+ }
4470
+ if (!declaredPythonVersion && pipfileLockDir) {
4377
4471
  let lock = {};
4378
4472
  try {
4379
- const json = await readFile((0, import_path5.join)(pipfileLockDir, "Pipfile.lock"), "utf8");
4473
+ const json = await readFile((0, import_path7.join)(pipfileLockDir, "Pipfile.lock"), "utf8");
4380
4474
  lock = JSON.parse(json);
4381
4475
  } catch (err) {
4382
- throw new import_build_utils7.NowBuildError({
4476
+ throw new import_build_utils8.NowBuildError({
4383
4477
  code: "INVALID_PIPFILE_LOCK",
4384
4478
  message: "Unable to parse Pipfile.lock"
4385
4479
  });
@@ -4387,20 +4481,30 @@ var build = async ({
4387
4481
  const pyFromLock = lock?._meta?.requires?.python_version;
4388
4482
  if (pyFromLock) {
4389
4483
  declaredPythonVersion = { version: pyFromLock, source: "Pipfile.lock" };
4390
- (0, import_build_utils7.debug)(`Found Python version ${pyFromLock} in Pipfile.lock`);
4484
+ (0, import_build_utils8.debug)(`Found Python version ${pyFromLock} in Pipfile.lock`);
4391
4485
  }
4392
4486
  }
4393
4487
  const pythonVersion = getSupportedPythonVersion({
4394
4488
  isDev: meta.isDev,
4395
4489
  declaredPythonVersion
4396
4490
  });
4397
- fsFiles = await (0, import_build_utils7.glob)("**", workPath);
4398
- const venvPath = (0, import_path5.join)(workPath, ".vercel", "python", ".venv");
4491
+ const selectedVersionTuple = parseVersionTuple(pythonVersion.version);
4492
+ const defaultVersionTuple = parseVersionTuple(DEFAULT_PYTHON_VERSION);
4493
+ if (!pythonVersionFileDir && pyprojectDir && declaredPythonVersion?.source === "pyproject.toml" && selectedVersionTuple && defaultVersionTuple && compareTuples(selectedVersionTuple, defaultVersionTuple) <= 0) {
4494
+ const pythonVersionFilePath = (0, import_path7.join)(pyprojectDir, ".python-version");
4495
+ await writeFile(pythonVersionFilePath, `${pythonVersion.version}
4496
+ `);
4497
+ console.log(
4498
+ `Writing .python-version file with version ${pythonVersion.version}`
4499
+ );
4500
+ }
4501
+ fsFiles = await (0, import_build_utils8.glob)("**", workPath);
4502
+ const venvPath = (0, import_path7.join)(workPath, ".vercel", "python", ".venv");
4399
4503
  await ensureVenv({
4400
4504
  pythonPath: pythonVersion.pythonPath,
4401
4505
  venvPath
4402
4506
  });
4403
- const hasCustomInstallCommand = (0, import_build_utils7.isPythonFramework)(framework) && !!projectInstallCommand;
4507
+ const hasCustomInstallCommand = (0, import_build_utils8.isPythonFramework)(framework) && !!projectInstallCommand;
4404
4508
  let useRuntime = false;
4405
4509
  if (hasCustomInstallCommand) {
4406
4510
  const baseEnv = spawnEnv || process.env;
@@ -4408,13 +4512,13 @@ var build = async ({
4408
4512
  pythonEnv.VERCEL_PYTHON_VENV_PATH = venvPath;
4409
4513
  const installCommand = projectInstallCommand;
4410
4514
  console.log(`Running "install" command: \`${installCommand}\`...`);
4411
- await (0, import_build_utils7.execCommand)(installCommand, {
4515
+ await (0, import_build_utils8.execCommand)(installCommand, {
4412
4516
  env: pythonEnv,
4413
4517
  cwd: workPath
4414
4518
  });
4415
4519
  } else {
4416
4520
  let ranPyprojectInstall = false;
4417
- if ((0, import_build_utils7.isPythonFramework)(framework)) {
4521
+ if ((0, import_build_utils8.isPythonFramework)(framework)) {
4418
4522
  const baseEnv = spawnEnv || process.env;
4419
4523
  const pythonEnv = createVenvEnv(venvPath, baseEnv);
4420
4524
  pythonEnv.VERCEL_PYTHON_VENV_PATH = venvPath;
@@ -4427,10 +4531,11 @@ var build = async ({
4427
4531
  );
4428
4532
  }
4429
4533
  if (!ranPyprojectInstall) {
4430
- let uvPath;
4534
+ let uv;
4431
4535
  try {
4432
- uvPath = await getUvBinaryOrInstall(pythonVersion.pythonPath);
4536
+ const uvPath = await getUvBinaryOrInstall(pythonVersion.pythonPath);
4433
4537
  console.log(`Using uv at "${uvPath}"`);
4538
+ uv = new UvRunner(uvPath);
4434
4539
  } catch (err) {
4435
4540
  console.log("Failed to install or locate uv");
4436
4541
  throw new Error(
@@ -4456,25 +4561,24 @@ var build = async ({
4456
4561
  repoRootPath,
4457
4562
  pythonPath: pythonVersion.pythonPath,
4458
4563
  pipPath: pythonVersion.pipPath,
4459
- uvPath,
4564
+ uv,
4460
4565
  venvPath,
4461
4566
  meta,
4462
4567
  runtimeDependencies
4463
4568
  });
4464
- await runUvSync({
4465
- uvPath,
4569
+ await uv.sync({
4466
4570
  venvPath,
4467
4571
  projectDir,
4468
4572
  locked: true
4469
4573
  });
4470
4574
  }
4471
4575
  }
4472
- (0, import_build_utils7.debug)("Entrypoint is", entrypoint);
4576
+ (0, import_build_utils8.debug)("Entrypoint is", entrypoint);
4473
4577
  const moduleName = entrypoint.replace(/\//g, ".").replace(/\.py$/i, "");
4474
4578
  const vendorDir = resolveVendorDir();
4475
4579
  const suffix = meta.isDev && !entrypoint.endsWith(".py") ? ".py" : "";
4476
4580
  const entrypointWithSuffix = `${entrypoint}${suffix}`;
4477
- (0, import_build_utils7.debug)("Entrypoint with suffix is", entrypointWithSuffix);
4581
+ (0, import_build_utils8.debug)("Entrypoint with suffix is", entrypointWithSuffix);
4478
4582
  let handlerPyContents;
4479
4583
  if (useRuntime) {
4480
4584
  handlerPyContents = `
@@ -4516,7 +4620,7 @@ if os.path.isdir(_vendor):
4516
4620
  from vercel_runtime.vc_init import vc_handler
4517
4621
  `;
4518
4622
  } else {
4519
- const originalPyPath = (0, import_path5.join)(__dirname, "..", "vc_init.py");
4623
+ const originalPyPath = (0, import_path7.join)(__dirname, "..", "vc_init.py");
4520
4624
  const originalHandlerPyContents = await readFile(originalPyPath, "utf8");
4521
4625
  handlerPyContents = originalHandlerPyContents.replace(/__VC_HANDLER_MODULE_NAME/g, moduleName).replace(/__VC_HANDLER_ENTRYPOINT/g, entrypointWithSuffix).replace(/__VC_HANDLER_VENDOR_DIR/g, vendorDir);
4522
4626
  }
@@ -4544,7 +4648,7 @@ from vercel_runtime.vc_init import vc_handler
4544
4648
  cwd: workPath,
4545
4649
  ignore: config && typeof config.excludeFiles === "string" ? [...predefinedExcludes, config.excludeFiles] : predefinedExcludes
4546
4650
  };
4547
- const files = await (0, import_build_utils7.glob)("**", globOptions);
4651
+ const files = await (0, import_build_utils8.glob)("**", globOptions);
4548
4652
  const vendorFiles = await mirrorSitePackagesIntoVendor({
4549
4653
  venvPath,
4550
4654
  vendorDirName: vendorDir
@@ -4553,12 +4657,12 @@ from vercel_runtime.vc_init import vc_handler
4553
4657
  files[p] = f;
4554
4658
  }
4555
4659
  const handlerPyFilename = "vc__handler__python";
4556
- files[`${handlerPyFilename}.py`] = new import_build_utils7.FileBlob({ data: handlerPyContents });
4660
+ files[`${handlerPyFilename}.py`] = new import_build_utils8.FileBlob({ data: handlerPyContents });
4557
4661
  if (config.framework === "fasthtml") {
4558
4662
  const { SESSKEY = "" } = process.env;
4559
- files[".sesskey"] = new import_build_utils7.FileBlob({ data: `"${SESSKEY}"` });
4663
+ files[".sesskey"] = new import_build_utils8.FileBlob({ data: `"${SESSKEY}"` });
4560
4664
  }
4561
- const output = new import_build_utils7.Lambda({
4665
+ const output = new import_build_utils8.Lambda({
4562
4666
  files,
4563
4667
  handler: `${handlerPyFilename}.vc_handler`,
4564
4668
  runtime: pythonVersion.runtime,
@@ -4594,7 +4698,7 @@ var defaultShouldServe = ({
4594
4698
  if (entrypoint === requestPath && hasProp(files, entrypoint)) {
4595
4699
  return true;
4596
4700
  }
4597
- const { dir, name } = (0, import_path5.parse)(entrypoint);
4701
+ const { dir, name } = (0, import_path7.parse)(entrypoint);
4598
4702
  if (name === "index" && dir === requestPath && hasProp(files, entrypoint)) {
4599
4703
  return true;
4600
4704
  }
@@ -4603,6 +4707,16 @@ var defaultShouldServe = ({
4603
4707
  function hasProp(obj, key) {
4604
4708
  return Object.hasOwnProperty.call(obj, key);
4605
4709
  }
4710
+ function parsePythonVersionFile(content) {
4711
+ const lines = content.split("\n");
4712
+ for (const line of lines) {
4713
+ const trimmed = line.trim();
4714
+ if (!trimmed || trimmed.startsWith("#"))
4715
+ continue;
4716
+ return trimmed;
4717
+ }
4718
+ return void 0;
4719
+ }
4606
4720
  // Annotate the CommonJS export names for ESM import in node:
4607
4721
  0 && (module.exports = {
4608
4722
  build,