@vercel/python-analysis 0.3.2 → 0.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.
package/dist/index.js CHANGED
@@ -66,7 +66,14 @@ var isErrnoException = (error, code = void 0) => {
66
66
  return util.types.isNativeError(error) && "code" in error && (code === void 0 || error.code === code);
67
67
  };
68
68
  var PythonAnalysisError = class extends Error {
69
- constructor({ message, code, path: path4, link, action }) {
69
+ constructor({
70
+ message,
71
+ code,
72
+ path: path4,
73
+ link,
74
+ action,
75
+ fileContent
76
+ }) {
70
77
  super(message);
71
78
  this.hideStackTrace = true;
72
79
  this.name = "PythonAnalysisError";
@@ -74,6 +81,7 @@ var PythonAnalysisError = class extends Error {
74
81
  this.path = path4;
75
82
  this.link = link;
76
83
  this.action = action;
84
+ this.fileContent = fileContent;
77
85
  }
78
86
  };
79
87
 
@@ -135,7 +143,8 @@ function parseRawConfig(content, filename, filetype = void 0) {
135
143
  throw new PythonAnalysisError({
136
144
  message: `Could not parse config file "${filename}": ${error.message}`,
137
145
  code: "PYTHON_CONFIG_PARSE_ERROR",
138
- path: filename
146
+ path: filename,
147
+ fileContent: content
139
148
  });
140
149
  }
141
150
  throw error;
@@ -153,7 +162,8 @@ function parseConfig(content, filename, schema, filetype = void 0) {
153
162
  message: `Invalid config in "${filename}":
154
163
  ${issues}`,
155
164
  code: "PYTHON_CONFIG_VALIDATION_ERROR",
156
- path: filename
165
+ path: filename,
166
+ fileContent: content
157
167
  });
158
168
  }
159
169
  return result.data;
@@ -435,6 +445,8 @@ function convertPipfileToPyprojectToml(pipfile) {
435
445
  }
436
446
  if (deps.length > 0) {
437
447
  pyproject.project = {
448
+ name: "app",
449
+ version: "0.1.0",
438
450
  dependencies: deps
439
451
  };
440
452
  }
@@ -492,6 +504,8 @@ function convertPipfileLockToPyprojectToml(pipfileLock) {
492
504
  }
493
505
  if (deps.length > 0) {
494
506
  pyproject.project = {
507
+ name: "app",
508
+ version: "0.1.0",
495
509
  dependencies: deps
496
510
  };
497
511
  }
@@ -568,7 +582,8 @@ var uvIndexEntrySchema = z3.object({
568
582
  name: z3.string(),
569
583
  url: z3.string(),
570
584
  default: z3.boolean().optional(),
571
- explicit: z3.boolean().optional()
585
+ explicit: z3.boolean().optional(),
586
+ format: z3.string().optional()
572
587
  });
