# Python with Elide

> Add Python to Elide, run a Python 3.13 program with the standard library, and test it with unittest; then add packages or JavaScript interop.

Python support is experimental. This quickstart runs a program using the bundled standard library, then tests it
with unittest. No third-party packages are needed.

> [!TIP] No CPython install
> Elide runs Python 3.13 and its standard library itself.

## Install

[Install Elide](https://elide.help/docs/installation) using a method that [supports Python](https://elide.help/docs/installation#python), then add the Python
component if it is not already included:

```bash
elide setup python
elide info
```

`elide info` should list `python` on its `Languages:` line. If the shell cannot find `elide`, follow
[Verify the install](https://elide.help/docs/installation#verify-the-install). If Python support is missing, see
[Python is not installed](https://elide.help/docs/troubleshooting#python-is-not-installed).

`elide setup python --channel=release` or `--channel=nightly` picks the channel; `--force` reinstalls the component.

## Run Python

Create a directory for this example:

```bash
mkdir hello-python
cd hello-python
```

Save this as `greeting.py`:

```python
import json


def greeting(name: str) -> str:
    return f"Hello, {name}!"


if __name__ == "__main__":
    print(json.dumps({"message": greeting("Ada")}))
```

```bash
elide python greeting.py
```

```terminaloutput
{"message": "Hello, Ada!"}
```

The `json` import uses the standard library included with the Python component.

## Tests

Create `test_greeting.py` in the same directory:

```python
import unittest

from greeting import greeting


class GreetingTest(unittest.TestCase):
    def test_names_the_caller(self):
        self.assertEqual(greeting("Ada"), "Hello, Ada!")
```

Run unittest as a module:

```bash
elide python -m unittest -v test_greeting
```

The runner should report one test and `OK`. If it cannot import `greeting` or `test_greeting`, check the filenames
and run the command from `hello-python`.

`elide test` does not discover Python tests. For discovery across several files or pytest, see
[Python tests](https://elide.help/docs/python-testing).

## Next steps

- [Add packages](https://elide.help/docs/python-packages): install dependencies with the optional Python package tooling, or use a compatible
  external virtual environment.
- [Run a project entry point](https://elide.help/docs/python-toolchain#run-project-scripts): use the scripts in `pyproject.toml`.
- [Call JavaScript from Python](#javascript-interop): share values between languages.
- [Check compatibility](#known-limitations) before moving an existing application.

## Command-line arguments

`elide python` takes Python interpreter arguments before the script or module. For an existing `app.py`:

```bash
elide python app.py --name Elide --count 2   # sys.argv: ['app.py', '--name', 'Elide', '--count', '2']
elide python -c 'import sys; print(sys.version)'
elide python -m json.tool input.json
echo 'print("from stdin")' | elide python -
```

Tokens after the script, `-c CMD`, or `-m MODULE` go to the program. Bare `elide python` starts the REPL in a
terminal and reads standard input otherwise.

<img src="https://elide.help/assets/demos/python-cli.gif" alt="Running a Python program with command-line arguments in Elide" width="1591" height="764" loading="lazy" decoding="async" class="rounded-lg border border-border my-6 w-full" />

The general commands run `.py` files with the same `sys.argv`:

```bash
elide app.py
elide run app.py
elide -l python -s 'print(1 + 1)'
```

### Interpreter options

Put these before the script, `-c`, or `-m`. `elide --help-all` lists them under "Python interpreter options".

| Flag | Effect |
| --- | --- |
| `-c CMD` | Run `CMD` as the program; trailing tokens become `sys.argv[1:]`. |
| `-m MODULE` | Run a library module as `__main__`. |
| `-s` | Don't add the user site directory to `sys.path`. |
| `-I` | Isolated mode. |
| `-E` | Ignore `PYTHON*` environment variables. |
| `-S` | Don't `import site` on startup. |
| `-P` | Don't prepend a potentially unsafe path to `sys.path`. |
| `-B` | Don't write bytecode files. |
| `-u` | Unbuffered standard output and error. |
| `-O` | Optimization level; repeat for `-OO`. |
| `-b` | Warn on `bytes`/`str` comparisons; repeat to raise errors. |
| `-W ARG` | Warning control; repeatable. |
| `-x` | Accepted for compatibility; no effect. |

Two flags are on by default: `-S`, because Elide builds `sys.path` itself and skips `site` for startup time, and
`-B`. `sys.flags` reports both. To import `site` (`.pth` files, `sitecustomize`), pass
`-X polyglot.python.NoSiteFlag=false`; to write bytecode, pass `-X polyglot.python.DontWriteBytecodeFlag=false`.

## Standard library

The standard library includes `json`, `pathlib`, `sqlite3`, `ssl`, `zlib`, and `ctypes`. `bz2` and `lzma` need no
system `libbz2` or `liblzma`. For the database drivers Elide includes, see [Databases](https://elide.help/docs/api-database).

## JavaScript interop

With `--interop`, Python evaluates JavaScript through the built-in `elide` module:

```python
# sum.py
from elide import js

print(js("[1, 2, 3].reduce((a, b) => a + b, 0)"))
```

```bash
elide --interop python sum.py
```

JavaScript and TypeScript import a Python module's default export:

```javascript
// main.mjs
import mod from "./mod.py";
console.log(mod.hello());
```

```bash
elide --interop run main.mjs
```

Without `--interop`, these calls fail. See [Languages and Interop](https://elide.help/docs/languages).

## Third-party packages

Package installation requires pytools, the optional package tooling installed with the Python component. Use
`elide uv install PACKAGE`, or `elide install --ecosystems=pypi` for declared dependencies. Plain `elide install`
retains its Maven default.

Packages installed through Elide use the project's automatic environment. A compatible Python 3.13 external
virtual environment can also supply packages through `VIRTUAL_ENV`.

Only compatible wheels can be installed; source builds and arbitrary CPython native wheels are not supported.
See [Packages and virtual environments](https://elide.help/docs/python-packages) for setup, commands and limitations.

## Tracing and metrics

The `opentelemetry` API and `logging` export traces, metrics, and logs through Elide, with no SDK installed; see
[OpenTelemetry in Python](https://elide.help/docs/opentelemetry/python).

## Known limitations

- **C extensions**: some C extension modules do not load.
- **macOS**: native module isolation is not available.
- **WebAssembly SIMD**: installing Python disables it; see [WebAssembly with Elide](https://elide.help/docs/wasm#limits).
- **CPython differences**: some edge cases behave differently from CPython 3.13; see the
  [Compatibility Matrix](https://elide.help/docs/compatibility).

## Samples

- [Python calling JavaScript](https://elide.help/docs/code-samples#python-calling-javascript)
- [JavaScript importing Python](https://elide.help/docs/code-samples#javascript-importing-python)
- [Python script](https://elide.help/docs/code-samples#python-script)
