{"record":{"id":"b851f55012425aab","repo":"astral-sh/ruff","slug":"for-an-mdtest-with-external-dependencies-a-python","errorCode":null,"errorMessage":"For an mdtest with external dependencies, a Python platform must be specified","messagePattern":"For an mdtest with external dependencies, a Python platform must be specified","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/ty_test/src/external_dependencies.rs","lineNumber":72,"sourceCode":"            .join(\"\\n\")\n    );\n\n    std::fs::write(\n        temp_path.join(\"pyproject.toml\").as_std_path(),\n        pyproject_toml,\n    )\n    .context(\"Failed to write pyproject.toml\")?;\n\n    // Convert PythonPlatform to uv's platform format\n    let uv_platform = match python_platform {\n        PythonPlatform::Identifier(id) => match id.as_str() {\n            \"win32\" => \"windows\",\n            \"darwin\" => \"macos\",\n            \"linux\" => \"linux\",\n            other => other,\n        },\n        PythonPlatform::All => {\n            bail!(\"For an mdtest with external dependencies, a Python platform must be specified\");\n        }\n    };\n\n    let upgrade_lockfile = std::env::var(\"MDTEST_UPGRADE_LOCKFILES\").is_ok_and(|v| v == \"1\");\n    let use_locked = if upgrade_lockfile {\n        // In upgrade mode, we'll generate a new lockfile\n        false\n    } else if lockfile_path.exists() {\n        // Copy existing lockfile to temp directory\n        let temp_lockfile = temp_path.join(\"uv.lock\");\n        std::fs::copy(lockfile_path, temp_lockfile.as_std_path())\n            .with_context(|| format!(\"Failed to copy lockfile from '{lockfile_path}'\"))?;\n        true\n    } else {\n        // No existing lockfile - error in normal mode\n        bail!(\n            \"Lockfile not found at '{lockfile_path}'. Run with `MDTEST_UPGRADE_LOCKFILES=1` to generate it.\",\n        );","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/astral-sh/ruff/blob/26f38c119cac42e4d320ba08f09224fdec74af2c/crates/ty_test/src/external_dependencies.rs#L54-L90","documentation":"setup_venv in ty_test's external-dependencies harness maps the mdtest Python platform to a uv-compatible platform string. When the platform is PythonPlatform::All (i.e. the mdtest did not pin a concrete platform), uv cannot resolve one lockfile for all platforms, so the harness refuses to proceed.","triggerScenarios":"Running an mdtest with external dependencies (MDTEST_EXTERNAL=1) while the mdtest frontmatter sets platform: all, or omits a platform so it defaults to All, in setup_venv at crates/ty_test/src/external_dependencies.rs:72.","commonSituations":"Writing a new external-dependency mdtest and forgetting the `platform:` frontmatter key; running on CI where the default platform differs; copying an mdtest that targets all platforms into the external-dependencies suite.","solutions":["Add a concrete platform to the mdtest frontmatter, e.g. `platform: linux` (or darwin/win32)","Only run the mdtest externally on a platform the test explicitly pins","If the test truly is platform-independent, skip external-dependency setup instead of requiring uv resolution"],"exampleFix":"// before (mdtest frontmatter)\n---\nexternal_dependencies: true\n---\n// after\n---\nexternal_dependencies: true\nplatform: linux\n---","handlingStrategy":"validation","validationCode":"import re, sys\ntext = open(mdtest_path).read()\nfrontmatter = text.split('---')[1]\nm = re.search(r'^platform:\\s*(all|linux|darwin|win32)', frontmatter, re.M)\nif m and m.group(1) == 'all':\n    sys.exit(f\"{mdtest_path}: external-dependency mdtests must pin a concrete platform\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set a concrete `platform:` in the frontmatter of external-dependency mdtests","Add a CI lint that scans external mdtests for platform: all","Copy frontmatter from an existing external mdtest when creating new ones"],"tags":["testing","mdtest","configuration","uv"],"backgroundTag":"missing-required-config","analyzedSha":"26f38c119cac42e4d320ba08f09224fdec74af2c","analyzedAt":"2026-09-05T10:32:37.492Z","contentChangedAt":"2026-09-05T10:32:37.492Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}