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


---

# Agent Instructions: 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/turkish/one-cikan-ozellikler/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.
