> 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/turkish/temel-ozellikler/headless/scripting-reference.md).

# Scripting Reference

Bu sayfa, `studio` Python paketinin sunduğu **kamuya açık başsız (headless) betik API'sini** belgelendirir.

Burada şu herkese açık sembollere odaklanır:

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

Daha önce bir senaryoyu başsız (UI olmadan) çalıştırmadıysanız önce Headless bölümünü okuyun, ardından API ayrıntarları için buraya geri dönün.

***

## İçe Aktarımlar

Buradaki tüm API'ler üst seviye `studio` paketinden dışa aktarılır:

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

***

## Tip İpuçları (Type Stubs)

Kamuya açık başsız yüzeyi şöyle görünür:

```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`, bir `.pmod` dosyasını masaüstü UI'sı olmadan **yüklemek ve çalıştırmak** için ana giriş noktasıdır.

### Yapıcı (Constructor)

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

#### `verification_code`

Bu değer, başsız çalıştırma için lisanslamayı yapılandırmakta kullanılır.

Yaygın kullanım örnekleri:

* **Yerel makine / sunucu:** doğrulama kodu dizesini verin.
* **Docker / CI:** lisans dosyasını konteynere bağlayıp `verification_code` olarak dosya **yolunu** verin.

> **Uyarı:** Etkileşimsiz ortamlarda (Docker/CI/servisler) `verification_code` değerini her zaman açıkça verin.

***

### Tipik yaşam döngüsü

Çoğu betikte şu adımları izlersiniz:

1. Senaryoyu oluşturun (`StudioScenario(...)`)
2. Bir `.pmod` yükleyin (`load_scenario(...)`)
3. Çalıştırın (`run(...)`)
4. Temizlik yapın (`cleanup()`)

```python
import os

from studio import StudioScenario, enable_logging_stdout


def main() -> None:
	# İsteğe bağlı: hata ayıklarken çalışma zamanı günlüklerini stdout'a yazdırır.
	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")

		# Eğer senaryonuzun N adet giriş portu varsa, tam olarak N argüman geçmelisiniz.
		result = scenario.run(args=())
		print("Scenario result:", result)
	finally:
		scenario.cleanup()


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

> **Bilgi:** `cleanup()` uzun süre çalışan süreçlerde (servisler, batch işleri) belleği serbest bırakmak ve çalışma zamanı durumunu sıfırlamak için önemlidir.

***

### Bir `.pmod` yükleme

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

* Başarılıysa `StudioScenario` döner.
* Yol mevcut değilse `None` döner.

Senaryonuz harici kaynaklara referans veriyorsa, masaüstünde kullandığınız aynı dizin yapısını koruyun (bkz. “Transferring .pmod files” bölümü).

***

### Bir senaryoyu çalıştırma

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

Çalışma zamanı, argüman sayısının senaryodaki giriş sayısıyla eşleştiğini doğrular.

`.pmod` dosyanızda:

* 0 giriş varsa: `scenario.run()` veya `scenario.run(())` çağırın
* 1 giriş varsa: `scenario.run((value,))` çağırın
* 2 giriş varsa: `scenario.run((value1, value2))` çağırın

> **Uyarı:** `args` bir tuple olmalıdır. Tek giriş için sonuna virgül eklemeyi unutmayın: `(value,)`.

***

## Diğer StudioScenario Metodları

Bu bölüm, otomasyon ve hata ayıklama için kullanabileceğiniz ek herkese açık metodları kapsar.

### Eksik kaynaklarda yüklemenin başarısız olmasını engelleme

Eğer senaryoları makineler/konteynerler arasında taşıyorsanız ve bazı kaynaklar eksik olabiliyorsa daha toleranslı yükleme seçeneğini kullanabilirsiniz:

```python
from studio import StudioScenario

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

### Yükleme / kaydetme

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

### Özel düğümler (custom nodes)

Bir klasörden özel düğüm Python modüllerini yükleyin:

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

> **Uyarı:** Bu, Python dosyalarını dinamik olarak içe aktarır. Yalnızca güvendiğiniz kodları yükleyin.

### Senaryo adı

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

### Portlar (senaryo girişleri/çıkışları)

Giriş/çıkış port isimlerini sorgulayabilirsiniz:

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

### Bir web sunucusu çalıştırma (isteğe bağlı)

Senaryo çalıştırıcısını HTTP üzerinden açmak isterseniz:

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

### Olaylar (Events)

Senaryo yürütme yaşam döngüsüne ilişkin geri çağırmaları (callback) kurun:

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


scenario.installStartEvent(on_start)
```

***

## Günlükleme (Logging) Yardımcıları

AugeLab Studio, bloklar ve senaryolar tarafından kullanılan bir çalışma zamanı kaydedicisine (logger) sahiptir. Başsız modda tipik olarak şu seçeneklerden birine ihtiyaç duyarsınız:

* geliştirme sırasında günlükleri stdout'a yazdırmak
* günlükleri kendi kayıt sisteminize iletmek

Bu yardımcılar **globaldir** (başsız senaryonuz tarafından kullanılan çalışma zamanı kaydedicisini etkiler).

***

### `enable_logging_stdout()`

Çalışma zamanı günlüklerini stdout'a yazdırmayı etkinleştirir.

Konsolda blok/senaryo günlüklerini görmek istediğinizde kullanın:

```python
from studio import enable_logging_stdout

enable_logging_stdout()
```

***

### `disable_logging_stdout()`

Çalışma zamanı günlüklerinin stdout'a yazdırılmasını devre dışı bırakır.

Aşağıdaki durumlarda kullanışlıdır:

* `install_logging_event(...)` kullanıyor ve günlüklerin çift görünmesini istemiyorsanız
* yalnızca kendi `print(...)`/kendi logger çıktınızı görmek istiyorsanız

```python
from studio import disable_logging_stdout

disable_logging_stdout()
```

***

### `install_logging_event(event: Callable[[str], None])`

Çalışma zamanı günlük mesajlarını alan bir geri çağırma (callback) kurar.

AugeLab çalışma zamanı günlüklerini kendi Python logging çerçevenize entegre etmenin en kolay yoludur.

```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)`

Eğer her bir senaryo için seviye filtrelemesiyle birlikte hook kurmayı tercih ediyorsanız, şu şekilde kullanın:

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


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

> **Uyarı:** Geri çağırmanızı hızlı tutun. Ağır iş (I/O, ağ) gerekiyorsa mesajları tamponlayıp başka bir thread/process içinde işlemek daha iyidir.

***

## Önerilen Kalıplar (Recommended Patterns)

### 1) Lisanslama için ortam değişkeni (Environment variable)

Yerel/CI/Docker gibi farklı ortamlarda çalışan betikler için `verification_code` değerini ortam değişkeni ile geçirmek kodun taşınabilirliğini artırır:

```python
import os
from studio import StudioScenario

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

### 2) Her zaman `try/finally` ile cleanup

```python
from studio import StudioScenario

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