@vercel/python 6.39.0 → 6.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +169 -89
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -4341,6 +4341,11 @@ var PythonDependencyExternalizer = class {
|
|
|
4341
4341
|
this.allVendorFiles = {};
|
|
4342
4342
|
this.totalBundleSize = 0;
|
|
4343
4343
|
this.analyzed = false;
|
|
4344
|
+
// Resolved once at the start of analyze(). The venv is immutable
|
|
4345
|
+
// after construction (quirks run before the bundle span) so these
|
|
4346
|
+
// do not change between analyze() and generateBundle().
|
|
4347
|
+
this.sitePackageDirs = null;
|
|
4348
|
+
this.distributions = null;
|
|
4344
4349
|
this.venvPath = options.venvPath;
|
|
4345
4350
|
this.vendorDir = options.vendorDir;
|
|
4346
4351
|
this.workPath = options.workPath;
|
|
@@ -4371,8 +4376,17 @@ var PythonDependencyExternalizer = class {
|
|
|
4371
4376
|
* Must be called before generateBundle().
|
|
4372
4377
|
*/
|
|
4373
4378
|
async analyze(files) {
|
|
4374
|
-
this.
|
|
4375
|
-
|
|
4379
|
+
this.sitePackageDirs = await getVenvSitePackagesDirs(this.venvPath);
|
|
4380
|
+
this.distributions = /* @__PURE__ */ new Map();
|
|
4381
|
+
for (const dir of this.sitePackageDirs) {
|
|
4382
|
+
try {
|
|
4383
|
+
await import_fs5.default.promises.access(dir);
|
|
4384
|
+
} catch {
|
|
4385
|
+
continue;
|
|
4386
|
+
}
|
|
4387
|
+
this.distributions.set(dir, await (0, import_python_analysis3.scanDistributions)(dir));
|
|
4388
|
+
}
|
|
4389
|
+
this.allVendorFiles = await this.mirrorPackagesIntoVendor({
|
|
4376
4390
|
vendorDirName: this.vendorDir
|
|
4377
4391
|
});
|
|
4378
4392
|
const tempFilesForSizing = { ...files };
|
|
@@ -4542,7 +4556,7 @@ To fix this, either:
|
|
|
4542
4556
|
wheels available.`
|
|
4543
4557
|
});
|
|
4544
4558
|
}
|
|
4545
|
-
const packageSizes = await calculatePerPackageSizes(
|
|
4559
|
+
const packageSizes = await this.calculatePerPackageSizes();
|
|
4546
4560
|
const alwaysBundled = [
|
|
4547
4561
|
...classification.privatePackages,
|
|
4548
4562
|
"vercel-runtime",
|
|
@@ -4550,8 +4564,7 @@ To fix this, either:
|
|
|
4550
4564
|
...this.alwaysBundlePackages,
|
|
4551
4565
|
...forceBundledDueToWheels
|
|
4552
4566
|
];
|
|
4553
|
-
const alwaysBundledFiles = await mirrorPackagesIntoVendor({
|
|
4554
|
-
venvPath: this.venvPath,
|
|
4567
|
+
const alwaysBundledFiles = await this.mirrorPackagesIntoVendor({
|
|
4555
4568
|
vendorDirName: this.vendorDir,
|
|
4556
4569
|
includePackages: alwaysBundled
|
|
4557
4570
|
});
|
|
@@ -4597,8 +4610,7 @@ To fix this, either:
|
|
|
4597
4610
|
);
|
|
4598
4611
|
const bundledPublic = lambdaKnapsack(publicPackageSizes, remainingCapacity);
|
|
4599
4612
|
const allBundledPackages = [...alwaysBundled, ...bundledPublic];
|
|
4600
|
-
const selectedVendorFiles = await mirrorPackagesIntoVendor({
|
|
4601
|
-
venvPath: this.venvPath,
|
|
4613
|
+
const selectedVendorFiles = await this.mirrorPackagesIntoVendor({
|
|
4602
4614
|
vendorDirName: this.vendorDir,
|
|
4603
4615
|
includePackages: allBundledPackages
|
|
4604
4616
|
});
|
|
@@ -4747,6 +4759,130 @@ splitting your application.`,
|
|
|
4747
4759
|
}
|
|
4748
4760
|
return incompatible;
|
|
4749
4761
|
}
|
|
4762
|
+
/**
|
|
4763
|
+
* Mirror packages from site-packages into the _vendor directory.
|
|
4764
|
+
*
|
|
4765
|
+
* When `includePackages` is provided, only distributions whose normalized
|
|
4766
|
+
* name is in the list are included. When omitted, every distribution is
|
|
4767
|
+
* included.
|
|
4768
|
+
*
|
|
4769
|
+
* Reads `this.sitePackageDirs` and `this.distributions` which are
|
|
4770
|
+
* resolved once at the start of `analyze()`.
|
|
4771
|
+
*/
|
|
4772
|
+
async mirrorPackagesIntoVendor({
|
|
4773
|
+
vendorDirName,
|
|
4774
|
+
includePackages
|
|
4775
|
+
}) {
|
|
4776
|
+
const vendorFiles = {};
|
|
4777
|
+
if (includePackages && includePackages.length === 0) {
|
|
4778
|
+
return vendorFiles;
|
|
4779
|
+
}
|
|
4780
|
+
const includeSet = includePackages ? new Set(includePackages.map(import_python_analysis3.normalizePackageName)) : null;
|
|
4781
|
+
const pending = [];
|
|
4782
|
+
for (const dir of this.sitePackageDirs) {
|
|
4783
|
+
const dirDistributions = this.distributions.get(dir);
|
|
4784
|
+
if (!dirDistributions)
|
|
4785
|
+
continue;
|
|
4786
|
+
const resolvedDir = (0, import_path6.resolve)(dir);
|
|
4787
|
+
const dirPrefix = resolvedDir + import_path6.sep;
|
|
4788
|
+
for (const [name, dist] of dirDistributions) {
|
|
4789
|
+
if (includeSet && !includeSet.has(name))
|
|
4790
|
+
continue;
|
|
4791
|
+
for (const { path: rawPath, size: recordSize } of dist.files) {
|
|
4792
|
+
const filePath = rawPath.replaceAll("/", import_path6.sep);
|
|
4793
|
+
if (!(0, import_path6.resolve)(resolvedDir, filePath).startsWith(dirPrefix)) {
|
|
4794
|
+
continue;
|
|
4795
|
+
}
|
|
4796
|
+
if (filePath.endsWith(".pyc") || filePath.split(import_path6.sep).includes("__pycache__")) {
|
|
4797
|
+
continue;
|
|
4798
|
+
}
|
|
4799
|
+
const srcFsPath = (0, import_path6.join)(dir, filePath);
|
|
4800
|
+
const bundlePath = (0, import_path6.join)(vendorDirName, filePath).replace(/\\/g, "/");
|
|
4801
|
+
pending.push({
|
|
4802
|
+
bundlePath,
|
|
4803
|
+
srcFsPath,
|
|
4804
|
+
// RECORD sizes are bigint; convert to number for FileFsRef.
|
|
4805
|
+
recordSize: recordSize !== void 0 && recordSize !== null ? Number(recordSize) : void 0
|
|
4806
|
+
});
|
|
4807
|
+
}
|
|
4808
|
+
}
|
|
4809
|
+
}
|
|
4810
|
+
const results = await Promise.all(
|
|
4811
|
+
pending.map(async ({ bundlePath, srcFsPath, recordSize }) => {
|
|
4812
|
+
if (recordSize !== void 0) {
|
|
4813
|
+
try {
|
|
4814
|
+
await import_fs5.default.promises.access(srcFsPath);
|
|
4815
|
+
return { bundlePath, srcFsPath, size: recordSize };
|
|
4816
|
+
} catch {
|
|
4817
|
+
return null;
|
|
4818
|
+
}
|
|
4819
|
+
} else {
|
|
4820
|
+
try {
|
|
4821
|
+
const stats = await import_fs5.default.promises.stat(srcFsPath);
|
|
4822
|
+
return { bundlePath, srcFsPath, size: stats.size };
|
|
4823
|
+
} catch {
|
|
4824
|
+
return null;
|
|
4825
|
+
}
|
|
4826
|
+
}
|
|
4827
|
+
})
|
|
4828
|
+
);
|
|
4829
|
+
for (const result of results) {
|
|
4830
|
+
if (result) {
|
|
4831
|
+
vendorFiles[result.bundlePath] = new import_build_utils5.FileFsRef({
|
|
4832
|
+
fsPath: result.srcFsPath,
|
|
4833
|
+
size: result.size
|
|
4834
|
+
});
|
|
4835
|
+
}
|
|
4836
|
+
}
|
|
4837
|
+
(0, import_build_utils5.debug)(
|
|
4838
|
+
`Mirrored ${Object.keys(vendorFiles).length} files` + (includePackages ? ` from ${includePackages.length} packages` : "")
|
|
4839
|
+
);
|
|
4840
|
+
return vendorFiles;
|
|
4841
|
+
}
|
|
4842
|
+
/**
|
|
4843
|
+
* Calculate the uncompressed size of each installed distribution.
|
|
4844
|
+
*
|
|
4845
|
+
* Returns a map of normalized package name to total size in bytes.
|
|
4846
|
+
* Uses RECORD sizes when available, falling back to stat for files
|
|
4847
|
+
* without a recorded size. All stat calls run in parallel.
|
|
4848
|
+
*/
|
|
4849
|
+
async calculatePerPackageSizes() {
|
|
4850
|
+
const sizes = /* @__PURE__ */ new Map();
|
|
4851
|
+
for (const dir of this.sitePackageDirs) {
|
|
4852
|
+
const dirDistributions = this.distributions.get(dir);
|
|
4853
|
+
if (!dirDistributions)
|
|
4854
|
+
continue;
|
|
4855
|
+
const resolvedDir = (0, import_path6.resolve)(dir);
|
|
4856
|
+
const dirPrefix = resolvedDir + import_path6.sep;
|
|
4857
|
+
for (const [name, dist] of dirDistributions) {
|
|
4858
|
+
let knownSize = 0;
|
|
4859
|
+
const statPromises = [];
|
|
4860
|
+
for (const { path: rawPath, size: recordSize } of dist.files) {
|
|
4861
|
+
const filePath = rawPath.replaceAll("/", import_path6.sep);
|
|
4862
|
+
if (!(0, import_path6.resolve)(resolvedDir, filePath).startsWith(dirPrefix)) {
|
|
4863
|
+
continue;
|
|
4864
|
+
}
|
|
4865
|
+
if (filePath.endsWith(".pyc") || filePath.split(import_path6.sep).includes("__pycache__")) {
|
|
4866
|
+
continue;
|
|
4867
|
+
}
|
|
4868
|
+
if (recordSize !== void 0 && recordSize !== null) {
|
|
4869
|
+
knownSize += Number(recordSize);
|
|
4870
|
+
} else {
|
|
4871
|
+
statPromises.push(
|
|
4872
|
+
import_fs5.default.promises.stat((0, import_path6.join)(dir, filePath)).then((stats) => stats.size).catch(() => 0)
|
|
4873
|
+
);
|
|
4874
|
+
}
|
|
4875
|
+
}
|
|
4876
|
+
const statSizes = await Promise.all(statPromises);
|
|
4877
|
+
let totalSize = knownSize;
|
|
4878
|
+
for (const s of statSizes) {
|
|
4879
|
+
totalSize += s;
|
|
4880
|
+
}
|
|
4881
|
+
sizes.set(name, totalSize);
|
|
4882
|
+
}
|
|
4883
|
+
}
|
|
4884
|
+
return sizes;
|
|
4885
|
+
}
|
|
4750
4886
|
};
|
|
4751
4887
|
async function getPackagesReachableOnPlatform(lockFile, projectName, pythonMajor, pythonMinor, sysPlatform, platformMachine) {
|
|
4752
4888
|
if (!projectName)
|
|
@@ -4806,66 +4942,35 @@ async function getPackagesReachableOnPlatform(lockFile, projectName, pythonMajor
|
|
|
4806
4942
|
}
|
|
4807
4943
|
return visited;
|
|
4808
4944
|
}
|
|
4809
|
-
async function mirrorPackagesIntoVendor({
|
|
4810
|
-
venvPath,
|
|
4811
|
-
vendorDirName,
|
|
4812
|
-
includePackages
|
|
4813
|
-
}) {
|
|
4814
|
-
const vendorFiles = {};
|
|
4815
|
-
if (includePackages && includePackages.length === 0) {
|
|
4816
|
-
return vendorFiles;
|
|
4817
|
-
}
|
|
4818
|
-
const includeSet = includePackages ? new Set(includePackages.map(import_python_analysis3.normalizePackageName)) : null;
|
|
4819
|
-
const sitePackageDirs = await getVenvSitePackagesDirs(venvPath);
|
|
4820
|
-
for (const dir of sitePackageDirs) {
|
|
4821
|
-
if (!import_fs5.default.existsSync(dir))
|
|
4822
|
-
continue;
|
|
4823
|
-
const resolvedDir = (0, import_path6.resolve)(dir);
|
|
4824
|
-
const dirPrefix = resolvedDir + import_path6.sep;
|
|
4825
|
-
const distributions = await (0, import_python_analysis3.scanDistributions)(dir);
|
|
4826
|
-
for (const [name, dist] of distributions) {
|
|
4827
|
-
if (includeSet && !includeSet.has(name))
|
|
4828
|
-
continue;
|
|
4829
|
-
for (const { path: rawPath } of dist.files) {
|
|
4830
|
-
const filePath = rawPath.replaceAll("/", import_path6.sep);
|
|
4831
|
-
if (!(0, import_path6.resolve)(resolvedDir, filePath).startsWith(dirPrefix)) {
|
|
4832
|
-
continue;
|
|
4833
|
-
}
|
|
4834
|
-
if (filePath.endsWith(".pyc") || filePath.split(import_path6.sep).includes("__pycache__")) {
|
|
4835
|
-
continue;
|
|
4836
|
-
}
|
|
4837
|
-
const srcFsPath = (0, import_path6.join)(dir, filePath);
|
|
4838
|
-
if (!import_fs5.default.existsSync(srcFsPath)) {
|
|
4839
|
-
continue;
|
|
4840
|
-
}
|
|
4841
|
-
const bundlePath = (0, import_path6.join)(vendorDirName, filePath).replace(/\\/g, "/");
|
|
4842
|
-
vendorFiles[bundlePath] = new import_build_utils5.FileFsRef({ fsPath: srcFsPath });
|
|
4843
|
-
}
|
|
4844
|
-
}
|
|
4845
|
-
}
|
|
4846
|
-
(0, import_build_utils5.debug)(
|
|
4847
|
-
`Mirrored ${Object.keys(vendorFiles).length} files` + (includePackages ? ` from ${includePackages.length} packages` : "")
|
|
4848
|
-
);
|
|
4849
|
-
return vendorFiles;
|
|
4850
|
-
}
|
|
4851
4945
|
async function calculateBundleSize(files) {
|
|
4852
|
-
let
|
|
4946
|
+
let knownSize = 0;
|
|
4947
|
+
const statPromises = [];
|
|
4853
4948
|
for (const filePath of Object.keys(files)) {
|
|
4854
4949
|
const file = files[filePath];
|
|
4855
4950
|
if ("fsPath" in file && file.fsPath) {
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
}
|
|
4860
|
-
|
|
4861
|
-
|
|
4951
|
+
const fsRef = file;
|
|
4952
|
+
if (typeof fsRef.size === "number") {
|
|
4953
|
+
knownSize += fsRef.size;
|
|
4954
|
+
} else {
|
|
4955
|
+
statPromises.push(
|
|
4956
|
+
import_fs5.default.promises.stat(fsRef.fsPath).then((stats) => stats.size).catch((err) => {
|
|
4957
|
+
console.warn(
|
|
4958
|
+
`Warning: Failed to stat file ${fsRef.fsPath}, size will not be included in bundle calculation: ${err}`
|
|
4959
|
+
);
|
|
4960
|
+
return 0;
|
|
4961
|
+
})
|
|
4862
4962
|
);
|
|
4863
4963
|
}
|
|
4864
4964
|
} else if ("data" in file) {
|
|
4865
4965
|
const data = file.data;
|
|
4866
|
-
|
|
4966
|
+
knownSize += typeof data === "string" ? Buffer.byteLength(data) : data.length;
|
|
4867
4967
|
}
|
|
4868
4968
|
}
|
|
4969
|
+
const statSizes = await Promise.all(statPromises);
|
|
4970
|
+
let totalSize = knownSize;
|
|
4971
|
+
for (const s of statSizes) {
|
|
4972
|
+
totalSize += s;
|
|
4973
|
+
}
|
|
4869
4974
|
return totalSize;
|
|
4870
4975
|
}
|
|
4871
4976
|
function lambdaKnapsack(packages, capacity) {
|
|
@@ -4883,36 +4988,6 @@ function lambdaKnapsack(packages, capacity) {
|
|
|
4883
4988
|
}
|
|
4884
4989
|
return bundled;
|
|
4885
4990
|
}
|
|
4886
|
-
async function calculatePerPackageSizes(venvPath) {
|
|
4887
|
-
const sizes = /* @__PURE__ */ new Map();
|
|
4888
|
-
const sitePackageDirs = await getVenvSitePackagesDirs(venvPath);
|
|
4889
|
-
for (const dir of sitePackageDirs) {
|
|
4890
|
-
if (!import_fs5.default.existsSync(dir))
|
|
4891
|
-
continue;
|
|
4892
|
-
const resolvedDir = (0, import_path6.resolve)(dir);
|
|
4893
|
-
const dirPrefix = resolvedDir + import_path6.sep;
|
|
4894
|
-
const distributions = await (0, import_python_analysis3.scanDistributions)(dir);
|
|
4895
|
-
for (const [name, dist] of distributions) {
|
|
4896
|
-
let totalSize = 0;
|
|
4897
|
-
for (const { path: rawPath } of dist.files) {
|
|
4898
|
-
const filePath = rawPath.replaceAll("/", import_path6.sep);
|
|
4899
|
-
if (!(0, import_path6.resolve)(resolvedDir, filePath).startsWith(dirPrefix)) {
|
|
4900
|
-
continue;
|
|
4901
|
-
}
|
|
4902
|
-
if (filePath.endsWith(".pyc") || filePath.split(import_path6.sep).includes("__pycache__")) {
|
|
4903
|
-
continue;
|
|
4904
|
-
}
|
|
4905
|
-
try {
|
|
4906
|
-
const stats = await import_fs5.default.promises.stat((0, import_path6.join)(dir, filePath));
|
|
4907
|
-
totalSize += stats.size;
|
|
4908
|
-
} catch {
|
|
4909
|
-
}
|
|
4910
|
-
}
|
|
4911
|
-
sizes.set(name, totalSize);
|
|
4912
|
-
}
|
|
4913
|
-
}
|
|
4914
|
-
return sizes;
|
|
4915
|
-
}
|
|
4916
4991
|
|
|
4917
4992
|
// src/diagnostics.ts
|
|
4918
4993
|
var import_fs6 = __toESM(require("fs"));
|
|
@@ -5160,7 +5235,7 @@ function buildCronRouteTable(crons) {
|
|
|
5160
5235
|
async function getServiceCrons(opts) {
|
|
5161
5236
|
const { service, entrypoint, rawEntrypoint, handlerFunction } = opts;
|
|
5162
5237
|
const isScheduledService = !!service && (0, import_build_utils7.isScheduleTriggeredService)(service);
|
|
5163
|
-
if (!isScheduledService || !service.name || typeof service.schedule !== "string") {
|
|
5238
|
+
if (!isScheduledService || !service.name || typeof service.schedule !== "string" && !Array.isArray(service.schedule)) {
|
|
5164
5239
|
return void 0;
|
|
5165
5240
|
}
|
|
5166
5241
|
const cronEntrypoint = entrypoint || rawEntrypoint;
|
|
@@ -5187,7 +5262,12 @@ async function getServiceCrons(opts) {
|
|
|
5187
5262
|
);
|
|
5188
5263
|
const moduleName = entrypointToModule(cronEntrypoint);
|
|
5189
5264
|
const resolvedHandler = handlerFunction ? `${moduleName}:${handlerFunction}` : moduleName;
|
|
5190
|
-
|
|
5265
|
+
const schedules = Array.isArray(service.schedule) ? service.schedule : [service.schedule];
|
|
5266
|
+
return schedules.map((schedule) => ({
|
|
5267
|
+
path: cronPath,
|
|
5268
|
+
schedule,
|
|
5269
|
+
resolvedHandler
|
|
5270
|
+
}));
|
|
5191
5271
|
}
|
|
5192
5272
|
async function getServiceCronsDynamic(opts) {
|
|
5193
5273
|
const {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vercel/python",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.40.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"smol-toml": "1.5.2",
|
|
35
35
|
"vitest": "2.1.4",
|
|
36
36
|
"which": "3.0.0",
|
|
37
|
+
"@vercel/build-utils": "13.23.0",
|
|
37
38
|
"@vercel/error-utils": "2.1.0",
|
|
38
|
-
"@vercel/python-runtime": "0.13.2"
|
|
39
|
-
"@vercel/build-utils": "13.22.0"
|
|
39
|
+
"@vercel/python-runtime": "0.13.2"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "node ../../utils/build-builder.mjs",
|