Metadata-Version: 2.1
Name: polyrun
Version: 0.2.0
Summary: Zero-dependency polyglot code execution — run 23 languages from Python
Home-page: https://github.com/og-py3/Polyrun
Author: Haripriyan
Author-email: 
License: UNKNOWN
Keywords: polyglot runner java node nodejs javascript typescript c cpp rust go python ruby php bash perl lua r kotlin haskell swift elixir dart julia groovy zig multiplatform
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Interpreters
Classifier: Topic :: Software Development :: Compilers
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest (>=7) ; extra == 'dev'
Requires-Dist: pytest-cov ; extra == 'dev'
Requires-Dist: ruff ; extra == 'dev'
Requires-Dist: mypy ; extra == 'dev'

<p align="center">
  <img src="logo.svg" alt="Polyrun logo" width="480"/>
</p>

<h3 align="center">⚡ Zero-dependency polyglot code execution</h3>
<p align="center">Run code in <strong>23 languages</strong> from a single Python import — no pip dependencies required.</p>

<p align="center">
  <a href="https://github.com/og-py3/Polyrun/actions/workflows/ci.yml">
    <img src="https://github.com/og-py3/Polyrun/actions/workflows/ci.yml/badge.svg" alt="CI"/>
  </a>
  <a href="https://pypi.org/project/polyrun/">
    <img src="https://img.shields.io/pypi/v/polyrun?color=6e40c9&logo=python&logoColor=white" alt="PyPI"/>
  </a>
  <a href="https://pypi.org/project/polyrun/">
    <img src="https://img.shields.io/pypi/pyversions/polyrun?logo=python&logoColor=white" alt="Python"/>
  </a>
  <a href="LICENSE">
    <img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="MIT License"/>
  </a>
  <a href="https://pypi.org/project/polyrun/">
    <img src="https://img.shields.io/pypi/dm/polyrun?color=2ea44f" alt="Downloads"/>
  </a>
</p>

---

```python
from polyrun import Rust, Node, Go, Python, Bash, Julia, Zig

result = Rust.run('fn main() { println!("Hello from Rust! ⚡"); }')
print(result.text())  # Hello from Rust! ⚡
```

---

## ⚡ Supported languages (23)

| # | Language | Import | Binary needed | Type |
|---|----------|--------|---------------|------|
| 1 | Node.js / JavaScript | `Node`, `JS` | `node` | Interpreted |
| 2 | Python | `Python` | `python3` | Interpreted |
| 3 | Bash | `Bash` | `bash` | Interpreted |
| 4 | Ruby | `Ruby` | `ruby` | Interpreted |
| 5 | PHP | `PHP` | `php` | Interpreted |
| 6 | Perl | `Perl` | `perl` | Interpreted |
| 7 | Lua | `Lua` | `lua` | Interpreted |
| 8 | R | `R` | `Rscript` | Interpreted |
| 9 | TypeScript | `TypeScript`, `TS` | `tsx` / `ts-node` / `npx` | Transpiled |
| 10 | Go | `Go` | `go` | Compiled |
| 11 | Rust | `Rust` | `rustc` | Compiled |
| 12 | C | `C` | `gcc` | Compiled |
| 13 | C++ | `Cpp` | `g++` | Compiled |
| 14 | Java | `Java` | `javac` + `java` | Compiled |
| 15 | Kotlin | `Kotlin` | `kotlinc` + `java` | Compiled to JAR |
| 16 | Swift | `Swift` | `swift` | Interpreted |
| 17 | Haskell | `Haskell` | `runghc` | Interpreted |
| 18 | Elixir | `Elixir` | `elixir` | Interpreted |
| 19 | Dart | `Dart` | `dart` | JIT |
| 20 | Julia | `Julia` | `julia` | JIT |
| 21 | Groovy | `Groovy` | `groovy` | Interpreted |
| 22 | Zig | `Zig` | `zig` | Compiled |

> **No pip dependencies.** Uses only Python's stdlib: `subprocess`, `tempfile`, `shutil`, `json`.
> Language runtimes must be installed separately and on your `PATH`.

---

## ⚡ Installation

```bash
pip install polyrun
```

From source:

