> For the complete documentation index, see [llms.txt](https://docs.augelab.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.augelab.com/german/hauptfunktionen/headless/scripting-reference.md).

# Skript-Referenz

Diese Seite dokumentiert die öffentliche Headless-Scripting-API, die vom Python-Paket `studio` bereitgestellt wird.

Der Fokus liegt auf diesen öffentlichen Symbolen:

* `StudioScenario`
* `install_logging_event`
* `enable_logging_stdout`
* `disable_logging_stdout`

Wenn Sie noch nie ein Szenario headless ausgeführt haben, lesen Sie zuerst den Abschnitt "Headless" und kehren Sie dann hierher zurück, um die API-Details zu prüfen.

***

## Imports

Alle hier dokumentierten APIs werden vom Top-Level-Paket `studio` exportiert:

```python
from studio import (
	StudioScenario,
	install_logging_event,
	enable_logging_stdout,
	disable_logging_stdout,
)
```

***

## Typ-Stubs

Die öffentliche Headless-Oberfläche sieht folgendermaßen aus:

```python
from __future__ import annotations

from typing import Any, Callable, Optional


def enable_logging_stdout() -> None: ...
def disable_logging_stdout() -> None: ...
def install_logging_event(event: Callable[[str], None]) -> None: ...


class StudioScenario:
	def __init__(self, *, verification_code: str = "") -> None: ...

	def load_scenario(self, path: str) -> Optional[StudioScenario]: ...
	def load_scenario_raw(self, content: str) -> bool: ...
	def save_scenario(self, path: str) -> bool: ...
	def clear_scenario(self) -> bool: ...
	def disable_load_errors(self) -> StudioScenario: ...
	def load_custom_nodes(self, path: str) -> bool: ...

	def get_ports(
		self,
		input_op_title: str = "Subsystem In",
		output_op_title: str = "Subsystem Out",
	) -> dict[str, list[str]]: ...
	def get_name(self) -> str: ...

	def run(self, args: tuple[Any, ...] = ()) -> tuple[list[Any], ...]: ...
	def run_server(
		self,
		inputs: tuple[Any, ...] = (),
		host: str = "127.0.0.1",
		port: int = 8080,
		display_controls: bool = False,
		header: str = "Scenario Server",
	) -> None: ...
	def cleanup(self) -> bool: ...

	def enable_logging_stdout(self) -> StudioScenario: ...
	def disable_logging_stdout(self) -> StudioScenario: ...
	def install_logging_hook(self, hook: Callable[[str, int], None], level: int = 0) -> StudioScenario: ...

	def installStartEvent(self, event: Callable[..., None]) -> StudioScenario: ...
	def installEndEvent(self, event: Callable[..., None]) -> StudioScenario: ...
	def installStepStartEvent(self, event: Callable[..., None]) -> StudioScenario: ...
	def installStepEndEvent(self, event: Callable[..., None]) -> StudioScenario: ...
```

***

## StudioScenario

`StudioScenario` ist der Haupteinstiegspunkt zum Laden und Ausführen einer `.pmod`-Datei ohne die Desktop-Benutzeroberfläche.

### Konstruktor

```python
scenario = StudioScenario(verification_code="...")
```

#### `verification_code`

Dieser Wert wird zur Lizenzierung für die Headless-Ausführung verwendet.

Gängige Muster:

* Lokal / Server: Übergeben Sie den Verifikationscode als String.
* Docker / CI: Mounten Sie eine Lizenzdatei in den Container und übergeben Sie den **Pfad** als `verification_code`.

> ⚠️ Warnung: Für nicht-interaktive Umgebungen (Docker/CI/Services) immer `verification_code` explizit übergeben.

***

### Typischer Ablauf

In den meisten Skripten:

1. Erstellen Sie das Szenario (`StudioScenario(...)`).
2. Laden Sie eine `.pmod` (`load_scenario(...)`).
3. Führen Sie es aus (`run(...)`).
4. Bereinigen Sie (`cleanup()`).

Beispiel:

```python
import os

from studio import StudioScenario, enable_logging_stdout


def main() -> None:
	# Optional: gibt Laufzeit-Logs auf stdout aus (nützlich beim Debugging).
	enable_logging_stdout()

	verification_code = os.environ.get("AUGELAB_VERIFICATION_CODE", "")
	scenario = StudioScenario(verification_code=verification_code)

	try:
		loaded = scenario.load_scenario("your_scenario.pmod")
		if loaded is None:
			raise FileNotFoundError("Could not load .pmod file")

		# Wenn Ihr Szenario N Eingangsports hat, müssen Sie genau N Argumente übergeben.
		result = scenario.run(args=())
		print("Scenario result:", result)
	finally:
		scenario.cleanup()


if __name__ == "__main__":
	main()
```

> ℹ️ Hinweis: `cleanup()` ist wichtig in lang laufenden Prozessen (Services, Batch-Jobs), um Speicher freizugeben und den Laufzeitzustand zurückzusetzen.

***

### Laden einer `.pmod`

```python
scenario.load_scenario("path/to/scenario.pmod")
```

* Gibt `StudioScenario` bei Erfolg zurück.
* Gibt `None` zurück, wenn der Pfad nicht existiert.

Wenn Ihr Szenario auf externe Ressourcen verweist, behalten Sie die gleiche Verzeichnisstruktur bei wie auf dem Desktop (siehe Abschnitt „Transferring .pmod files“).

***

### Ausführen eines Szenarios

```python
outputs = scenario.run(args=(... ,))
```

Die Laufzeit validiert, dass die Anzahl der Argumente mit der Anzahl der Szenarioeingänge übereinstimmt.

Wenn Ihre `.pmod` hat:

* 0 Eingänge: rufen Sie `scenario.run()` oder `scenario.run(())` auf
* 1 Eingang: rufen Sie `scenario.run((value,))` auf
* 2 Eingänge: rufen Sie `scenario.run((value1, value2))` auf

> ⚠️ Warnung: `args` muss ein Tuple sein. Für einen einzelnen Eingang nicht das abschließende Komma vergessen: `(value,)`.

***

## Weitere StudioScenario-Methoden

Dieser Abschnitt beschreibt zusätzliche öffentliche Methoden, die Sie für Automatisierung und Debugging verwenden können.

### Laden ohne Fehler bei fehlenden Ressourcen

Wenn Sie Szenarien zwischen Maschinen/Containern verschieben und einige Ressourcen möglicherweise nicht verfügbar sind, können Sie permissiver laden:

```python
from studio import StudioScenario

scenario = StudioScenario(verification_code="YOUR_CODE")
scenario.disable_load_errors()
scenario.load_scenario("scenario.pmod")
```

### Laden / Speichern

```python
scenario.load_scenario_raw(content="...")
scenario.save_scenario("out.pmod")
scenario.clear_scenario()
```

### Custom Nodes

Laden Sie benutzerdefinierte Node-Python-Module aus einem Ordner:

```python
scenario.load_custom_nodes("path/to/custom_nodes")
```

> ⚠️ Warnung: Dies importiert Python-Dateien dynamisch. Laden Sie nur vertrauenswürdigen Code.

### Szenario-Name

```python
name = scenario.get_name()
```

### Ports (Szenario Eingänge/Ausgänge)

Sie können die Namen der Eingangs-/Ausgangsports abfragen:

```python
ports = scenario.get_ports()
print("inputs:", ports["inputs"])
print("outputs:", ports["outputs"])
```

### Einen Webserver starten (optional)

Wenn Sie einen Szenario-Runner per HTTP bereitstellen möchten:

```python
scenario.run_server(host="0.0.0.0", port=8080)
```

### Events

Installieren Sie Lifecycle-Callbacks rund um die Szenarioausführung:

```python
def on_start() -> None:
	print("Scenario started")


scenario.installStartEvent(on_start)
```

***

## Logging-Hilfen

AugeLab Studio verfügt über einen Laufzeit-Logger, der von Blöcken und Szenarien verwendet wird. Im Headless-Modus möchten Sie typischerweise eines der folgenden:

* Logs während der Entwicklung auf stdout ausgeben
* Logs in Ihr eigenes Logging-System weiterleiten

Diese Hilfsfunktionen sind global (sie beeinflussen den Laufzeit-Logger, der von Ihrem Headless-Szenario verwendet wird).

***

### enable\_logging\_stdout()

Aktiviert die „freundliche“ Laufzeitprotokollierung auf stdout.

Verwenden Sie dies, wenn Sie Block-/Szenario-Logs in der Konsole sehen möchten:

```python
from studio import enable_logging_stdout

enable_logging_stdout()
```

***

### disable\_logging\_stdout()

Deaktiviert die Laufzeitprotokollierung nach stdout.

Nützlich wenn:

* Sie `install_logging_event(...)` verwenden und doppelte Logs vermeiden möchten
* Sie saubere Ausgabe möchten (nur eigene `print(...)`-/Logger-Ausgaben)

```python
from studio import disable_logging_stdout

disable_logging_stdout()
```

***

### install\_logging\_event(event: Callable\[\[str], None])

Installiert einen Callback, der Laufzeit-Lognachrichten empfängt.

Das ist der einfachste Weg, AugeLab-Laufzeitlogs in Ihr eigenes Logging-Framework zu integrieren.

```python
import logging

from studio import install_logging_event, disable_logging_stdout

logger = logging.getLogger("augelab")


def forward_to_python_logging(msg: str) -> None:
	logger.info(msg)


disable_logging_stdout()
install_logging_event(forward_to_python_logging)
```

### StudioScenario.install\_logging\_hook(hook, level=0)

Wenn Sie bevorzugen, Hooks pro Szenario zu installieren (mit Filterung nach Level), verwenden Sie:

```python
def hook(msg: str, level: int) -> None:
	print(level, msg)


scenario.install_logging_hook(hook, level=20)
```

> ⚠️ Warnung: Halten Sie Ihren Callback schnell. Wenn Sie schwere Arbeit (I/O, Netzwerk) durchführen müssen, ziehen Sie in Betracht, Nachrichten zu puffern und diese in einem anderen Thread/Prozess zu verarbeiten.

***

## Empfohlene Muster

### 1) Umgebungsvariable für Lizenzierung

Für Skripte, die in unterschiedlichen Umgebungen (lokal vs CI vs Docker) laufen, ist das Übergeben von `verification_code` über eine Umgebungsvariable praktisch portabel:

```python
import os
from studio import StudioScenario

scenario = StudioScenario(verification_code=os.environ["AUGELAB_VERIFICATION_CODE"])
```

### 2) Immer mit try/finally aufräumen

```python
from studio import StudioScenario

scenario = StudioScenario(verification_code="YOUR_CODE")
try:
	scenario.load_scenario("scenario.pmod")
	scenario.run(())
finally:
	scenario.cleanup()
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.augelab.com/german/hauptfunktionen/headless/scripting-reference.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
