-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
feat: add pyproject.toml and uv support for Python tasks #3181
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 | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,22 @@ | ||||||||
| import { resolveDotEnvVars } from "./src/utilities/dotEnv.js"; | ||||||||
| import fs from "node:fs"; | ||||||||
| import { resolve } from "node:path"; | ||||||||
|
|
||||||||
| const tempDir = resolve(process.cwd(), "temp-env-test"); | ||||||||
| if (!fs.existsSync(tempDir)) fs.mkdirSync(tempDir); | ||||||||
|
|
||||||||
| fs.writeFileSync(resolve(tempDir, ".env"), "TEST_VAR=base\nTRIGGER_API_URL=http://base"); | ||||||||
| fs.writeFileSync(resolve(tempDir, ".env.local"), "TEST_VAR=override"); | ||||||||
|
|
||||||||
| console.log("Testing with .env and .env.local..."); | ||||||||
| const vars = resolveDotEnvVars(tempDir); | ||||||||
| console.log("Resolved vars:", vars); | ||||||||
|
|
||||||||
| if (vars.TEST_VAR === "override") { | ||||||||
| console.log("✅ SUCCESS: .env.local overrides .env"); | ||||||||
| } else { | ||||||||
| console.log("❌ FAILURE: .env.local did NOT override .env. Got:", vars.TEST_VAR); | ||||||||
| process.exit(1); | ||||||||
|
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. 🟡 Temp directory not cleaned up when test fails
Suggested change
Was this helpful? React with 👍 or 👎 to provide feedback. |
||||||||
| } | ||||||||
|
|
||||||||
| fs.rmSync(tempDir, { recursive: true, force: true }); | ||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| import { describe, it, expect, vi } from "vitest"; | ||
| import { ZodNamespace } from "../../src/v3/zodNamespace.js"; | ||
| import { z } from "zod"; | ||
| import { Server } from "socket.io"; | ||
| import { createServer } from "node:http"; | ||
|
|
||
| describe("ZodNamespace", () => { | ||
| it("should allow sending messages with the ZodSocketMessageCatalogSchema structure", async () => { | ||
| const io = new Server(createServer()); | ||
|
|
||
| const clientMessages = { | ||
| CLIENT_MSG: { | ||
| message: z.object({ foo: z.string() }) | ||
| } | ||
| }; | ||
|
|
||
| const serverMessages = { | ||
| SERVER_MSG: { | ||
| message: z.object({ bar: z.number() }) | ||
| } | ||
| }; | ||
|
|
||
| const ns = new ZodNamespace({ | ||
| io, | ||
| name: "test", | ||
| clientMessages, | ||
| serverMessages, | ||
| }); | ||
|
|
||
| const emitSpy = vi.spyOn(ns.namespace, "emit"); | ||
|
|
||
| // This should not throw and should emit the correct payload | ||
| // Currently this might throw or require passing { message: { bar: 1 } } | ||
| await ns.sender.send("SERVER_MSG", { bar: 1 } as any); | ||
|
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. 🚩 zodNamespace test uses The test at Was this helpful? React with 👍 or 👎 to provide feedback. |
||
|
|
||
| expect(emitSpy).toHaveBeenCalledWith("SERVER_MSG", { | ||
| payload: { bar: 1 }, | ||
| version: "v1" | ||
| }); | ||
| }); | ||
|
|
||
| it("should support schemas with callbacks if updated", async () => { | ||
| // This test represents the desired state | ||
| const io = new Server(createServer()); | ||
|
|
||
| const clientMessages = { | ||
| CLIENT_MSG: { | ||
| message: z.object({ foo: z.string() }), | ||
| callback: z.object({ ok: z.boolean() }) | ||
| } | ||
| }; | ||
|
|
||
| const serverMessages = { | ||
| SERVER_MSG: { | ||
| message: z.object({ bar: z.number() }), | ||
| callback: z.object({ success: z.boolean() }) | ||
| } | ||
| } as any; // Cast for now until we update the types | ||
|
|
||
| const ns = new ZodNamespace({ | ||
| io, | ||
| name: "test-cb", | ||
| clientMessages, | ||
| serverMessages, | ||
| }); | ||
|
|
||
| expect(ns).toBeDefined(); | ||
| }); | ||
| }); | ||
| 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}` | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+61
to
+66
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. 🟡 Missing mutual exclusion validation for The constructor at
Suggested change
Was this helpful? React with 👍 or 👎 to provide feedback. |
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| 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
+162
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. 🚩 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.
🚩 test-dotenv.ts is an ad-hoc script, not a vitest test
This file is committed as a standalone executable script at the package root rather than as a proper vitest test file. The repo's CLAUDE.md states 'We use vitest exclusively' and AGENTS.md says 'Test files live beside the files under test and use descriptive describe and it blocks.' This file uses
console.logassertions andprocess.exitinstead of vitest'sdescribe/it/expect. Consider converting this to a proper vitest test in a location next topackages/cli-v3/src/utilities/dotEnv.ts, or removing it if it was only intended as a temporary debugging aid.Was this helpful? React with 👍 or 👎 to provide feedback.