# Python Integration

> **Related:** [Library Mode](library-mode.md) | [Build an AI Day Planner](../../tutorials/first-app/build-ai-day-planner.md)

---

## **Jac Compiles to Python Bytecode**

Jac compiles to Python bytecode, JavaScript, and native machine code (C-ABI compatible), giving you full compatibility with the PyPI, npm, and native ecosystems. You can use your existing Python and JavaScript knowledge while accessing Jac's graph-based and object-spatial programming features.

### **How it Works: Transpilation to Native Python**

Jac programs execute on the standard Python runtime without requiring custom runtime environments, virtual machines, or interpreters. The Jac compiler transpiles Jac source code into standard Python through a multi-stage compilation pipeline that generates optimized Python bytecode. This approach provides several advantages:

* **Standard Python Runtime:** Jac programs execute on the Python runtime, utilizing Python's garbage collector, memory management, and threading model.
* **Full Ecosystem Access:** All packages on PyPI, internal libraries, and Python development tools are compatible with Jac.
* **Readable Output:** The transpiled Python code is clean and maintainable, enabling inspection, debugging, and understanding.

Jac's Python target compiles to standard Python bytecode, giving you native access to the entire Python ecosystem without interop layers or wrappers.

**Example: From Jac to Python**

The following Jac module demonstrates functions, objects, and an entrypoint:

```jac
"""Functions in Jac."""

def factorial(n: int) -> int {
    if n == 0 { return 1; }
    else { return n * factorial(n-1); }
}

obj Person {
    has name: str;
    has age: int;

    def greet() -> None {
        print(f"Hello, my name is {self.name} and I'm {self.age} years old.");
    }
}

with entry {
    person = Person("John", 42);
    person.greet();
    print(f"5! = {factorial(5)}");
}
```

The Jac compiler converts this code into the following Python implementation:

```python
"""Functions in Jac."""
from __future__ import annotations
from jaclang.lib import Obj

def factorial(n: int) -> int:
    if n == 0:
        return 1
    else:
        return n * factorial(n - 1)

class Person(Obj):
    name: str
    age: int

    def greet(self) -> None:
        print(f"Hello, my name is {self.name} and I'm {self.age} years old.")

person = Person('John', 42)
person.greet()
print(f'5! = {factorial(5)}')
```

The compiled output demonstrates how Jac's object-oriented features map to standard Python classes inheriting from `Obj` (Jac's base object archetype), with imports from the `jaclang.lib` package.

!!! note
    The transpiler outputs `from jaclang.jac0core.jaclib import ...` internally. The public API `jaclang.lib` re-exports the same symbols and is the recommended import path for library-mode usage.

---

### **Seamless Interoperability: Import Jac Files Like Python Modules**

Jac integrates with Python through a seamless import mechanism. When jaclang is installed, a `.pth` file automatically registers a lightweight import hook at Python startup, so `.jac` files can be imported using standard Python import statements without requiring build steps, compilation commands, or configuration files.

!!! note
    In previous versions, `import jaclang` was required before importing `.jac` modules. This is no longer necessary: Jac imports work automatically after installation. The explicit `import jaclang` still works and is harmless if present in existing code.

**Key Integration Features:**

* **Bidirectional Module Imports:** Python files can import Jac modules, and Jac files can import Python modules using standard import syntax. Modules written in `.jac` and `.py` can be used interchangeably within a project.

* **Incremental Adoption:** Jac can be added to existing Python projects without restructuring the codebase. Python files can remain unchanged while Jac modules are introduced where beneficial.

* **Standard Import Syntax:** The same `import` statements used for Python modules work with `.jac` files, requiring no special syntax or additional tools.

**Example: Importing Across Languages**

Consider a Jac module containing graph utilities:

```jac
# graph_tools.jac
node Task {
    has name: str;
    has priority: int;
}
```

This module can be imported in Python using standard import syntax:

```python
# main.py
from graph_tools import Task  # Import from .jac file, just works!

# Use Jac classes in Python
my_task = Task(name="Deploy", priority=1)
```

Jac files can also import Python libraries:

```jac
# analyzer.jac
import pandas as pd;
import numpy as np;
import from sklearn.linear_model { LinearRegression }

with entry {
    # NumPy
    arr = np.array([1, 2, 3, 4, 5]);
    print(f"Mean: {np.mean(arr)}");

    # Pandas
    df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]});
    print(df.describe());

    # Scikit-learn
    model = LinearRegression();
}
```