573
588
  var uvConfigSchema = z3.object({
574
589
  sources: z3.record(z3.union([dependencySourceSchema, z3.array(dependencySourceSchema)])).optional(),
@@ -642,6 +657,7 @@ import { normalize } from "path";
642
657
  import { parsePipRequirementsFile } from "pip-requirements-js";
643
658
  var PRIMARY_INDEX_NAME = "primary";
644
659
  var EXTRA_INDEX_PREFIX = "extra-";
660
+ var FIND_LINKS_PREFIX = "find-links-";
645
661
  function parseGitUrl(url) {
646
662
  if (!url.startsWith("git+")) {
647
663
  return null;
@@ -683,6 +699,8 @@ function extractPipArguments(fileContent) {
683
699
  };
684
700
  const lines = fileContent.split(/\r?\n/);
685
701
  const cleanedLines = [];
702
+ const pathRequirements = [];
703
+ const editableRequirements = [];
686
704
  for (let i = 0; i < lines.length; i++) {
687
705
  const line = lines[i];
688
706
  const trimmed = line.trim();
@@ -697,11 +715,21 @@ function extractPipArguments(fileContent) {
697
715
  fullLine = fullLine.slice(0, -1) + lines[i + linesConsumed].trim();
698
716
  }
699
717
  const extracted = tryExtractPipArgument(fullLine, options);
700
- if (extracted) {
718
+ if (extracted === true) {
719
+ i += linesConsumed;
720
+ } else if (typeof extracted === "object" && extracted.editable) {
721
+ editableRequirements.push(extracted.editable);
701
722
  i += linesConsumed;
702
723
  } else {
724
+ if (/^-[a-zA-Z]/.test(fullLine) && !fullLine.startsWith("-r") && !fullLine.startsWith("-c")) {
725
+ i += linesConsumed;
726
+ continue;
727
+ }
703
728
  const strippedLine = stripInlineHashes(fullLine);
704
- if (strippedLine !== fullLine) {
729
+ const effectiveLine = (strippedLine !== fullLine ? strippedLine : fullLine).trim();
730
+ if (isPathOrUrlRequirement(effectiveLine)) {
731
+ pathRequirements.push(effectiveLine);
732
+ } else if (strippedLine !== fullLine) {
705
733
  cleanedLines.push(strippedLine);
706
734
  } else {
707
735
  cleanedLines.push(line);
@@ -714,7 +742,9 @@ function extractPipArguments(fileContent) {
714
742
  }
715
743
  return {
716
744
  cleanedContent: cleanedLines.join("\n"),
717
- options
745
+ options,
746
+ pathRequirements,
747
+ editableRequirements
718
748
  };
719
749
  }
720
750
  function tryExtractPipArgument(line, options) {
@@ -753,6 +783,46 @@ function tryExtractPipArgument(line, options) {
753
783
  return true;
754
784
  }
755
785
  }
786
+ if (line.startsWith("--editable")) {
787
+ const path4 = extractArgValue(line, "--editable");
788
+ if (path4) {
789
+ return { editable: path4 };
790
+ }
791
+ }
792
+ if (line.startsWith("-e ") || line.startsWith("-e ")) {
793
+ const path4 = line.slice(2).trim();
794
+ if (path4) {
795
+ return { editable: path4 };
796
+ }
797
+ }
798
+ if (line.startsWith("--find-links")) {
799
+ const url = extractArgValue(line, "--find-links");
800
+ if (url) {
801
+ if (!options.findLinks)
802
+ options.findLinks = [];
803
+ options.findLinks.push(url);
804
+ return true;
805
+ }
806
+ }
807
+ if (line.startsWith("-f ") || line.startsWith("-f ")) {
808
+ const match = line.match(/^-f\s+(\S+)/);
809
+ if (match) {
810
+ if (!options.findLinks)
811
+ options.findLinks = [];
812
+ options.findLinks.push(match[1]);
813
+ return true;
814
+ }
815
+ }
816
+ if (line === "--no-index" || line.startsWith("--no-index ")) {
817
+ options.noIndex = true;
818
+ return true;
819
+ }
820
+ if (line.startsWith("--no-binary") || line.startsWith("--only-binary")) {
821
+ return true;
822
+ }
823
+ if (line.startsWith("--")) {
824
+ return true;
825
+ }
756
826
  return false;
757
827
  }
758
828
  function stripInlineHashes(line) {
@@ -768,15 +838,158 @@ function extractInlineHashes(line) {
768
838
  return hashes;
769
839
  }
770
840
  function extractArgValue(line, option) {
841
+ let value = null;
771
842
  if (line.startsWith(`${option}=`)) {
772
- const value = line.slice(option.length + 1).trim();
773
- return value || null;
843
+ value = line.slice(option.length + 1).trim();
844
+ } else if (line.startsWith(`${option} `) || line.startsWith(`${option} `)) {
845
+ value = line.slice(option.length).trim();
774
846
  }
775
- if (line.startsWith(`${option} `) || line.startsWith(`${option} `)) {
776
- const value = line.slice(option.length).trim();
777
- return value || null;
847
+ if (!value)
848
+ return null;
849
+ const commentIdx = value.indexOf(" #");
850
+ if (commentIdx !== -1) {
851
+ value = value.slice(0, commentIdx).trim();
778
852
  }
779
- return null;
853
+ return value || null;
854
+ }
855
+ function isPathOrUrlRequirement(line) {
856
+ if (line.startsWith("./") || line.startsWith("../"))
857
+ return true;
858
+ if (line.startsWith("/"))
859
+ return true;
860
+ if (line.startsWith("~/"))
861
+ return true;
862
+ if (/^(https?|ftp|file):\/\//i.test(line))
863
+ return true;
864
+ if (isBareArchiveFilename(line))
865
+ return true;
866
+ return false;
867
+ }
868
+ function isBareArchiveFilename(line) {
869
+ if (line.includes(" @ "))
870
+ return false;
871
+ let check = line;
872
+ const commentIdx = check.indexOf(" #");
873
+ if (commentIdx !== -1)
874
+ check = check.slice(0, commentIdx);
875
+ const markerIdx = check.indexOf(" ;");
876
+ if (markerIdx !== -1)
877
+ check = check.slice(0, markerIdx);
878
+ const extrasIdx = check.indexOf("[");
879
+ if (extrasIdx !== -1)
880
+ check = check.slice(0, extrasIdx);
881
+ check = check.trim();
882
+ return /\.(whl|tar\.gz|tar\.bz2|tar\.xz|zip)$/i.test(check);
883
+ }
884
+ function parseWheelFilename(filename) {
885
+ if (!filename.endsWith(".whl"))
886
+ return null;
887
+ const stem = filename.slice(0, -4);
888
+ const parts = stem.split("-");
889
+ if (parts.length < 5 || parts.length > 6)
890
+ return null;
891
+ const name = parts[0];
892
+ const version = parts[1];
893
+ if (!name || !version)
894
+ return null;
895
+ return {
896
+ name: name.replace(/_/g, "-"),
897
+ version
898
+ };
899
+ }
900
+ function parseSdistFilename(filename) {
901
+ let stem = filename;
902
+ for (const ext of [".tar.gz", ".tar.bz2", ".tar.xz", ".zip"]) {
903
+ if (stem.endsWith(ext)) {
904
+ stem = stem.slice(0, -ext.length);
905
+ break;
906
+ }
907
+ }
908
+ if (stem === filename)
909
+ return null;
910
+ const parts = stem.split("-");
911
+ let versionIdx = -1;
912
+ for (let i = 1; i < parts.length; i++) {
913
+ if (/^\d/.test(parts[i])) {
914
+ versionIdx = i;
915
+ break;
916
+ }
917
+ }
918
+ if (versionIdx === -1)
919
+ return null;
920
+ return {
921
+ name: parts.slice(0, versionIdx).join("-"),
922
+ version: parts.slice(versionIdx).join("-")
923
+ };
924
+ }
925
+ function normalizePathRequirement(rawLine) {
926
+ let line = rawLine;
927
+ const commentIdx = line.indexOf(" #");
928
+ if (commentIdx !== -1) {
929
+ line = line.slice(0, commentIdx).trim();
930
+ }
931
+ let markers;
932
+ const markerIdx = line.indexOf(" ;");
933
+ if (markerIdx !== -1) {
934
+ markers = line.slice(markerIdx + 2).trim();
935
+ line = line.slice(0, markerIdx).trim();
936
+ }
937
+ let extras;
938
+ const extrasMatch = line.match(/\[([^\]]+)\]$/);
939
+ if (extrasMatch) {
940
+ extras = extrasMatch[1].split(",").map((e) => e.trim());
941
+ line = line.slice(0, extrasMatch.index).trim();
942
+ }
943
+ const isUrl = /^(https?|ftp|file):\/\//i.test(line);
944
+ let filename;
945
+ if (isUrl) {
946
+ try {
947
+ const url = new URL(line);
948
+ filename = url.pathname.split("/").pop() || "";
949
+ } catch {
950
+ return null;
951
+ }
952
+ } else {
953
+ const cleanPath = line.replace(/\/+$/, "");
954
+ filename = cleanPath.split("/").pop() || "";
955
+ }
956
+ if (!filename)
957
+ return null;
958
+ let name;
959
+ let version;
960
+ const wheelParsed = parseWheelFilename(filename);
961
+ if (wheelParsed) {
962
+ name = wheelParsed.name;
963
+ version = wheelParsed.version;
964
+ }
965
+ if (!name) {
966
+ const sdistParsed = parseSdistFilename(filename);
967
+ if (sdistParsed) {
968
+ name = sdistParsed.name;
969
+ version = sdistParsed.version;
970
+ }
971
+ }
972
+ if (!name) {
973
+ name = filename.replace(/[-_.]+/g, "-").toLowerCase();
974
+ }
975
+ if (!name)
976
+ return null;
977
+ const req = { name };
978
+ if (version) {
979
+ req.version = `==${version}`;
980
+ }
981
+ if (extras && extras.length > 0) {
982
+ req.extras = extras;
983
+ }
984
+ if (markers) {
985
+ req.markers = markers;
986
+ }
987
+ if (isUrl) {
988
+ req.url = line;
989
+ } else {
990
+ req.source = { path: line };
991
+ }
992
+ return req;
780
993
  }
781
994
  function convertRequirementsToPyprojectToml(fileContent, readFile3) {
782
995
  const pyproject = {};
@@ -795,6 +1008,8 @@ function convertRequirementsToPyprojectToml(fileContent, readFile3) {
795
1008
  }
796
1009
  if (deps.length > 0) {
797
1010
  pyproject.project = {
1011
+ name: "app",
1012
+ version: "0.1.0",
798
1013
  dependencies: deps
799
1014
  };
800
1015
  }
@@ -826,6 +1041,15 @@ function buildIndexEntries(pipOptions) {
826
1041
  url: pipOptions.extraIndexUrls[i]
827
1042
  });
828
1043
  }
1044
+ if (pipOptions.findLinks) {
1045
+ for (let i = 0; i < pipOptions.findLinks.length; i++) {
1046
+ indexes.push({
1047
+ name: `${FIND_LINKS_PREFIX}${i + 1}`,
1048
+ url: pipOptions.findLinks[i],
1049
+ format: "flat"
1050
+ });
1051
+ }
1052
+ }
829
1053
  return indexes;
830
1054
  }
831
1055
  function parseRequirementsFile(fileContent, readFile3) {
@@ -833,7 +1057,7 @@ function parseRequirementsFile(fileContent, readFile3) {
833
1057
  return parseRequirementsFileInternal(fileContent, readFile3, visited);
834
1058
  }
835
1059
  function parseRequirementsFileInternal(fileContent, readFile3, visited) {
836
- const { cleanedContent, options } = extractPipArguments(fileContent);
1060
+ const { cleanedContent, options, pathRequirements, editableRequirements } = extractPipArguments(fileContent);
837
1061
  const hashMap = buildHashMap(fileContent);
838
1062
  const requirements = parsePipRequirementsFile(cleanedContent);
839
1063
  const normalized = [];
@@ -841,7 +1065,9 @@ function parseRequirementsFileInternal(fileContent, readFile3, visited) {
841
1065
  requirementFiles: [...options.requirementFiles],
842
1066
  constraintFiles: [...options.constraintFiles],
843
1067
  indexUrl: options.indexUrl,
844
- extraIndexUrls: [...options.extraIndexUrls]
1068
+ extraIndexUrls: [...options.extraIndexUrls],
1069
+ findLinks: options.findLinks ? [...options.findLinks] : void 0,
1070
+ noIndex: options.noIndex
845
1071
  };
846
1072
  for (const req of requirements) {
847
1073
  if (req.type === "RequirementsFile") {
@@ -861,6 +1087,23 @@ function parseRequirementsFileInternal(fileContent, readFile3, visited) {
861
1087
  normalized.push(norm);
862
1088
  }
863
1089
  }
1090
+ for (const rawPath of pathRequirements) {
1091
+ const norm = normalizePathRequirement(rawPath);
1092
+ if (norm != null) {
1093
+ normalized.push(norm);
1094
+ }
1095
+ }
1096
+ for (const rawPath of editableRequirements) {
1097
+ const norm = normalizePathRequirement(rawPath);
1098
+ if (norm != null) {
1099
+ if (norm.source) {
1100
+ norm.source.editable = true;
1101
+ } else {
1102
+ norm.source = { path: rawPath, editable: true };
1103
+ }
1104
+ normalized.push(norm);
1105
+ }
1106
+ }
864
1107
  if (readFile3) {
865
1108
  for (const refPath of mergedOptions.requirementFiles) {
866
1109
  const refPathKey = normalize(refPath);
@@ -897,6 +1140,18 @@ function parseRequirementsFileInternal(fileContent, readFile3, visited) {
897
1140
  mergedOptions.constraintFiles.push(constraintPath);
898
1141
  }
899
1142
  }
1143
+ if (refParsed.pipOptions.findLinks) {
1144
+ if (!mergedOptions.findLinks)
1145
+ mergedOptions.findLinks = [];
1146
+ for (const fl of refParsed.pipOptions.findLinks) {
1147
+ if (!mergedOptions.findLinks.includes(fl)) {
1148
+ mergedOptions.findLinks.push(fl);
1149
+ }
1150
+ }
1151
+ }
1152
+ if (refParsed.pipOptions.noIndex) {
1153
+ mergedOptions.noIndex = true;
1154
+ }
900
1155
  }
901
1156
  }
902
1157
  }
@@ -1385,6 +1640,11 @@ var PythonManifestKind = /* @__PURE__ */ ((PythonManifestKind2) => {
1385
1640
  PythonManifestKind2["PyProjectToml"] = "pyproject.toml";
1386
1641
  return PythonManifestKind2;
1387
1642
  })(PythonManifestKind || {});
1643
+ var PythonLockFileKind = /* @__PURE__ */ ((PythonLockFileKind2) => {
1644
+ PythonLockFileKind2["UvLock"] = "uv.lock";
1645
+ PythonLockFileKind2["PylockToml"] = "pylock.toml";
1646
+ return PythonLockFileKind2;
1647
+ })(PythonLockFileKind || {});
1388
1648
  var PythonManifestConvertedKind = /* @__PURE__ */ ((PythonManifestConvertedKind2) => {
1389
1649
  PythonManifestConvertedKind2["Pipfile"] = "Pipfile";
1390
1650
  PythonManifestConvertedKind2["PipfileLock"] = "Pipfile.lock";
@@ -1426,6 +1686,7 @@ async function discoverPythonPackage({
1426
1686
  }
1427
1687
  let entrypointManifest;
1428
1688
  let workspaceManifest;
1689
+ let workspaceLockFile;
1429
1690
  if (manifests.length === 0) {
1430
1691
  return {
1431
1692
  configs
@@ -1437,6 +1698,7 @@ async function discoverPythonPackage({
1437
1698
  manifests
1438
1699
  );
1439
1700
  workspaceManifest = entrypointWorkspaceManifest;
1701
+ workspaceLockFile = entrypointWorkspaceManifest.lockFile;
1440
1702
  configs = configs.filter(
1441
1703
  (config) => Object.values(config).some(
1442
1704
  (cfg) => cfg !== void 0 && isSubpath(
@@ -1454,6 +1716,7 @@ async function discoverPythonPackage({
1454
1716
  return {
1455
1717
  manifest: entrypointManifest,
1456
1718
  workspaceManifest,
1719
+ workspaceLockFile,
1457
1720
  configs,
1458
1721
  requiresPython
1459
1722
  };
@@ -1568,6 +1831,21 @@ async function loadPythonManifest(root, prefix) {
1568
1831
  }
1569
1832
  return manifest;
1570
1833
  }
1834
+ async function maybeLoadLockFile(root, subdir) {
1835
+ const uvLockRelPath = path3.join(subdir, "uv.lock");
1836
+ const uvLockPath = path3.join(root, uvLockRelPath);
1837
+ const uvLockContent = await readFileTextIfExists(uvLockPath);
1838
+ if (uvLockContent != null) {
1839
+ return { path: uvLockRelPath, kind: "uv.lock" /* UvLock */ };
1840
+ }
1841
+ const pylockRelPath = path3.join(subdir, "pylock.toml");
1842
+ const pylockPath = path3.join(root, pylockRelPath);
1843
+ const pylockContent = await readFileTextIfExists(pylockPath);
1844
+ if (pylockContent != null) {
1845
+ return { path: pylockRelPath, kind: "pylock.toml" /* PylockToml */ };
1846
+ }
1847
+ return void 0;
1848
+ }
1571
1849
  async function maybeLoadPyProjectToml(root, subdir) {
1572
1850
  const pyprojectTomlRelPath = path3.join(subdir, "pyproject.toml");
1573
1851
  const pyprojectTomlPath = path3.join(root, pyprojectTomlRelPath);
@@ -1614,9 +1892,11 @@ async function maybeLoadPyProjectToml(root, subdir) {
1614
1892
  pyproject.tool.uv = uvToml;
1615
1893
  }
1616
1894
  }
1895
+ const lockFile = await maybeLoadLockFile(root, subdir);
1617
1896
  return {
1618
1897
  path: pyprojectTomlRelPath,
1619
- data: pyproject
1898
+ data: pyproject,
1899
+ lockFile
1620
1900
  };
1621
1901
  }
1622
1902
  async function maybeLoadPipfile(root, subdir) {
@@ -1703,12 +1983,16 @@ async function maybeLoadRequirementsTxt(root, subdir, fileName) {
1703
1983
  } catch (error) {
1704
1984
  if (error instanceof PythonAnalysisError) {
1705
1985
  error.path = requirementsTxtRelPath;
1986
+ if (!error.fileContent) {
1987
+ error.fileContent = requirementsContent;
1988
+ }
1706
1989
  throw error;
1707
1990
  }
1708
1991
  throw new PythonAnalysisError({
1709
1992
  message: `could not parse ${fileName}: ${error instanceof Error ? error.message : String(error)}`,
1710
1993
  code: "PYTHON_REQUIREMENTS_PARSE_ERROR",
1711
- path: requirementsTxtRelPath
1994
+ path: requirementsTxtRelPath,
1995
+ fileContent: requirementsContent
1712
1996
  });
1713
1997
  }
1714
1998
  }
@@ -1745,6 +2029,29 @@ async function maybeLoadPythonRequest(root, subdir) {
1745
2029
  };
1746
2030
  }
1747
2031
 
2032
+ // src/manifest/serialize.ts
2033
+ import toml2 from "smol-toml";
2034
+ function stringifyManifest(data) {
2035
+ return toml2.stringify(data);
2036
+ }
2037
+ function createMinimalManifest(options = {}) {
2038
+ const {
2039
+ name = "app",
2040
+ version = "0.1.0",
2041
+ requiresPython,
2042
+ dependencies = []
2043
+ } = options;
2044
+ return {
2045
+ project: {
2046
+ name,
2047
+ version,
2048
+ ...requiresPython && { "requires-python": requiresPython },
2049
+ dependencies,
2050
+ classifiers: ["Private :: Do Not Upload"]
2051
+ }
2052
+ };
2053
+ }
2054
+
1748
2055
  // src/manifest/python-selector.ts
1749
2056
  function selectPython(constraints, available) {
1750
2057
  const warnings = [];
@@ -1917,6 +2224,7 @@ export {
1917
2224
  PythonBuild,
1918
2225
  PythonConfigKind,
1919
2226
  PythonImplementation,
2227
+ PythonLockFileKind,
1920
2228
  PythonManifestConvertedKind,
1921
2229
  PythonManifestKind,
1922
2230
  PythonVariant,
@@ -1927,6 +2235,8 @@ export {
1927
2235
  UvConfigWorkspaceSchema,
1928
2236
  UvIndexEntrySchema,
1929
2237
  containsAppOrHandler,
2238
+ createMinimalManifest,
1930
2239
  discoverPythonPackage,
1931
- selectPython
2240
+ selectPython,
2241
+ stringifyManifest
1932
2242
  };
@@ -20,6 +20,26 @@ export declare enum PythonManifestKind {
20
20
  /** Standard `pyproject.toml` file (PEP 517/518/621). */
21
21
  PyProjectToml = "pyproject.toml"
22
22
  }
23
+ /**
24
+ * Kinds of Python lock files.
25
+ *
26
+ * Lock files pin exact dependency versions for reproducible installs.
27
+ */
28
+ export declare enum PythonLockFileKind {
29
+ /** uv's lock file format. */
30
+ UvLock = "uv.lock",
31
+ /** PEP 751 standard lock file format. */
32
+ PylockToml = "pylock.toml"
33
+ }
34
+ /**
35
+ * Information about a detected lock file.
36
+ */
37
+ export interface PythonLockFile {
38
+ /** Relative path to the lock file. */
39
+ path: RelPath;
40
+ /** The lock file format. */
41
+ kind: PythonLockFileKind;
42
+ }
23
43
  /**
24
44
  * Kinds of Python package manifests that are converted to pyproject.toml format.
25
45
  *
@@ -63,6 +83,8 @@ export interface PythonManifest {
63
83
  origin?: PythonManifestOrigin;
64
84
  /** Whether this manifest represents a workspace root. */
65
85
  isRoot?: boolean;
86
+ /** Lock file associated with this manifest, if one exists. */
87
+ lockFile?: PythonLockFile;
66
88
  }
67
89
  /**
68
90
  * Configuration from a `.python-version` file.
@@ -130,6 +152,8 @@ export interface PythonPackage {
130
152
  requiresPython?: PythonConstraint[];
131
153
  /** The workspace root manifest, if this package is part of a workspace. */
132
154
  workspaceManifest?: PythonManifest;
155
+ /** Lock file at the workspace root, if one exists. */
156
+ workspaceLockFile?: PythonLockFile;
133
157
  }
134
158
  /**
135
159
  * Discover Python package information starting from an entrypoint directory.
@@ -219,16 +219,19 @@ export declare const pyProjectToolSectionSchema: z.ZodObject<{
219
219
  url: z.ZodString;
220
220
  default: z.ZodOptional<z.ZodBoolean>;
221
221
  explicit: z.ZodOptional<z.ZodBoolean>;
222
+ format: z.ZodOptional<z.ZodString>;
222
223
  }, "strip", z.ZodTypeAny, {
223
224
  name: string;
224
225
  url: string;
225
226
  default?: boolean | undefined;
226
227
  explicit?: boolean | undefined;
228
+ format?: string | undefined;
227
229
  }, {
228
230
  name: string;
229
231
  url: string;
230
232
  default?: boolean | undefined;
231
233
  explicit?: boolean | undefined;
234
+ format?: string | undefined;
232
235
  }>, "many">>;
233
236
  workspace: z.ZodOptional<z.ZodObject<{
234
237
  members: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
@@ -259,6 +262,7 @@ export declare const pyProjectToolSectionSchema: z.ZodObject<{
259
262
  url: string;
260
263
  default?: boolean | undefined;
261
264
  explicit?: boolean | undefined;
265
+ format?: string | undefined;
262
266
  }[] | undefined;
263
267
  workspace?: {
264
268
  members?: string[] | undefined;
@@ -283,6 +287,7 @@ export declare const pyProjectToolSectionSchema: z.ZodObject<{
283
287
  url: string;
284
288
  default?: boolean | undefined;
285
289
  explicit?: boolean | undefined;
290
+ format?: string | undefined;
286
291
  }[] | undefined;
287
292
  workspace?: {
288
293
  members?: string[] | undefined;
@@ -309,6 +314,7 @@ export declare const pyProjectToolSectionSchema: z.ZodObject<{
309
314
  url: string;
310
315
  default?: boolean | undefined;
311
316
  explicit?: boolean | undefined;
317
+ format?: string | undefined;
312
318
  }[] | undefined;
313
319
  workspace?: {
314
320
  members?: string[] | undefined;
@@ -335,6 +341,7 @@ export declare const pyProjectToolSectionSchema: z.ZodObject<{
335
341
  url: string;
336
342
  default?: boolean | undefined;
337
343
  explicit?: boolean | undefined;
344
+ format?: string | undefined;
338
345
  }[] | undefined;
339
346
  workspace?: {
340
347
  members?: string[] | undefined;
@@ -513,16 +520,19 @@ export declare const pyProjectTomlSchema: z.ZodObject<{
513
520
  url: z.ZodString;
514
521
  default: z.ZodOptional<z.ZodBoolean>;
515
522
  explicit: z.ZodOptional<z.ZodBoolean>;
523
+ format: z.ZodOptional<z.ZodString>;
516
524
  }, "strip", z.ZodTypeAny, {
517
525
  name: string;
518
526
  url: string;
519
527
  default?: boolean | undefined;
520
528
  explicit?: boolean | undefined;
529
+ format?: string | undefined;
521
530
  }, {
522
531
  name: string;
523
532
  url: string;
524
533
  default?: boolean | undefined;
525
534
  explicit?: boolean | undefined;
535
+ format?: string | undefined;
526
536
  }>, "many">>;
527
537
  workspace: z.ZodOptional<z.ZodObject<{
528
538
  members: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
@@ -553,6 +563,7 @@ export declare const pyProjectTomlSchema: z.ZodObject<{
553
563
  url: string;
554
564
  default?: boolean | undefined;
555
565
  explicit?: boolean | undefined;
566
+ format?: string | undefined;
556
567
  }[] | undefined;
557
568
  workspace?: {
558
569
  members?: string[] | undefined;
@@ -577,6 +588,7 @@ export declare const pyProjectTomlSchema: z.ZodObject<{
577
588
  url: string;
578
589
  default?: boolean | undefined;
579
590
  explicit?: boolean | undefined;
591
+ format?: string | undefined;
580
592
  }[] | undefined;
581
593
  workspace?: {
582
594
  members?: string[] | undefined;
@@ -603,6 +615,7 @@ export declare const pyProjectTomlSchema: z.ZodObject<{
603
615
  url: string;
604
616
  default?: boolean | undefined;
605
617
  explicit?: boolean | undefined;
618
+ format?: string | undefined;
606
619
  }[] | undefined;
607
620
  workspace?: {
608
621
  members?: string[] | undefined;
@@ -629,6 +642,7 @@ export declare const pyProjectTomlSchema: z.ZodObject<{
629
642
  url: string;
630
643
  default?: boolean | undefined;
631
644
  explicit?: boolean | undefined;
645
+ format?: string | undefined;
632
646
  }[] | undefined;
633
647
  workspace?: {
634
648
  members?: string[] | undefined;
@@ -693,6 +707,7 @@ export declare const pyProjectTomlSchema: z.ZodObject<{
693
707
  url: string;
694
708
  default?: boolean | undefined;
695
709
  explicit?: boolean | undefined;
710
+ format?: string | undefined;
696
711
  }[] | undefined;
697
712
  workspace?: {
698
713
  members?: string[] | undefined;
@@ -757,6 +772,7 @@ export declare const pyProjectTomlSchema: z.ZodObject<{
757
772
  url: string;
758
773
  default?: boolean | undefined;
759
774
  explicit?: boolean | undefined;
775
+ format?: string | undefined;
760
776
  }[] | undefined;
761
777
  workspace?: {
762
778
  members?: string[] | undefined;