If you need to execute Python scripts in your Trigger.dev project, you can use the pythonExtension build extension via the @trigger.dev/python package.

First, you’ll need to install the @trigger.dev/python package:

npm add @trigger.dev/python

Then, you can use the pythonExtension build extension in your trigger.config.ts file:

import { defineConfig } from "@trigger.dev/sdk/v3";
import { pythonExtension } from "@trigger.dev/python/extension";

export default defineConfig({
  project: "<project ref>",
  build: {
    extensions: [pythonExtension()],
  },
});

This will take care of adding python to the build image and setting up the necessary environment variables to execute Python scripts. You can then use our python utilities in the @trigger.dev/python package to execute Python scripts in your tasks. For example, running a Python script inline in a task:

import { task } from "@trigger.dev/sdk/v3";
import { python } from "@trigger.dev/python";

export const myScript = task({
  id: "my-python-script",
  run: async () => {
    const result = await python.runInline(`print("Hello, world!")`);
    return result.stdout;
  },
});

Adding python scripts

You can automatically add python scripts to your project using the scripts option in the pythonExtension function. This will copy the specified scripts to the build directory during the deploy process. For example:

import { defineConfig } from "@trigger.dev/sdk/v3";
import { pythonExtension } from "@trigger.dev/python/extension";

export default defineConfig({
  project: "<project ref>",
  build: {
    extensions: [
      pythonExtension({
        scripts: ["./python/**/*.py"],
      }),
    ],
  },
});

This will copy all Python files in the python directory to the build directory during the deploy process. You can then execute these scripts using the python.runScript function:

import { task } from "@trigger.dev/sdk/v3";
import { python } from "@trigger.dev/python";

export const myScript = task({
  id: "my-python-script",
  run: async () => {
    const result = await python.runScript("./python/my_script.py", ["hello", "world"]);
    return result.stdout;
  },
});

The pythonExtension will also take care of moving the scripts to the correct location during dev mode, so you can use the same exact path in development as you do in production.

Using requirements files

If you have a requirements.txt file in your project, you can use the requirementsFile option in the pythonExtension function to install the required packages during the build process. For example:

import { defineConfig } from "@trigger.dev/sdk/v3";
import { pythonExtension } from "@trigger.dev/python/extension";

export default defineConfig({
  project: "<project ref>",
  build: {
    extensions: [
      pythonExtension({
        requirementsFile: "./requirements.txt",
      }),
    ],
  },
});

This will install the packages specified in the requirements.txt file during the build process. You can then use these packages in your Python scripts.

The requirementsFile option is only available in production mode. In development mode, you can install the required packages manually using the pip command.

Virtual environments

If you are using a virtual environment in your project, you can use the devPythonBinaryPath option in the pythonExtension function to specify the path to the Python binary in the virtual environment. For example:

import { defineConfig } from "@trigger.dev/sdk/v3";
import { pythonExtension } from "@trigger.dev/python/extension";

export default defineConfig({
  project: "<project ref>",
  build: {
    extensions: [
      pythonExtension({
        devPythonBinaryPath: ".venv/bin/python",
      }),
    ],
  },
});

This has no effect in production mode, but in development mode, it will use the specified Python binary to execute Python scripts.

Streaming output

All of the python functions have a streaming version that allows you to stream the output of the Python script as it runs. For example:

import { task } from "@trigger.dev/sdk/v3";
import { python } from "@trigger.dev/python";

export const myStreamingScript = task({
  id: "my-streaming-python-script",
  run: async () => {
    // You don't need to await the result
    const result = python.stream.runScript("./python/my_script.py", ["hello", "world"]);

    // result is an async iterable/readable stream
    for await (const chunk of streamingResult) {
      console.log(chunk);
    }
  },
});

Environment variables

We automatically inject the environment variables in the process.env object when running Python scripts. You can access these environment variables in your Python scripts using the os.environ dictionary. For example:

import os

print(os.environ["MY_ENV_VAR"])

You can also pass additional environment variables to the Python script using the env option in the python.runScript function. For example:

import { task } from "@trigger.dev/sdk/v3";
import { python } from "@trigger.dev/python";

export const myScript = task({
  id: "my-python-script",
  run: async () => {
    const result = await python.runScript("./python/my_script.py", ["hello", "world"], {
      env: {
        MY_ENV_VAR: "my value",
      },
    });
    return result.stdout;
  },
});