Skip to content

Commit fd86ff2

Browse files
Fix uv env skipped beside a Poetry plugin (#1916) (#1922)
* Start fix for #1916 Assisted-by: Claude Code:claude-opus-5-5 * Test uv env beside a Poetry plugin table A lockless uv project whose pyproject.toml carries a Poetry plugin table such as [tool.poetry-dynamic-versioning] must still have its UV_PROJECT_ENVIRONMENT crawled. Fails until the lockless-uv gate reads the parsed [tool.poetry] table (#1916). Assisted-by: Claude Code:claude-opus-5-5 * Fix uv env skipped beside a Poetry plugin table A lockless uv project that uses a Poetry plugin such as poetry-dynamic-versioning was mistaken for a Poetry project, because the check looked for the text "[tool.poetry" anywhere in pyproject.toml (plugin tables and comments included). Its UV_PROJECT_ENVIRONMENT was then never crawled, so scan, apply and VEX missed every package installed there. The check now reads the parsed [tool.poetry] table, the same rule Poetry env discovery already uses. Fixes #1916 Assisted-by: Claude Code:claude-opus-5-5 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 6257afa commit fd86ff2

1 file changed

Lines changed: 50 additions & 3 deletions

File tree

‎crates/socket-patch-core/src/crawlers/python_crawler.rs‎

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,8 +1044,9 @@ async fn uv_project_environment_site_packages(
10441044
}
10451045

10461046
/// Whether a manager other than uv records or locks the project at `cwd`:
1047-
/// Poetry, PDM or Pipenv files, or a lockless Poetry (`[tool.poetry]`) or
1048-
/// PDM project.
1047+
/// Poetry, PDM or Pipenv files, or a lockless Poetry (`[tool.poetry]`, read
1048+
/// by [`declares_tool_poetry`], so a plugin table such as
1049+
/// `[tool.poetry-dynamic-versioning]` does not count) or PDM project.
10491050
async fn claimed_by_non_uv_manager(cwd: &Path) -> bool {
10501051
let other_lock = [
10511052
"poetry.lock",
@@ -1061,7 +1062,7 @@ async fn claimed_by_non_uv_manager(cwd: &Path) -> bool {
10611062
|| is_pdm_project(cwd).await
10621063
|| read_regular_to_string(&cwd.join("pyproject.toml"))
10631064
.await
1064-
.is_ok_and(|text| text.contains("[tool.poetry"))
1065+
.is_ok_and(|text| declares_tool_poetry(&text))
10651066
}
10661067

10671068
/// Whether only uv installs for `cwd`, so its env is only ever uv's own: a
@@ -5114,6 +5115,52 @@ mod tests {
51145115
assert!(found.contains(&managed_site), "{found:?}");
51155116
}
51165117

5118+
/// #1916: "is this lockless project Poetry's" reads the parsed
5119+
/// `[tool.poetry]` table, the same rule as Poetry env discovery. A
5120+
/// Poetry plugin table such as `[tool.poetry-dynamic-versioning]`
5121+
/// (common with non-Poetry backends) or a commented-out header does
5122+
/// not hand a lockless uv project to Poetry, so its
5123+
/// `UV_PROJECT_ENVIRONMENT` is still crawled.
5124+
#[tokio::test]
5125+
async fn poetry_plugin_table_does_not_claim_a_lockless_uv_project() {
5126+
let tmp = tempfile::tempdir().unwrap();
5127+
let project = tmp.path().join("app");
5128+
std::fs::create_dir_all(&project).unwrap();
5129+
let site = fake_venv(&project, "env");
5130+
let stray = fake_venv(&project, ".venv");
5131+
let env = env_of(&[("UV_PROJECT_ENVIRONMENT", "env".to_string())]);
5132+
5133+
for pyproject in [
5134+
"[project]\nname = \"app\"\ndynamic = [\"version\"]\n\
5135+
[tool.poetry-dynamic-versioning]\nenable = true\n",
5136+
"[project]\nname = \"app\"\n# [tool.poetry]\n",
5137+
"[project]\nname = \"app\"\n[tool.poetry_bumpversion]\nfile = \"x\"\n",
5138+
] {
5139+
std::fs::write(project.join("pyproject.toml"), pyproject).unwrap();
5140+
assert_eq!(
5141+
find_local_venv_site_packages_with(&project, &env).await,
5142+
vec![site.clone()],
5143+
"{pyproject}"
5144+
);
5145+
}
5146+
5147+
// A real `[tool.poetry]` table, or only a subtable of it, is still
5148+
// Poetry's.
5149+
for pyproject in [
5150+
"[tool.poetry]\nname = \"app\"\n",
5151+
"[project]\nname = \"app\"\n[tool.poetry.dependencies]\npython = \"^3.12\"\n",
5152+
"[project]\nname = \"app\"\n[tool.poetry-dynamic-versioning]\n\
5153+
enable = true\n[tool.poetry]\npackage-mode = false\n",
5154+
] {
5155+
std::fs::write(project.join("pyproject.toml"), pyproject).unwrap();
5156+
assert_eq!(
5157+
find_local_venv_site_packages_with(&project, &env).await,
5158+
vec![stray.clone()],
5159+
"{pyproject}"
5160+
);
5161+
}
5162+
}
5163+
51175164
/// #525: uv syncs a project into `UV_PROJECT_ENVIRONMENT` (absolute, or
51185165
/// relative to the project) instead of `./.venv`, ignoring an
51195166
/// activated venv; the variable means nothing outside a uv project.

0 commit comments

Comments
 (0)