**Inline Python with `::py::` Blocks**

For performance-critical code or complex Python-only APIs, embed Python directly in `.jac` files:

```jac
::py::
import numpy as np

def complex_calculation(data):
    """Pure Python for performance-critical code."""
    arr = np.array(data)
    return arr.mean(), arr.std()
::py::

with entry {
    (mean, std) = complex_calculation([1, 2, 3, 4, 5]);
    print(f"Mean: {mean}, Std: {std}");
}
```

**When to use inline Python:**

* Complex Python-only APIs
* Performance-critical numerical code
* Legacy code integration

**When NOT to use inline Python:**

* Simple imports (use `import` instead)
* New code that could use Jac features

**Implementation Details:** Jac extends Python's native import mechanism using the [PEP 302](https://peps.python.org/pep-0302/) import hook system. When jaclang is installed, a `.pth` file registers a lightweight lazy finder at Python startup. On the first `.jac` import, the full Jac compiler is bootstrapped and a `JacMetaImporter` is registered that enables Python to locate and load `.jac` files. Subsequently, Python's import mechanism automatically checks for `.jac` files alongside `.py` files, compiles them transparently, and loads them into the program. This integration makes Jac modules function as first-class citizens within the Python environment.

---

### **Five Adoption Patterns: Choose Your Integration Level**

Jac provides five adoption strategies that accommodate different development requirements, ranging from pure Python implementations with Jac library support to fully Jac-based applications. The following patterns represent the primary integration approaches:

#### **Pattern Comparison Table**

| Pattern | Use Case | Jac Content | Python Content | Key Benefits | Example Scenario |
|---------|----------|-------------|----------------|--------------|------------------|
| **1. Pure Jac** | New projects, microservices | 100% | 0% | Full Jac language features, modern syntax | Building a new graph-based application with only `.jac` files |
| **2. Jac + Inline Python** | Inline Python in Jac files | Mixed (::py:: blocks) | Embedded inline | Gradual migration, use Python syntax when needed | `.jac` files with embedded Python for legacy logic or complex imports |
| **3. Mostly Jac** | Import Python modules into Jac | 80-95% .jac | 5-20% .py | Jac architecture with existing Python utilities | Project with `.jac` files importing your existing `.py` utility modules |
| **4. Mostly Python** | Import Jac modules into Python | 5-20% .jac | 80-95% .py | Python codebase with select Jac features | Python project with `.py` files importing specialized `.jac` modules for graphs/AI |
| **5. Pure Python + Jac Library** | Conservative adoption | 0% | 100% | No new syntax, just Jac runtime capabilities | Pure `.py` project using Jac runtime via imports and decorators |

```mermaid
graph LR
    A[Pure Jac<br/>100% .jac files] --> B[Jac + Inline Python<br/>::py:: blocks]
    B --> C[Mostly Jac<br/>import .py files]
    C --> D[Mostly Python<br/>import .jac files]
    D --> E[Pure Python<br/>+ Jac Library]

    style A fill:#2d5f3f,stroke:#4CAF50,stroke-width:2px,color:#fff
    style B fill:#3d4f2d,stroke:#8BC34A,stroke-width:2px,color:#fff
    style C fill:#5f4d1a,stroke:#FFC107,stroke-width:2px,color:#fff
    style D fill:#5f3d1a,stroke:#FF9800,stroke-width:2px,color:#fff
    style E fill:#5f2d2d,stroke:#FF5722,stroke-width:2px,color:#fff
```

---

### **Pattern Details and Examples**

**Example Project:** The following examples demonstrate a task manager application that stores tasks and generates AI-powered task descriptions.

**Core Features:**

* Task storage with graph-based relationships
* Task validation (title length check)
* AI-generated task descriptions

Each pattern demonstrates a different approach to implementing this application.

---

#### **Pattern 1: Pure Jac**

This pattern uses exclusively `.jac` files with no Python files required.

**Use Case:** New projects requiring full access to Jac language features

**Directory Structure:**

```
project/
├── main.jac
├── models.jac
└── utils.jac
```

