OpenRewrite now supports Python, offering semantic, repeatable refactors across large codebases using the <strong>Lossless Semantic Tree (LST)</strong>. This...
OpenRewrite Adds Python Support: How Moderne’s LST Brings Semantic Refactoring to Python
OpenRewrite now supports Python, offering semantic, repeatable refactors across large codebases using the Lossless Semantic Tree (LST). This move lets teams modernize code, fix vulnerabilities, and run change programs over a larger portion of their applications and data infrastructure with higher confidence. I'm Ermenildo Valdez Castro, Jr., and I think this matters.
Key Takeaways:
- OpenRewrite for Python provides semantic refactoring via the Lossless Semantic Tree (LST).
- It resolves symbols, preserves intent, and supports large-scale change initiatives across monorepos and multi-repo setups.
- It reduces manual fixes, helps patch vulnerabilities at scale, and enables reliable migrations.
What is OpenRewrite for Python?
Short, clear definition.
When explained fully, OpenRewrite for Python is a semantic refactoring platform that reads Python code, resolves symbols across modules, tracks references, and rewrites code while preserving its original intent—this is accomplished by the company's Lossless Semantic Tree (LST), which keeps structural and symbol information so refactors avoid behavioral regressions, and it integrates with CI to apply recipes safely at scale. I’ve worked on migrations where line-based edits failed because they didn’t understand imports or aliasing, and the difference this makes is real and measurable.
Yes, it’s more than scripted search-and-replace.

Core Benefits/Importance
OpenRewrite gives teams the ability to apply consistent fixes across hundreds or thousands of files.
When I led a migration at a large e-commerce company, we needed to change a logging API across dozens of services, and trying to do that by hand cost us weeks and introduced subtle bugs because of import aliasing and conditional imports—semantic refactors would have resolved names correctly across modules and avoided regressions, which shows how important symbol-aware tools are for real systems; the tool’s strengths are speed, repeatability, and reduced manual toil.
The upside is clear.
Here are the major benefits you should expect:
- Accurate symbol resolution — LST resolves references across files so a refactor updates true callers, not false positives.
- Intent preservation — Rewrite rules can preserve behavior by understanding types and relationships.
- Security fixes at scale — Replace vulnerable patterns across codebases in one pass.
- Migration support — Update deprecated APIs and library usage reliably.
- CI gating — Run recipes in CI and fail safely when a refactor risks regressions.
I've tested similar workflows dozens of times, and the biggest win is saving developer time.
It matters for ethical stewardship of engineering work and for reducing repetitive labor.
Step-by-Step Implementation/Guide
Start small and iterate.
When I introduced a structural refactor in a monorepo, I first created a single recipe, ran it on a small subset of packages, reviewed the diffs in pull requests, and closed the loop by adding smoke tests and type checks—this incremental approach exposed hidden assumptions and let us tune the recipe before broad application, which reduced risk; then we ramped up to run the recipe across the entire monorepo via CI orchestration and recorded the resulting fixes in a changelog so reviewers could audit the changes.
Test early, then scale.
- Audit and pick a small target — Choose a single library or service where the change is low risk.
- Write a focused recipe — Begin with a clear transformation and add guard conditions.
- Run locally — Use feature branches and linting to catch obvious issues.
- Open pull requests — Review diffs, invite domain experts, and iterate on the recipe.
- Automate in CI — Add the recipe as a step that runs and produces PRs or patches when it succeeds.
- Measure and rollback — Track failures, revert problematic runs, and refine rules.
I remember a case where we refactored a database client API; we missed a conditional import used only in a background job, and our initial run caused a runtime error in production because we didn't have a test for that path—after that, we added targeted tests for background jobs and switched the recipe to be opt-in for those modules until tests passed.
Be conservative at first.
Comparison Table
Short, direct compare.
| Feature | OpenRewrite (Python) | LibCST (Competitor) |
|---|---:|---:|
| Semantic symbol resolution | **Yes, via LST** | Partial, best-effort |
| Intent preservation | **High** | Medium |
| Scale for monorepos | **Designed for large codebases** | Good for file-level ops |
| Ecosystem of recipes | **Growing central repo** | Smaller community recipes |
| Integration with CI/CD | **Built-in support** | Requires custom tooling |
Each tool has trade-offs depending on your repo size and the complexity of refactors needed.
Choose the tool that fits your risk tolerance and operational model.
Common Mistakes to Avoid
Most teams try to rewrite everything at once.
I made that mistake once when I pushed a repo-wide refactor without isolating service boundaries, and it caused a cascade of merge conflicts and blocked releases for a week—lessons from that day: always run subsets first, keep changes small, and ensure you have a clear rollback path because real-world systems have edge cases and late-bound imports that tooling may miss; practical safeguards include smoke tests, feature flags, and careful CI gating.
Don’t rush big sweeps.
Other common errors include:
- Skipping review by domain experts.
- Neglecting runtime patterns like metaprogramming and import-time side effects.
- Assuming tests cover every production path.
- Failing to document recipe behavior for future engineers.
Most guides claim automation is risk-free, but the truth is that tools are helpful only when paired with good process and stewardship—consider the care you’d take managing any valuable asset, because code is work that serves people and communities.
Respect the work.
Frequently Asked Questions
Q: Is OpenRewrite safe for production refactors?
A: Yes when paired with tests and review processes. In my experience, semantic tools greatly reduce false positives, but you still need CI gates and human review to catch domain-specific risks. Short answer: safe with safeguards.
Q: Can it handle runtime-only patterns like eval or dynamic imports?
A: It does best with statically analyzable code; runtime metaprogramming still poses challenges. I’ve seen tools miss patterns created by heavy use of importlib, and in those cases the safe path is to whitelist or exclude those modules until additional checks are in place. Keep dynamic code under tighter review.
Q: How does LST differ from AST-based tools?
A: LST preserves symbol binding and relationships while an AST only describes syntax; that difference matters when refactors must respect intent and call semantics. I’ve broken code with AST-only rewrites because the tool misinterpreted an alias; LST aims to avoid that by tracking symbol resolution across modules.
Final Thought
This Python support is a practical win for teams who value the stewardship of their code and the dignity of work, because it reduces repetitive toil and helps engineers focus on higher-value problems rather than endless mechanical edits. I’ve watched teams reclaim weeks of developer time when they applied semantic refactors thoughtfully, and that time was then spent improving quality, mentoring juniors, and serving customers better—small acts of stewardship that echo larger responsibilities.
There’s also a moral side: choose tools and processes that respect human effort and promote justice in the workplace by reducing monotonous labor. Be deliberate, add safeguards, and treat refactors as acts of care for the people who maintain the code next.
—Ermenildo V Castro

Further reading and source material: