Files
triggerdotdev--trigger.dev/packages/python/src/extension.ts
T
Chris Arderne c7861be520 chore: activate no-unused-vars and import linters (#4096)
Once this is merged, oxlint is at a pretty sensible baseline.

**Enable `no-unused-vars`, `typescript/consistent-type-imports`, and
`import/no-duplicates` lint rules**

Turns on three previously-disabled oxlint rules across the monorepo and
fixes all violations:

- **`no-unused-vars`** – enabled as an error with standard ignore
patterns: unused function arguments are ignored by default (`args:
"none"`), variables/caught errors/destructured array elements prefixed
with `_` are allowed, and rest siblings are permitted.
- **`typescript/consistent-type-imports`** – enforced as an error; all
type-only imports now use the `import type` syntax.
- **`import/no-duplicates`** – enforced as an error; duplicate import
statements from the same module have been merged.

The remaining commits clean up the violations found across the codebase:
removing unused variables/imports/type aliases, adding `_` prefixes to
intentionally unused bindings, fixing duplicate imports, and converting
value imports to `import type` where appropriate.
2026-07-02 11:37:05 +01:00

157 lines
4.5 KiB
TypeScript

import fs from "node:fs";
import assert from "node:assert";
import { addAdditionalFilesToBuild } from "@trigger.dev/build/internal";
import type { BuildManifest } from "@trigger.dev/core/v3";
import type { BuildContext, BuildExtension } from "@trigger.dev/core/v3/build";
export type PythonOptions = {
requirements?: string[];
requirementsFile?: string;
/**
* [Dev-only] The path to the python binary.
*
* @remarks
* This option is typically used during local development or in specific testing environments
* where a particular Python installation needs to be targeted. It should point to the full path of the python executable.
*
* Example: `/usr/bin/python3` or `C:\\Python39\\python.exe`
*/
devPythonBinaryPath?: string;
/**
* An array of glob patterns that specify which Python scripts are allowed to be executed.
*
* @remarks
* These scripts will be copied to the container during the build process.
*/
scripts?: string[];
};
const splitAndCleanComments = (str: string) =>
str
.split("\n")
.map((line) => line.trim())
.filter((line) => line && !line.startsWith("#"));
export function pythonExtension(options: PythonOptions = {}): BuildExtension {
return new PythonExtension(options);
}
class PythonExtension implements BuildExtension {
public readonly name = "PythonExtension";
constructor(private options: PythonOptions = {}) {
assert(
!(this.options.requirements && this.options.requirementsFile),
"Cannot specify both requirements and requirementsFile"
);
if (this.options.requirementsFile) {
assert(
fs.existsSync(this.options.requirementsFile),
`Requirements file not found: ${this.options.requirementsFile}`
);
this.options.requirements = splitAndCleanComments(
fs.readFileSync(this.options.requirementsFile, "utf-8")
);
}
}
async onBuildComplete(context: BuildContext, manifest: BuildManifest) {
await addAdditionalFilesToBuild(
"pythonExtension",
{
files: this.options.scripts ?? [],
},
context,
manifest
);
if (context.target === "dev") {
if (this.options.devPythonBinaryPath) {
process.env.PYTHON_BIN_PATH = this.options.devPythonBinaryPath;
}
return;
}
context.logger.debug(`Adding ${this.name} to the build`);
context.addLayer({
id: "python-installation",
image: {
instructions: splitAndCleanComments(`
# Install Python
RUN apt-get update && apt-get install -y --no-install-recommends \
python3 python3-pip python3-venv && \
apt-get clean && rm -rf /var/lib/apt/lists/*
# Set up Python environment
RUN python3 -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
`),
},
deploy: {
env: {
PYTHON_BIN_PATH: `/opt/venv/bin/python`,
},
override: true,
},
});
if (this.options.requirementsFile) {
if (this.options.requirements) {
context.logger.warn(
`[pythonExtension] Both options.requirements and options.requirementsFile are specified. requirements will be ignored.`
);
}
// Copy requirements file to the container
await addAdditionalFilesToBuild(
"pythonExtension",
{
files: [this.options.requirementsFile],
},
context,
manifest
);
// Add a layer to the build that installs the requirements
context.addLayer({
id: "python-dependencies",
image: {
instructions: splitAndCleanComments(`
# Copy the requirements file
COPY ${this.options.requirementsFile} .
# Install dependencies
RUN pip install --no-cache-dir -r ${this.options.requirementsFile}
`),
},
deploy: {
override: true,
},
});
} else if (this.options.requirements) {
context.addLayer({
id: "python-dependencies",
build: {
env: {
REQUIREMENTS_CONTENT: this.options.requirements?.join("\n") || "",
},
},
image: {
instructions: splitAndCleanComments(`
ARG REQUIREMENTS_CONTENT
RUN echo "$REQUIREMENTS_CONTENT" > requirements.txt
# Install dependencies
RUN pip install --no-cache-dir -r requirements.txt
`),
},
deploy: {
override: true,
},
});
}
}
}