From 242abdf1b4e342af8b1329feab58dd7f3fdd96fd Mon Sep 17 00:00:00 2001 From: deepshekhardas Date: Thu, 5 Mar 2026 07:42:23 +0530 Subject: [PATCH 1/2] feat: support pyproject.toml and uv in python extension (#3118) --- packages/python/src/extension.ts | 49 ++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/packages/python/src/extension.ts b/packages/python/src/extension.ts index 53b5c2c8cf3..3f557cca381 100644 --- a/packages/python/src/extension.ts +++ b/packages/python/src/extension.ts @@ -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 ."} `), }, 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: { From f445a623666ce5fbd19b0b5454b8e40d18dda044 Mon Sep 17 00:00:00 2001 From: deepshekhardas Date: Thu, 5 Mar 2026 15:13:29 +0530 Subject: [PATCH 2/2] feat: add pyproject.toml and uv support for Python tasks --- packages/cli-v3/test-dotenv.ts | 22 +++++++ packages/core/test/v3/zodNamespace.test.ts | 69 ++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 packages/cli-v3/test-dotenv.ts create mode 100644 packages/core/test/v3/zodNamespace.test.ts diff --git a/packages/cli-v3/test-dotenv.ts b/packages/cli-v3/test-dotenv.ts new file mode 100644 index 00000000000..773a2c2f477 --- /dev/null +++ b/packages/cli-v3/test-dotenv.ts @@ -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); +} + +fs.rmSync(tempDir, { recursive: true, force: true }); diff --git a/packages/core/test/v3/zodNamespace.test.ts b/packages/core/test/v3/zodNamespace.test.ts new file mode 100644 index 00000000000..7d992b4e04a --- /dev/null +++ b/packages/core/test/v3/zodNamespace.test.ts @@ -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); + + 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(); + }); +});