Skip to content

Transformation Migration Guide

LunaModel 0.6.0

LunaModel 0.6.0 introduces breaking changes to the Python transformation API.

The old transformation API is completely removed in 0.6.0. This guide is for users upgrading from an earlier release to the new API, which separates:

  • transformation artifacts used for backward replay
  • analysis results exposed through PassContext
  • transformation history exposed through TransformationRecord

If you were only using built-in passes and PassManager, migration is usually small. If you implemented custom transformation passes, you will likely need to update your pass classes and decorators.


What Changed

PassManager.run(...) now returns TransformationOutput

Old code often treated the pass manager result as an IR-style object.

Use:

Python
from luna_model.transformation import PassManager

output = PassManager([...]).run(model)

result_model = output.model
record = output.record
ctx = output.context

Instead of the old IR, use TransformationOutput.

Backward transformation is record-driven

Use:

Python
backward_solution = output.record.backward(solution)

instead of relying on the old manager-level or outcome-style flow from earlier releases.

Analysis results are no longer accessed through the old cache model

The old AnalysisCache-oriented API has been replaced by:

  • PassContext for reading analysis results during pass execution
  • TransformationRecord for inspecting what happened during execution

Use:

Python
ctx.require_analysis(MyAnalysis.key())

instead of old name-based cache access patterns.

IfElsePass now belongs under .passes

Use:

Python
from luna_model.transformation.passes import IfElsePass

instead of importing it from the root transformation package used in earlier releases.

Custom transformation pass semantics changed

In the new API, TransformationPass returns:

tuple[Model, Artifact]

If your old custom transformation pass returned extra result state, it is conceptually closer to a new CompositePass, which returns:

tuple[Model, Artifact, Result]

That is the main conceptual migration for custom pass authors.


Import Migrations

Replace old imports

Use the new imports directly:

Python
# old
from luna_model.transformation import IR, IfElsePass, TransformationOutcome

# new
from luna_model.transformation.output import TransformationOutput
from luna_model.transformation.passes import IfElsePass

TransformationOutcome does not have a direct new equivalent. In the new API:

  • TransformationPass.forward(...) returns tuple[Model, Artifact]
  • CompositePass.forward(...) returns tuple[Model, Artifact, Result]

Decorators

Decorator names remain available, but their semantics follow the new pass model.

The most important change is @transform: the decorated function must now return an artifact-based result rather than the old outcome/action-style result.


Custom Pass Migration

Old transformation pass

Python
from luna_model.transformation import TransformationPass, TransformationOutcome


class MyPass(TransformationPass):
    @property
    def name(self) -> str:
        return "my-pass"

    def run(self, model, cache):
        return TransformationOutcome(model, ...)

    def backwards(self, solution, cache):
        return solution

New transformation pass

Python
from luna_model.solution.sol import Solution
from luna_model.transformation import TransformationPass
from luna_model.transformation.artifact import NothingArtifact
from luna_model.transformation.context import PassContext


class MyPass(TransformationPass[NothingArtifact]):
    def name(self) -> str:
        return "my-pass"

    def forward(self, model, ctx: PassContext) -> tuple:
        return model, NothingArtifact()

    @classmethod
    def backward(cls, artifact: NothingArtifact, solution: Solution) -> Solution:
        return solution

When to use CompositePass

Use CompositePass if your old transformation pass also produced a result that later passes consumed.

Python
from luna_model.solution.sol import Solution
from luna_model.transformation import CompositePass
from luna_model.transformation.artifact import NothingArtifact


class MyComposite(CompositePass[NothingArtifact, float]):
    PROVIDES = "my-result"

    def name(self) -> str:
        return "my-composite"

    def forward(self, model, ctx) -> tuple:
        result = 1.0
        return model, NothingArtifact(), result

    @classmethod
    def backward(cls, artifact: NothingArtifact, solution: Solution) -> Solution:
        return solution

Analysis and Meta-Analysis Migration

Analysis passes

Old analysis passes often relied on the cache object directly.

Use PassContext in the new API:

Python
from luna_model.transformation import AnalysisPass


class MyAnalysis(AnalysisPass[float]):
    PROVIDES = "my-analysis"

    def name(self) -> str:
        return "my-analysis"

    def run(self, model, ctx) -> float:
        return 1.0

Reading analysis results

Use typed keys:

Python
value = ctx.require_analysis(MyAnalysis.key())

  1. Replace root compatibility imports with the new module paths.
  2. Replace IR usage with TransformationOutput.
  3. Replace old backward calls with output.record.backward(...).
  4. Migrate old analysis-cache access to PassContext.
  5. Migrate custom transformation passes:
  6. use TransformationPass if you only need Model + Artifact
  7. use CompositePass if you also produce a result
  8. Remove any dependency on luna_model.transformation.legacy

Version Boundary

There is no intermediate compatibility release between the old and new transformation APIs. Earlier LunaModel releases used the old transformation API. LunaModel 0.6.0 uses only the new transformation API described in this guide.