diff --git a/.changeset/cute-eagles-exist.md b/.changeset/cute-eagles-exist.md new file mode 100644 index 000000000000..57388e61526d --- /dev/null +++ b/.changeset/cute-eagles-exist.md @@ -0,0 +1,6 @@ +--- +"workers-playground": minor +"wrangler": minor +--- + +Python packages are now read from cf-requirements.txt instead of requirements.txt by default diff --git a/packages/workers-playground/generate-default-hashes.ts b/packages/workers-playground/generate-default-hashes.ts index cb1c0f36adbf..feda6c5e6ec5 100644 --- a/packages/workers-playground/generate-default-hashes.ts +++ b/packages/workers-playground/generate-default-hashes.ts @@ -37,11 +37,11 @@ const pythonWorker = async () => { ); worker.set( - "requirements.txt", - new Blob([await readFile("./welcome/requirements.txt", "utf8")], { + "cf-requirements.txt", + new Blob([await readFile("./welcome/cf-requirements.txt", "utf8")], { type: "text/plain", }), - "requirements.txt" + "cf-requirements.txt" ); return worker; }; diff --git a/packages/workers-playground/src/QuickEditor/defaultHashes.ts b/packages/workers-playground/src/QuickEditor/defaultHashes.ts index c7b54aa4bcec..f6aeab50b93a 100644 --- a/packages/workers-playground/src/QuickEditor/defaultHashes.ts +++ b/packages/workers-playground/src/QuickEditor/defaultHashes.ts @@ -3,7 +3,7 @@ export default { contentType: "multipart/form-data; boundary=----formdata-88e2b909-318c-42df-af0d-9077f33c7988", worker: - '------formdata-88e2b909-318c-42df-af0d-9077f33c7988\r\nContent-Disposition: form-data; name="metadata"\r\n\r\n{"main_module":"index.py","compatibility_date":"$REPLACE_COMPAT_DATE","compatibility_flags":["python_workers"]}\r\n------formdata-88e2b909-318c-42df-af0d-9077f33c7988\r\nContent-Disposition: form-data; name="index.py"; filename="index.py"\r\nContent-Type: text/x-python\r\n\r\nfrom js import Response\nimport numpy as np\n\ndef on_fetch(request):\n print("Hi there!")\n arr = np.array([1, 2, 3])\n return Response.new(str(arr))\n\r\n------formdata-88e2b909-318c-42df-af0d-9077f33c7988\r\nContent-Disposition: form-data; name="requirements.txt"; filename="requirements.txt"\r\nContent-Type: text/plain\r\n\r\nnumpy\r\n------formdata-88e2b909-318c-42df-af0d-9077f33c7988--', + '------formdata-88e2b909-318c-42df-af0d-9077f33c7988\r\nContent-Disposition: form-data; name="metadata"\r\n\r\n{"main_module":"index.py","compatibility_date":"$REPLACE_COMPAT_DATE","compatibility_flags":["python_workers"]}\r\n------formdata-88e2b909-318c-42df-af0d-9077f33c7988\r\nContent-Disposition: form-data; name="index.py"; filename="index.py"\r\nContent-Type: text/x-python\r\n\r\nfrom js import Response\nimport numpy as np\n\ndef on_fetch(request):\n print("Hi there!")\n arr = np.array([1, 2, 3])\n return Response.new(str(arr))\n\r\n------formdata-88e2b909-318c-42df-af0d-9077f33c7988\r\nContent-Disposition: form-data; name="cf-requirements.txt"; filename="cf-requirements.txt"\r\nContent-Type: text/plain\r\n\r\nnumpy\r\n------formdata-88e2b909-318c-42df-af0d-9077f33c7988--', }, "/": { contentType: diff --git a/packages/workers-playground/src/QuickEditor/useDraftWorker.ts b/packages/workers-playground/src/QuickEditor/useDraftWorker.ts index f8d2d49cda51..33510e144e66 100644 --- a/packages/workers-playground/src/QuickEditor/useDraftWorker.ts +++ b/packages/workers-playground/src/QuickEditor/useDraftWorker.ts @@ -75,15 +75,15 @@ export function serialiseWorker(service: PartialWorker): FormData { const entrypointModule = typedModules.find( (m) => m.name === service.entrypoint ); - // Try to find a requirements.txt file + // Try to find a cf-requirements.txt file const isPythonEntrypoint = entrypointModule?.type === "python"; if (isPythonEntrypoint) { try { - const pythonRequirements = service.modules["requirements.txt"]; + const pythonRequirements = service.modules["cf-requirements.txt"]; if (pythonRequirements) { const textContent = decoder.decode(pythonRequirements.contents); - // This is incredibly naive. However, it supports common syntax for requirements.txt + // This is incredibly naive. However, it supports common syntax for cf-requirements.txt for (const requirement of textContent.split("\n")) { const packageName = requirement.match(/^[^\d\W]\w*/); if (typeof packageName?.[0] === "string") { @@ -98,10 +98,10 @@ export function serialiseWorker(service: PartialWorker): FormData { } } } - // We don't care if a requirements.txt isn't found + // We don't care if a cf-requirements.txt isn't found } catch (e) { console.debug( - "Python entrypoint detected, but no requirements.txt file found." + "Python entrypoint detected, but no cf-requirements.txt file found." ); } } diff --git a/packages/wrangler/src/deployment-bundle/find-additional-modules.ts b/packages/wrangler/src/deployment-bundle/find-additional-modules.ts index d785b9b91fcd..61c666a56692 100644 --- a/packages/wrangler/src/deployment-bundle/find-additional-modules.ts +++ b/packages/wrangler/src/deployment-bundle/find-additional-modules.ts @@ -1,3 +1,4 @@ +import { existsSync } from "node:fs"; import { mkdir, readdir, readFile, writeFile } from "node:fs/promises"; import path from "node:path"; import chalk from "chalk"; @@ -93,7 +94,7 @@ export async function findAdditionalModules( name: m.name, })); - // Try to find a requirements.txt file + // Try to find a cf-requirements.txt file const isPythonEntrypoint = getBundleType(entry.format, entry.file) === "python"; @@ -101,13 +102,20 @@ export async function findAdditionalModules( let pythonRequirements = ""; try { pythonRequirements = await readFile( - path.resolve(entry.projectRoot, "requirements.txt"), + path.resolve(entry.projectRoot, "cf-requirements.txt"), "utf-8" ); } catch (e) { - // We don't care if a requirements.txt isn't found + // We don't care if a cf-requirements.txt isn't found logger.debug( - "Python entrypoint detected, but no requirements.txt file found." + "Python entrypoint detected, but no cf-requirements.txt file found." + ); + } + + // If a `requirements.txt` file is found, show a warning instructing user to use `cf-requirements.txt` instead. + if (existsSync(path.resolve(entry.projectRoot, "requirements.txt"))) { + logger.warn( + "Found a `requirements.txt` file. Python requirements should now be in a `cf-requirements.txt` file." ); } @@ -117,7 +125,7 @@ export async function findAdditionalModules( } if (!isValidPythonPackageName(requirement)) { throw new UserError( - `Invalid Python package name "${requirement}" found in requirements.txt. Note that requirements.txt should contain package names only, not version specifiers.` + `Invalid Python package name "${requirement}" found in cf-requirements.txt. Note that cf-requirements.txt should contain package names only, not version specifiers.` ); } diff --git a/packages/wrangler/src/deployment-bundle/guess-worker-format.ts b/packages/wrangler/src/deployment-bundle/guess-worker-format.ts index cf7ce4fb7509..15f5f2aa4523 100644 --- a/packages/wrangler/src/deployment-bundle/guess-worker-format.ts +++ b/packages/wrangler/src/deployment-bundle/guess-worker-format.ts @@ -24,7 +24,7 @@ export default async function guessWorkerFormat( `The entrypoint ${path.relative( process.cwd(), entryFile - )} defines a Python worker, support for Python workers is currently experimental. Python workers with a requirements.txt file can only be run locally and cannot be deployed.` + )} defines a Python worker, support for Python workers is currently experimental. Python workers with a cf-requirements.txt file can only be run locally and cannot be deployed.` ); return { format: "modules", exports: [] }; } diff --git a/packages/wrangler/src/dev/use-esbuild.ts b/packages/wrangler/src/dev/use-esbuild.ts index 436307e7c081..ea23584b8a74 100644 --- a/packages/wrangler/src/dev/use-esbuild.ts +++ b/packages/wrangler/src/dev/use-esbuild.ts @@ -184,10 +184,10 @@ export function runBuild( // trigger "builds" when any change if (noBundle) { const watching = [path.resolve(entry.moduleRoot)]; - // Check whether we need to watch a Python requirements.txt file. + // Check whether we need to watch a Python cf-requirements.txt file. const watchPythonRequirements = getBundleType(entry.format, entry.file) === "python" - ? path.resolve(entry.projectRoot, "requirements.txt") + ? path.resolve(entry.projectRoot, "cf-requirements.txt") : undefined; if (watchPythonRequirements) {