=== "main.jac"
    ```jac
    """Main application."""
    import models, utils;

    walker TaskCreator {
        has title: str;

        can create with Root entry {
            if utils.validate_title(self.title) {
                task = models.Task(title=self.title);
                here ++> task;
                desc = utils.generate_desc(self.title);
                print(f" Created: {task.title}");
                print(f"  AI: {desc}");
            } else {
                print(" Title too short!");
            }
        }
    }

    with entry {
        root spawn TaskCreator(title="Build API");
    }
    ```

=== "models.jac"
    ```jac
    """Task node definition."""

    node Task {
        has title: str;
        has done: bool = False;
    }
    ```

=== "utils.jac"
    ```jac
    """Validation and AI utilities."""

    def validate_title(title: str) -> bool {
        return len(title) > 3;
    }

    def generate_desc(title: str) -> str {
        return f"Task description for: {title}";
    }
    ```

---

#### **Pattern 2: Jac + Inline Python**

This pattern embeds Python code directly within `.jac` files using `::py::` blocks, enabling the use of Python-specific libraries or preservation of existing Python code.

**Use Case:** Incremental migration of Python codebases while maintaining legacy utilities

**Directory Structure:**

```
project/
├── main.jac
└── models.jac
```

=== "main.jac"
    ```jac
    """Application with inline Python validation."""
    import models;

    def generate_desc(title: str) -> str {
        return f"Task description for: {title}";
    }

    ::py::
    # Legacy Python validation - kept as-is
    def validate_title(title):
        """Complex validation logic from old codebase."""
        return len(title) > 3 and title.strip() != ""

    def get_sample_task():
        """Helper from legacy code."""
        return {"title": "Build API"}
    ::py::

    walker TaskCreator {
        can create with Root entry {
            # Use inline Python functions
            task_data = get_sample_task();

            if validate_title(task_data["title"]) {
                task = models.Task(title=task_data["title"]);
                here ++> task;
                desc = generate_desc(task.title);
                print(f" Created: {task.title}");
                print(f"  AI: {desc}");
            } else {
                print(" Title invalid!");
            }
        }
    }

    with entry {
        root spawn TaskCreator();
    }
    ```

=== "models.jac"
    ```jac
    """Task node definition."""

    node Task {
        has title: str;
        has done: bool = False;
    }
    ```

This approach preserves tested Python code while introducing Jac features, supporting incremental migration strategies.

---

#### **Pattern 3: Mostly Jac**

This pattern implements the primary application logic in Jac while importing Python utilities from separate `.py` files.

**Use Case:** Jac-first development that leverages existing Python utilities or shared modules

**Directory Structure:**

```
project/
├── main.jac
├── models.jac
└── validators.py
```

=== "main.jac"
    ```jac
    """Main application - imports Python module."""
    import models;
    import validators;

    def generate_desc(title: str) -> str {
        return f"Task description for: {title}";
    }

    walker TaskCreator {
        has title: str;

        can create with Root entry {
            # Call Python module functions
            if validators.validate_title(self.title) {
                task = models.Task(title=self.title);
                here ++> task;
                desc = generate_desc(task.title);
                print(f" Created: {task.title}");
                print(f"  AI: {desc}");
            } else {
                print(" Title too short!");
            }
        }
    }

    with entry {
        root spawn TaskCreator(title="Build API");
    }
    ```

=== "models.jac"
    ```jac
    """Task node definition."""

    node Task {
        has title: str;
        has done: bool = False;
    }
    ```

=== "validators.py"
    ```python
    """Python validation utilities - shared with other projects."""

    def validate_title(title: str) -> bool:
        """Validator used across multiple projects."""
        return len(title) > 3

    def get_sample_title():
        """Helper to load sample data."""
        return "Build API"
    ```

Jac imports Python modules using standard import mechanisms without requiring configuration.

---

#### **Pattern 4: Mostly Python**

This pattern maintains a Python-first application structure while importing `.jac` modules for graph-based and AI features.

**Use Case:** Existing Python projects incorporating Jac's graph-native and AI capabilities

**Directory Structure:**

```
project/
├── main.py
├── validators.py
└── task_graph.jac
```

=== "main.py"
    ```python
    """Python application importing Jac modules."""
    from validators import validate_title
    from task_graph import Task, TaskCreator, generate_desc
    from jaclang.lib import spawn, root

    def create_task(title: str):
        """Python function using Jac features."""
        if not validate_title(title):
            print(" Title too short!")
            return

        # Use Jac walker
        creator = TaskCreator(title=title)
        spawn(creator, root())

        # Use Jac's AI
        desc = generate_desc(title)
        print(f"  AI: {desc}")

    if __name__ == "__main__":
        create_task("Build API")
    ```

