Skip to content

Commit fd2c282

Browse files
committed
Python: Require interpreter to have openrewrite installed for dev builds
Instead of silently bootstrapping a stale PyPI release into a `dev/` directory, dev builds now require the Python interpreter to already have the openrewrite package available. This is the expected setup when using a venv created by `uv sync` in rewrite-python/rewrite/. Release builds continue to bootstrap a pinned version into a version-specific subdirectory under pipPackagesPath.
1 parent f93dd01 commit fd2c282

1 file changed

Lines changed: 21 additions & 31 deletions

File tree

rewrite-python/src/main/java/org/openrewrite/python/rpc/PythonRewriteRpc.java

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -536,23 +536,25 @@ public Builder pythonVersion(String pythonVersion) {
536536

537537
@Override
538538
public PythonRewriteRpc get() {
539-
// For dev builds (version ending in .dev0), check whether the interpreter
540-
// already has the rewrite package (e.g., from a venv with an editable install).
541-
// If so, skip bootstrap and PYTHONPATH prepend so the interpreter's own
542-
// version takes precedence. For release/CI builds, always use pipPackagesPath
543-
// to ensure the correct pinned version.
544539
String version = StringUtils.readFully(
545540
PythonRewriteRpc.class.getResourceAsStream("/META-INF/rewrite-python-version.txt")).trim();
546541
boolean isDevBuild = version.isEmpty() || version.endsWith(".dev0");
547-
boolean interpreterHasRewrite = isDevBuild && pipPackagesPath != null && canImportRewrite(pythonPath);
548-
boolean usePipPackagesPath = pipPackagesPath != null && !interpreterHasRewrite;
549542

550-
// Resolve version-specific subdirectory under pipPackagesPath
543+
// For dev builds, require the interpreter already has the rewrite package
544+
// (e.g., from a venv with an editable install via `uv sync`).
545+
// For release builds, bootstrap into a version-specific subdirectory.
551546
Path resolvedPipPackagesPath = null;
552-
if (usePipPackagesPath) {
553-
String versionDir = isDevBuild ? "dev" : version;
554-
resolvedPipPackagesPath = pipPackagesPath.resolve(versionDir);
555-
bootstrapOpenrewrite(resolvedPipPackagesPath, version, isDevBuild);
547+
if (isDevBuild) {
548+
if (!canImportRewrite(pythonPath)) {
549+
throw new IllegalStateException(
550+
"The Python interpreter at " + pythonPath + " cannot import the 'rewrite' package. " +
551+
"For development builds, the interpreter must already have the openrewrite package installed. " +
552+
"Run 'uv sync' in the rewrite-python/rewrite/ directory to set up an editable install, " +
553+
"then configure the pythonPath to point to the venv's Python executable.");
554+
}
555+
} else if (pipPackagesPath != null) {
556+
resolvedPipPackagesPath = pipPackagesPath.resolve(version);
557+
bootstrapOpenrewrite(resolvedPipPackagesPath, version);
556558
}
557559

558560
Stream<@Nullable String> cmd;
@@ -594,9 +596,8 @@ public PythonRewriteRpc get() {
594596
// If debug source path is set, use it
595597
if (debugRewriteSourcePath != null) {
596598
pythonPathParts.add(debugRewriteSourcePath.toAbsolutePath().normalize().toString());
597-
} else if (pipPackagesPath == null) {
598-
// Only search for development source if pip packages path is not set
599-
// Try to find the Python source in the project structure
599+
} else if (isDevBuild) {
600+
// For dev builds, try to find the Python source in the project structure
600601
// Look for rewrite-python/rewrite/src relative to the working directory
601602
Path basePath = workingDirectory != null ? workingDirectory : Paths.get(System.getProperty("user.dir"));
602603

@@ -661,18 +662,12 @@ private static boolean canImportRewrite(Path pythonPath) {
661662
}
662663

663664
/**
664-
* Ensures the openrewrite Python package is installed in the pip packages directory.
665-
* This is required for the RPC server to start.
665+
* Ensures the pinned openrewrite Python package is installed in the pip packages directory.
666+
* Only used for release builds — dev builds require the interpreter to already have the package.
666667
*/
667-
private void bootstrapOpenrewrite(Path pipPackagesPath, String version, boolean isDevBuild) {
668-
boolean pinVersion = !isDevBuild;
669-
668+
private void bootstrapOpenrewrite(Path pipPackagesPath, String version) {
670669
Path versionMarker = pipPackagesPath.resolve(".openrewrite-version");
671670
if (Files.exists(pipPackagesPath.resolve("rewrite"))) {
672-
// Already installed — check if version matches
673-
if (!pinVersion) {
674-
return;
675-
}
676671
try {
677672
if (Files.exists(versionMarker) &&
678673
version.equals(new String(Files.readAllBytes(versionMarker), StandardCharsets.UTF_8).trim())) {
@@ -683,8 +678,6 @@ private void bootstrapOpenrewrite(Path pipPackagesPath, String version, boolean
683678
}
684679
}
685680

686-
String packageSpec = pinVersion ? "openrewrite==" + version : "openrewrite";
687-
688681
try {
689682
Files.createDirectories(pipPackagesPath);
690683

@@ -693,7 +686,7 @@ private void bootstrapOpenrewrite(Path pipPackagesPath, String version, boolean
693686
"-m", "pip", "install",
694687
"--upgrade",
695688
"--target=" + pipPackagesPath.toAbsolutePath().normalize(),
696-
packageSpec
689+
"openrewrite==" + version
697690
);
698691
pb.redirectErrorStream(true);
699692
if (log != null) {
@@ -727,10 +720,7 @@ private void bootstrapOpenrewrite(Path pipPackagesPath, String version, boolean
727720
throw new RuntimeException("Failed to bootstrap openrewrite package, pip install exited with code " + exitCode);
728721
}
729722

730-
// Write version marker so we can detect stale installs
731-
if (pinVersion) {
732-
Files.write(versionMarker, version.getBytes(StandardCharsets.UTF_8));
733-
}
723+
Files.write(versionMarker, version.getBytes(StandardCharsets.UTF_8));
734724
} catch (IOException e) {
735725
throw new UncheckedIOException("Failed to bootstrap openrewrite package", e);
736726
} catch (InterruptedException e) {

0 commit comments

Comments
 (0)