-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
feat: support pyproject.toml and uv in python extension (#3118) #3177
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,9 @@ import { BuildContext, BuildExtension } from "@trigger.dev/core/v3/build"; | |
| export type PythonOptions = { | ||
| requirements?: string[]; | ||
| requirementsFile?: string; | ||
| pyprojectFile?: string; | ||
| useUv?: boolean; | ||
|
|
||
| /** | ||
| * [Dev-only] The path to the python binary. | ||
| * | ||
|
|
@@ -54,6 +57,14 @@ class PythonExtension implements BuildExtension { | |
| fs.readFileSync(this.options.requirementsFile, "utf-8") | ||
| ); | ||
| } | ||
|
|
||
| if (this.options.pyprojectFile) { | ||
| assert( | ||
| fs.existsSync(this.options.pyprojectFile), | ||
| `pyproject.toml not found: ${this.options.pyprojectFile}` | ||
| ); | ||
| } | ||
|
|
||
| } | ||
|
|
||
| async onBuildComplete(context: BuildContext, manifest: BuildManifest) { | ||
|
|
@@ -88,6 +99,8 @@ class PythonExtension implements BuildExtension { | |
| # Set up Python environment | ||
| RUN python3 -m venv /opt/venv | ||
| ENV PATH="/opt/venv/bin:$PATH" | ||
|
|
||
| ${this.options.useUv ? "RUN pip install uv" : ""} | ||
| `), | ||
| }, | ||
| deploy: { | ||
|
|
@@ -123,7 +136,36 @@ class PythonExtension implements BuildExtension { | |
| # Copy the requirements file | ||
| COPY ${this.options.requirementsFile} . | ||
| # Install dependencies | ||
| RUN pip install --no-cache-dir -r ${this.options.requirementsFile} | ||
| ${this.options.useUv | ||
| ? `RUN uv pip install --no-cache -r ${this.options.requirementsFile}` | ||
| : `RUN pip install --no-cache-dir -r ${this.options.requirementsFile}` | ||
| } | ||
| `), | ||
| }, | ||
| deploy: { | ||
| override: true, | ||
| }, | ||
| }); | ||
| } else if (this.options.pyprojectFile) { | ||
| // Copy pyproject file to the container | ||
| await addAdditionalFilesToBuild( | ||
| "pythonExtension", | ||
| { | ||
| files: [this.options.pyprojectFile], | ||
| }, | ||
| context, | ||
| manifest | ||
| ); | ||
|
|
||
| // Add a layer to the build that installs the dependencies | ||
| context.addLayer({ | ||
| id: "python-dependencies", | ||
| image: { | ||
| instructions: splitAndCleanComments(` | ||
| # Copy the pyproject file | ||
| COPY ${this.options.pyprojectFile} . | ||
| # Install dependencies | ||
| ${this.options.useUv ? "RUN uv pip install ." : "RUN pip install ."} | ||
|
Comment on lines
+160
to
+168
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚩 When using the Was this helpful? React with 👍 or 👎 to provide feedback. |
||
| `), | ||
| }, | ||
| deploy: { | ||
|
|
@@ -144,7 +186,10 @@ class PythonExtension implements BuildExtension { | |
| RUN echo "$REQUIREMENTS_CONTENT" > requirements.txt | ||
|
|
||
| # Install dependencies | ||
| RUN pip install --no-cache-dir -r requirements.txt | ||
| ${this.options.useUv | ||
| ? "RUN uv pip install --no-cache -r requirements.txt" | ||
| : "RUN pip install --no-cache-dir -r requirements.txt" | ||
| } | ||
| `), | ||
| }, | ||
| deploy: { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 Missing mutual-exclusion validation for
pyprojectFileagainstrequirements/requirementsFileThe constructor validates that
requirementsandrequirementsFilecannot both be specified (line 46-48), butpyprojectFileis never checked against either option. BecauseonBuildCompleteuses anif/else ifchain (requirementsFile→pyprojectFile→requirements), conflicting combinations are silently resolved by priority rather than flagged as errors. For example, passing{ pyprojectFile: "pyproject.toml", requirementsFile: "requirements.txt" }silently ignorespyprojectFile, and passing{ pyprojectFile: "pyproject.toml", requirements: ["numpy"] }silently ignoresrequirements. This is inconsistent with the existing assertion pattern that explicitly rejects conflicting options.Was this helpful? React with 👍 or 👎 to provide feedback.