This guide captures the script migration pattern used in the district-scripts history,
moving from old Python 2 Jython-style top-level scripts to the current JPype-based regi_python bridge.
The key mental shift is that your script no longer procedurally runs from top to bottom.
Instead, you define your calculation logic inside a function – a callback – and hand that function to run_headless().
The REGI framework starts the JVM, prepares the execution environment, and then calls your callback.
The top level of your script only needs to define and hand off the callback.
Old scripts typically:
- imported Java classes at module import time
- accessed global
registryand calculation objects at top level - executed the calculation immediately when the file was loaded
- relied on shell wrappers such as
RunHeadlessJython.bator.sh
New scripts should:
- import
regi_sessionandrun_headlessfromregi_python - move Java imports inside a callback, such as
run_calculations(registry)below, whichrun_headlessinvokes once the JVM has started - wrap the calculation logic in a function such as
run_calculations(registry) - keep
registry.getCalculation(...)and Java method calls unchanged - end with
if __name__ == "__main__": with regi_session(): run_headless(run_calculations)
from java.util import Calendar
from java.util import TimeZone
gateCalc = registry.getCalculation(1.0, "Gate Flow")
timeZone = TimeZone.getTimeZone("US/Central")
startCal = Calendar.getInstance(timeZone)
endCal = Calendar.getInstance(timeZone)
gateCalc.computeFlowGroup("SWT", "FOSS", startCal.getTime(), endCal.getTime(), "Flow.FOSS.Project_Total")from regi_python import regi_session, run_headless
def run_calculations(registry):
from java.util import Calendar
from java.util import TimeZone
gateCalc = registry.getCalculation(1.0, "Gate Flow")
timeZone = TimeZone.getTimeZone("US/Central")
startCal = Calendar.getInstance(timeZone)
endCal = Calendar.getInstance(timeZone)
gateCalc.computeFlowGroup("SWT", "FOSS", startCal.getTime(), endCal.getTime(), "Flow.FOSS.Project_Total")
if __name__ == "__main__":
with regi_session():
run_headless(run_calculations)JPype-backed imports should happen after the JVM starts.
Put them inside run_calculations(registry) or a nested helper only called from that callback.
This is the biggest behavioral difference from Jython scripts.
The migration does not change the scriptable REGI API. Calls like these stay the same:
registry.getNames(1.0)registry.getCalculation(1.0, "Inflow")registry.getCalculation(1.0, "Gate Flow")
The change is only the Python wrapper around those calls.
Scripts must be converted from immediate execution to a run_calculations() function.
That keeps import side effects out of the module.
Old scripts often contain lines like:
print "Error Computing Flow Group"Update these to Python 3 syntax:
print("Error Computing Flow Group")Calls such as LoggingOptions.setDbMessageLevel(2) and LoggingOptions.setMetricsEnabled(True) still belong in the script if the district workflow depends on them. They do not move to regi_python; they simply live inside the callback now.
The old RunHeadlessJython launchers are no longer needed. The Python file itself becomes the entry point:
if __name__ == "__main__":
with regi_session():
run_headless(run_calculations)The current district scripts show the same migration shape across several script families:
SWF/InflowCalcComputedInflow.pySWF/InflowCalcComputeEvapAsFlow.pySWF/GateSettings.pySWT/GateFlowGroup1.pySWL/Big3-GateFlow.py
The differences between them are the calculation names, location lists, and optional logging or flow-group loops. The migration pattern itself is the same.