@@ -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