```bash
git clone https://github.com/og-py3/Polyrun.git
cd Polyrun
pip install -e .
```

---

## ⚡ Quick start

### Hello world in every language

```python
from polyrun import (
    Node, Python, Ruby, PHP, Bash, Perl, Lua, R, TypeScript,
    Go, Rust, C, Cpp, Java, Kotlin, Swift, Haskell,
    Elixir, Dart, Julia, Groovy, Zig,
)

Node.run("console.log('⚡ node')")
Python.run("print('⚡ python')")
Ruby.run("puts '⚡ ruby'")
PHP.run("echo '⚡ php';")
Bash.run("echo '⚡ bash'")
Perl.run("print '⚡ perl\n';")
Lua.run("print('⚡ lua')")
R.run("cat('⚡ R\n')")
TypeScript.run('const x: string = "⚡ typescript"; console.log(x);')
Go.run('package main\nimport "fmt"\nfunc main(){fmt.Println("⚡ go")}')
Rust.run('fn main(){println!("⚡ rust");}')
C.run('#include <stdio.h>\nint main(){puts("⚡ c");return 0;}')
Cpp.run('#include <iostream>\nint main(){std::cout<<"⚡ cpp"<<std::endl;}')
Java.run('public class Hi{public static void main(String[] a){System.out.println("⚡ java");}}')
Kotlin.run('fun main(){println("⚡ kotlin")}')
Swift.run('print("⚡ swift")')
Haskell.run('main :: IO ()\nmain = putStrLn "⚡ haskell"')
Elixir.run('IO.puts("⚡ elixir")')
Dart.run('void main(){print("⚡ dart");}')
Julia.run('println("⚡ julia")')
Groovy.run("println '⚡ groovy'")
Zig.run('const std=@import("std");\npub fn main()!void{try std.io.getStdOut().writer().print("⚡ zig\\n",.{});}')
```

---

## ⚡ RunResult API

```python
result = Python.run("print('hello')")

result.text()        # "hello"          — stripped stdout
result.lines()       # ["hello"]        — stdout as list
result.json()        # parse stdout as JSON
result.ok()          # True             — returncode == 0
result.stdout        # raw stdout string
result.stderr        # raw stderr string
result.returncode    # integer exit code
result.language      # "Python"
```

---

## ⚡ stdin passthrough

```python
result = Node.run(
    "process.stdin.resume(); let d=''; "
    "process.stdin.on('data', c => d += c); "
    "process.stdin.on('end', () => console.log(d.trim().toUpperCase()));",
    input_data="hello world",
)
print(result.text())  # HELLO WORLD
```

---

## ⚡ Environment variables

```python
result = Bash.run("echo $GREETING", env={"GREETING": "⚡ polyrun"})
print(result.text())  # ⚡ polyrun
```

---

## ⚡ Error handling

```python
from polyrun import Rust
from polyrun.exceptions import CompilationError, PolyRuntimeError, LanguageNotFoundError

try:
    Rust.run("fn main() { this_wont_compile }")

except CompilationError as e:
    print(f"❌ Compile error [{e.language}]: {e.stderr}")

except PolyRuntimeError as e:
    print(f"❌ Runtime error [{e.language}] exit {e.returncode}: {e.stderr}")

except LanguageNotFoundError as e:
    print(f"❌ Install {e.binary} to use {e.language}")
```

| Exception | When raised | Attributes |
|---|---|---|
| `CompilationError` | Compiler exits non-zero | `.language`, `.stderr` |
| `PolyRuntimeError` | Program exits non-zero | `.language`, `.stderr`, `.returncode` |
| `LanguageNotFoundError` | Binary not on PATH | `.language`, `.binary` |

> `RuntimeError` is kept as an alias for `PolyRuntimeError` for backwards compatibility.

---

## ⚡ Pipeline — chain languages

```python
from polyrun import Node, Python, Bash
from polyrun.pipeline import Pipeline

result = (
    Pipeline()
    .then(Node,   "console.log(JSON.stringify({value: 21}))")
    .then(Python, "import sys,json; d=json.load(sys.stdin); print(d['value']*2)")
    .then(Bash,   'read n; echo "⚡ The answer is $n"')
    .run()
)
print(result.text())  # ⚡ The answer is 42
```

