# Python Environments

{% hint style="warning" %}
Python support is (and likely will remain) experimental by nature, because Python packages do not typically test on a WebAssembly platform. Thus, new versions of packages may break your Pyodide-Obit workflow and not all existing pakages will work.
{% endhint %}

Obit FedDDL supports Python environments using [Pyodide](https://pyodide.org/en/stable/), which is a port of CPython that works in the browser. We pin Pyodide v0.27.7 and Python support may be enabled via the Workload `initializationOptions` object.

### Learn by doing?

See an example workload of Pyodide [here](https://docs.obitmc.com/for-research/practical-examples/full-pyodide-example) (DQN on the Pendulum environment via the [Gymnasium](https://gymnasium.farama.org/) python package)

### Caveats

Note that this support is provided via a virtual machine running via WebAssembly in the browser, which means that it may not have support for all packages. Additionally, some CPU features such as SIMD (SSE/AVX/NEON) may not be available, and GPU passthrough is not supported. For this reason, it is recommended for performance-dependent applications to rewrite the environment in Obit-native syntax (using the Environment API).

### Unsupported / risky packages

* Anything requiring native extensions (C/C++/Fortran) not prebuilt for Pyodide (most of NumPy/SciPy stack is available, but many ML libs are not).
* GPU-backed packages (CUDA, ROCm), OpenCL, Vulkan — GPU passthrough is not supported.
* Packages that spawn processes or rely on POSIX syscalls not present in the browser sandbox.
* Large wheels pulled from PyPI at runtime may exceed browser memory or fetch limits; prefer small, pure-Python deps.

### Minimal example

{% code title="initialization.js" %}

```javascript
const initializationOptions = {
	pyodide: {
		enabled: true,
		packages: ["micropip"], // optional extra packages
	}
};

// In your workload (RL example):
const autovectorizeInfo = { enabled: true };

const session = new ReinforcementLearningSession(
	ACTION_COUNT,
	TOTAL_SAMPLES,
	TOTAL_ROUNDS,
	BATCH_SIZE,
	EPOCHS_PER_ROUND,
	MIN_CLIENTS_TO_START,
	model,
	Environment,            // JS or Python-wrapped env
	initializationOptions,
	AlgorithmClass,
	algorithmConfig,
	autovectorizeInfo
);
```

{% endcode %}

On the client, Pyodide is initialized when `initializationOptions.pyodide.enabled` is true. Additional packages listed in `packages` are loaded via `micropip` (keep these minimal to avoid long load times).

### Structuring a Python Environment class

The current pattern for Python environments mirrors the JS [Environment API](https://docs.obitmc.com/for-research/workload-types/model-training/reinforcement-learning/environment-api):

* Define a Python class named `Environment` with methods:
  * `__init__(self, config: dict)` — accept only serializable config.
  * `reset(self)` — returns the initial state (list/tuple of numbers); may be awaited on the JS side.
  * `step(self, action)` — returns a dict with keys `state`, `reward`, `done` (and optionally `info`, `truncated`).
* Avoid capturing globals; keep the class self-contained. No file I/O, sockets, or multiprocessing.
* Keep computation lightweight; heavy numeric code may be slow in Pyodide. Prefer pure Python + minimal NumPy where available.
* Return plain Python lists/tuples/numbers; avoid custom objects in the step/reset payloads.

Example sketch (Python, to be executed inside Pyodide):

{% code title="environment.py" %}

```python
class Environment:
		def __init__(self, config=None):
				cfg = config or {}
				self.max_steps = cfg.get("maxEpisodeSteps", 200)
				self.state = [0.0, 0.0]
				self.steps = 0

		def reset(self):
				self.state = [0.0, 0.0]
				self.steps = 0
				return self.state

		def step(self, action):
				# simple dynamics placeholder
				self.state[0] += float(action)
				self.state[1] -= float(action)
				self.steps += 1
				done = self.steps >= self.max_steps
				reward = 1.0 if not done else 0.0
				return {"state": self.state, "reward": reward, "done": done}
```

{% endcode %}

### Integration notes

* Package loading: only list small, pure-Python deps in `initializationOptions.pyodide.packages`; large wheels can stall or fail. If a package is missing in Pyodide’s index, it likely won’t work.
* Performance: Pyodide runs in WASM; no SIMD/GPU guarantees. For performance-critical envs, prefer implementations using the [Obit Environment API](https://docs.obitmc.com/for-research/workload-types/model-training/reinforcement-learning/environment-api).
* Logging/metrics semantics are unchanged. Env outputs are consumed by the existing JS algorithm/runtime and logged as usual.

### Status

Python environments are experimental and best-effort. Expect breakage with some packages or Pyodide updates.
