General rules#
This section covers the fundamental rules that apply to all SAF solution code.
No top-level executable code#
Modules must not contain executable code at the top level. Place all logic inside
functions, methods, or if __name__ == "__main__": guards.
When SAF GLOW Engine imports your step modules, any code at the module level executes immediately. This causes side effects, slows startup, and can break the framework entirely.
# setup_step.py
import numpy as np
data = np.zeros(100) # Runs on import — breaks GLOW
result = expensive_function() # Side effect on import
class SetupStep(StepModel): ...
# setup_step.py
from ansys.saf.glow.solution import StepModel, StepSpec, transaction
class SetupStep(StepModel):
"""Setup step — no code runs on import."""
data: list[float] = []
result: float = 0.0
@transaction(self=StepSpec(upload=["data", "result"]))
def initialize(self) -> None:
import numpy as np # Heavy import inside the method
self.data = np.zeros(100).tolist()
self.result = expensive_function()
Test business logic in isolation first#
Validate your domain functions (solvers, transforms, PyAnsys calls) in standalone scripts or unit tests before wiring them into SAF transactions. This catches algorithm bugs early, without the overhead of the full framework.
# logic/beam_solver.py
def compute_deflection(length: float, load: float, modulus: float) -> float:
"""Compute beam deflection — pure function, no SAF dependency."""
return (load * length**3) / (3 * modulus)
# tests/test_beam_solver.py
from logic.beam_solver import compute_deflection
def test_compute_deflection():
result = compute_deflection(length=1.0, load=100.0, modulus=200e9)
assert result > 0
from ansys.saf.glow.solution import StepModel, StepSpec, transaction
from logic.beam_solver import compute_deflection
class BeamStep(StepModel):
"""Beam analysis step."""
length: float = 1.0
load: float = 100.0
modulus: float = 200e9
deflection: float = 0.0
@transaction(self=StepSpec(download=["length", "load", "modulus"], upload=["deflection"]))
def solve(self) -> None:
self.deflection = compute_deflection(self.length, self.load, self.modulus)
Backend-first development#
Build and test all backend logic before writing any frontend code. This rule ensures a stable API layer before you invest time in UI code that depends on it.
Run your solution with saf run and open the auto-generated API documentation at
http://localhost:<port>/docs. From there you can invoke any transaction directly,
inspect request/response payloads, and confirm that every method returns Completed
before writing a single line of frontend code.