---

## ⚡ Bridge — JSON data exchange

```python
from polyrun import Go
from polyrun.pipeline import Bridge

code = """
package main
import ("encoding/json";"fmt";"os")
func main() {
    var d map[string]interface{}
    json.NewDecoder(os.Stdin).Decode(&d)
    nums := d["numbers"].([]interface{})
    sum := 0.0
    for _, n := range nums { sum += n.(float64) }
    fmt.Println(sum)
}
"""
result = Bridge.send(Go, code, data={"numbers": [1,2,3,4,5]})
print(result.text())  # 15
```

---

## ⚡ Check installed languages

```python
from polyrun.detect import check, available

check()   # prints ⚡ Polyrun availability table
```

```
⚡ Polyrun — language availability (8/22 installed)
──────────────────────────────────────────────────
  ✅  Node.js / JavaScript
  ✅  Python
  ❌  Java
  ✅  Rust
  ...
```

---

## ⚡ Architecture

```
┌──────────────────────────────────────────────────────────┐
│                    Your Python code                       │
│  from polyrun import Rust, Node, Go, Julia               │
│  result = Rust.run(code, input_data="hello")             │
└────────────────────────┬─────────────────────────────────┘
                         ▼
┌──────────────────────────────────────────────────────────┐
│  ⚡ polyrun                                               │
│  BaseRunner — 23 language runners                        │
│  Pipeline   — stdout → stdin chaining                    │
│  Bridge     — JSON encode/decode                         │
│  detect     — shutil.which availability checks           │
│  exceptions — CompilationError / PolyRuntimeError / …   │
└────────────────────────┬─────────────────────────────────┘
                         ▼
┌──────────────────────────────────────────────────────────┐
│  subprocess + tempfiles (isolated per run)               │
│  1. Write code → temp file                               │
│  2. Compile if needed (gcc, rustc, javac, kotlinc, zig)  │
│  3. Run via subprocess, capture stdout/stderr            │
│  4. Return RunResult, clean up temp dir                  │
└──────────────────────────────────────────────────────────┘
```

---

## ⚡ Project structure

```
polyrun/
├── polyrun/
│   ├── __init__.py           # 23 runner singletons
│   ├── base.py               # BaseRunner + RunResult
│   ├── pipeline.py           # Pipeline + Bridge
│   ├── detect.py             # ⚡ availability report
│   ├── exceptions.py         # CompilationError / PolyRuntimeError / LanguageNotFoundError
│   ├── py.typed              # PEP 561 marker
│   └── runners/              # 22 runner modules
│       ├── node.py  java.py  c.py    cpp.py   rust.py  go.py
│       ├── python.py  ruby.py  php.py  bash.py  typescript.py  perl.py
│       ├── lua.py  r.py  kotlin.py  haskell.py  swift.py  elixir.py
│       └── dart.py  julia.py  groovy.py  zig.py
├── tests/
│   ├── conftest.py                    # auto-skip for missing runtimes
│   ├── test_base.py
│   ├── test_detect.py
│   ├── test_exceptions.py
│   ├── test_pipeline.py
│   ├── test_runners_interpreted.py    # Node, Python, Ruby, PHP, Bash, Perl, Lua, R
│   ├── test_runners_compiled.py       # C, C++, Rust, Go, Java, Kotlin, Haskell, Swift, Dart, Zig
│   └── test_runners_functional.py     # TypeScript, Elixir, Julia, Groovy + cross-language
├── logo.svg
├── demo.py
├── pyproject.toml
├── setup.py
├── CHANGELOG.md
├── CONTRIBUTING.md
└── LICENSE
```

---

## ⚡ Running the tests

```bash
pip install pytest pytest-cov
pytest tests/ -v

# With coverage report:
pytest tests/ --cov=polyrun --cov-report=term-missing

# Tests auto-skip for any runtime not installed on your machine.
```

---

## ⚡ Publishing to PyPI

```bash
pip install build twine
python -m build
twine upload dist/*
```

---

## ⚡ Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) — adding a new language runner takes about 30 lines of code.

---

## License

MIT — see [LICENSE](LICENSE) for details.


