* Like getPyprojectScriptsEntrypoint but returns diagnostic metadata * (the raw script value and checked paths) so callers can produce * targeted error messages when resolution fails.
( workPath: string )
| 287 | * targeted error messages when resolution fails. |
| 288 | */ |
| 289 | async function getPyprojectEntrypointWithDiagnostics( |
| 290 | workPath: string |
| 291 | ): Promise<PyprojectEntrypointResult> { |
| 292 | const pyprojectData = await readConfigFile<{ |
| 293 | project?: { scripts?: Record<string, unknown> }; |
| 294 | }>(join(workPath, 'pyproject.toml')); |
| 295 | if (!pyprojectData) return { entrypoint: null }; |
| 296 | |
| 297 | const scripts = pyprojectData.project?.scripts as |
| 298 | | Record<string, unknown> |
| 299 | | undefined; |
| 300 | const appScript = scripts?.app; |
| 301 | if (typeof appScript !== 'string') return { entrypoint: null }; |
| 302 | |
| 303 | // Expect values like "package.module:app". Extract the module portion. |
| 304 | const match = appScript.match(/([A-Za-z_][\w.]*)\s*:\s*([A-Za-z_][\w]*)/); |
| 305 | if (!match) return { entrypoint: null, appScript }; |
| 306 | const modulePath = match[1]; |
| 307 | const variableName = match[2]; |
| 308 | const relPath = modulePath.replace(/\./g, '/'); |
| 309 | |
| 310 | const candidates = [`${relPath}.py`, `${relPath}/__init__.py`]; |
| 311 | for (const candidate of candidates) { |
| 312 | if (await fileExists(join(workPath, candidate))) { |
| 313 | return { entrypoint: { entrypoint: candidate, variableName } }; |
| 314 | } |
| 315 | } |
| 316 | return { entrypoint: null, appScript, checkedPaths: candidates }; |
| 317 | } |
| 318 | |
| 319 | async function findValidEntrypoint( |
| 320 | workPath: string, |
no test coverage detected