////
  // Copyright (c) 2021, 2026 Contributors to the Eclipse Foundation
  //
  // This program and the accompanying materials are made
  // available under the terms of the Eclipse Public License 2.0
  // which is available at https://www.eclipse.org/legal/epl-2.0/
  //
  // SPDX-License-Identifier: EPL-2.0
////

include::_initCommon.adoc[]

== Python Execution Engine

=== Introduction

The execution engine can be used to execute an LSAT scenario (as defined in an LSAT dispatching file) against a physical or virtualized environment.
From the LSAT specification a resource task graph is generated which represents tasks, their allocations to resources (peripherals) and their dependencies.
The execution engine drives this graph and orchestrates invocation of peripheral behaviour on the target environment.

The engine is implemented using a thread-pool executor where one thread is reserved for every peripheral declared in the specification.
Tasks in the resource task graph are allocated to a peripheral and are executed on that peripheral's reserved thread.
When the engine executes a task it invokes the corresponding method on the peripheral skeleton.

Peripheral skeletons are generated from the LSAT specification: for each peripheral a Python skeleton class is created that provides placeholder methods for all simple actions and move operations the peripheral can perform.
Integrators should implement or extend these skeleton classes so the placeholder methods perform the actual interactions with physical or virtual devices.

image::{imgsdir}/ExecutionEngine-Overview.png[]


.Generated peripheral skeleton example

The LSAT tooling generates a Python skeleton class for each peripheral declared in the specification.
Below is a short example (based on the Tutorial) showing the style of the generated action and move methods.
Integrators should add their implementation between the "Start of user code" and "End of user code" comment markers.

[source,python]
----
#!/usr/bin/env python

...

def robot1_m_apply_brake(**kwargs):
    """
    Executes action apply_brake on peripheral Robot1.M
    """
    getTracer('Robot1.M').info('"Robot1" > "apply_brake"')
    getLogger('Robot1.M').info('> robot1_m_apply_brake')
    # Start of user code robot1_m_apply_brake
    # End of user code
    getLogger('Robot1.M').info('< robot1_m_apply_brake')
    getTracer('Robot1.M').info('"Robot1" < "apply_brake"')

def robot1_m_move(**kwargs):
    """
    Moves peripheral Robot1.M to the specified position.
    By default this is called from the specialized move methods below
    :param **kwargs['dest']: specifies the target position of the move
    """
    getLogger('Robot1.M').info('> robot1_m_move (source=\'%s\', dest=\'%s\')', kwargs.get('source'), kwargs.get('dest'))
    # Start of user code robot1_m_move
    # End of user code
    getLogger('Robot1.M').info('< robot1_m_move')
----

IMPORTANT: Place your implementation code between the "Start of user code" and "End of user code" comments so the generator can safely regenerate the surrounding skeleton without losing your custom logic.

=== Usage

Typical workflow
 
. Generate the execution artifacts from a dispatching model +
  Generate the execution engine artifacts directly from a `.dispatching` file: right-click the `.dispatching` file in the Project Explorer (or the appropriate navigator), then select the context menu item menu:[Generate Python Execution Engine...]. 
  This opens the Execution Engine generation dialog (see the image below).
  The generator produces the Python peripheral skeletons and a runner that wires the resource task graph to the execution engine. +
+
image::{imgsdir}/ExecutionEngine-Generate.png[]

. Implement peripheral behaviour +
  Edit the generated peripheral skeletons and add the platform-specific code between the "Start of user code" and "End of user code" markers in each method.
  This preserves your changes when the skeletons are regenerated.

. Run the scenario +
  For each `.dispatching` file a Python runner script with the same name is generated in the `src-gen` folder of your project.
  This runner file executes the scenario and will drive the resource task graph and call into your implemented peripheral methods.
.. *From the command line:* run the generated Python runner directly with your configured Python interpreter:
+
[source,bash]
----
python src-gen/mydispatching.py
----
..  *From within Eclipse:* optionally install the PyDev plugin for Eclipse to enable direct execution of Python files from the IDE.
  With PyDev installed, right-click the generated runner file and select menu:Run As[Python Run].

. Monitor execution and logs
  The engine emits tracing and logging messages (the generated code uses `getTracer` and `getLogger` calls).
  Inspect the Eclipse Console, the LSAT execution log and the Error Log view for progress, errors and Python tracebacks.

Notes

- The Python Execution Engine is experimental.
  Expect that generated code or the engine internals may change between releases; always preserve user code in the marked regions and keep the generator and engine versions aligned.
- For advanced deployments (remote devices, containers or bespoke device APIs) implement the peripheral skeleton methods to delegate to the appropriate communication layer or driver.

=== Installation

The Python Execution Engine is provided as an optional Eclipse feature: the "LSAT Python Execution Engine Feature (Experimental)". 
It can be installed from the Eclipse LSAT P2 (update site) repository .

==== Install from the P2 repository (Eclipse GUI)

. In Eclipse select menu:Help[Install New Software...]
. Click btn:[Add...], give the update site a name (for example "LSAT Updates") and enter the {lsat} P2 repository URL used by your installation.
  Please consult the {lsat} website for the exact update-site URL.
. From the "Work with" drop-down select the LSAT update site. Expand the categories and locate "LSAT Python Execution Engine Feature (Experimental)".
. Select the feature, click btn:[Next], accept any licenses and complete the install.
  Restart Eclipse when prompted.

==== Notes and verification

- The Python Execution Engine feature is optional and marked experimental in the LSAT product. 
  It depends on core {lsat} features (for example `org.eclipse.lsat.scheduler.feature`); the p2 repository should resolve these automatically when installing.
- After installation verify the feature is present via menu:Help[About Eclipse IDE > Installation Details > Installed Software] and look for the label "LSAT Python Execution Engine Feature (Experimental)".
- You can also check the installed bundles list for `org.eclipse.lsat.engine.python` and `org.eclipse.lsat.engine.python.ui`.