=== "validators.py"
    ```python
    """Python validation utilities."""

    def validate_title(title: str) -> bool:
        """Title validator."""
        return len(title) > 3
    ```

=== "task_graph.jac"
    ```jac
    """Jac module with graph and AI features."""

    node Task {
        has title: str;
        has done: bool = False;
    }

    walker TaskCreator {
        has title: str;

        can create with Root entry {
            task = Task(title=self.title);
            here ++> task;
            print(f" Created: {task.title}");
        }
    }

    def generate_desc(title: str) -> str {
        return f"Task description for: {title}";
    }
    ```

This approach maintains familiar Python syntax while providing access to Jac's graph-based and AI features.

---

#### **Pattern 5: Pure Python + Jac Library**

This pattern uses pure Python with Jac's runtime as a library, without any `.jac` files.

**Use Case:** Conservative adoption paths, teams preferring Python syntax, or existing Python projects

**Directory Structure:**

```
project/
├── main.py
└── validators.py
```

=== "main.py"
    ```python
    """Pure Python using Jac runtime."""
    from jaclang.lib import Node, Walker, on_entry, connect, spawn, root
    from validators import validate_title

    # Define Task node using Jac base class
    class Task(Node):
        title: str
        done: bool

        def __init__(self, title: str):
            super().__init__()
            self.title = title
            self.done = False

    # Define walker using Jac decorators
    class TaskCreator(Walker):
        def __init__(self, title: str):
            super().__init__()
            self.title = title

        @on_entry
        def create(self, here) -> None:
            """Entry point - creates task."""
            if validate_title(self.title):
                task = Task(title=self.title)
                connect(here, task)
                print(f" Created: {task.title}")
                # Note: AI features require .jac syntax
            else:
                print(" Title too short!")

    if __name__ == "__main__":
        creator = TaskCreator(title="Build API")
        spawn(creator, root())
    ```

=== "validators.py"
    ```python
    """Python validation utilities."""

    def validate_title(title: str) -> bool:
        """Title validator."""
        return len(title) > 3
    ```

This pattern provides graph-based capabilities in pure Python without introducing new syntax, utilizing Jac's object-spatial model through library imports.

---

### **Key Takeaways**

Jac's Python bytecode compilation enables complementary use of both languages rather than requiring a choice between them. Key characteristics include:

* **Incremental Adoption:** Projects can begin with Pattern 5 (pure Python + Jac library) and progressively adopt Pattern 1 (pure Jac) as requirements evolve
* **Full Ecosystem Access:** All Python libraries, frameworks, and development tools remain compatible without modification
* **Flexible Integration:** Five adoption patterns accommodate different team preferences and project requirements
* **No Vendor Lock-in:** Transpiled Python code is readable and maintainable, providing migration paths if needed
* **Transparent Interoperability:** A `.pth`-based lazy import hook enables seamless bidirectional imports between `.jac` and `.py` files with zero configuration

| Adoption Pattern | Learning Curve | Migration Effort | Feature Access | Risk Level |
|------------------|---------------|------------------|----------------|------------|
| Pattern 1: Pure Jac | Higher | Higher | 100% Jac features | Low |
| Pattern 2: Jac + Inline Python | Medium | Low | 100% Jac features | Low |
| Pattern 3: Mostly Jac | Medium-High | Medium | 100% Jac features | Low |
| Pattern 4: Mostly Python | Low-Medium | Low | Select Jac features | Low |
| Pattern 5: Pure Python + Library | Low | Very Low | Core runtime only | Very Low |

Jac accommodates both new application development and enhancement of existing Python codebases, providing structured approaches to graph-based and object-spatial programming while maintaining full Python ecosystem compatibility.

### Using Jac from Python

```python
# Import Jac modules using standard Python import syntax, no setup needed!
from my_module import my_function, MyClass

# Use exported functions/classes
result = my_function(arg1, arg2)
instance = MyClass()
```

---

## Type Compatibility

| Jac Type | Python Type |
|----------|-------------|
| `int` | `int` |
| `float` | `float` |
| `str` | `str` |
| `bool` | `bool` |
| `list` | `list` |
| `dict` | `dict` |
| `tuple` | `tuple` |
| `set` | `set` |
| `None` | `None` |
