anyPython
When the node you need doesn't exist, paste the code instead
- image
- STRING
- IMAGE
anyPython is a single text box that runs whatever Python you paste into it, right inside your ComfyUI workflow. No API, no key, no model download - you type code (or get an LLM to type it), the node executes it when the queue runs, and hands you back a string and an image. That's the whole pitch, and for a very specific class of annoyance it's genuinely the fastest thing in your toolbox.
The gap it fills is real. ComfyUI has thousands of custom nodes, but you'll still hit a task with no node for it: "grab the temperature from a weather API and put it in the caption," "compute the dominant color of this image and a readable font color to overlay," "give me today's date," "turn this URL's HTML into markdown." Each of those used to mean writing a custom node and restarting. With anyPython you just paste code, and the author's own examples are exactly that list. On r/comfyui it gets recommended the same way: someone asks "is there a node that creates a directory if it doesn't exist?" and the answer is "yeah, just do it in anyPython." That's the sweet spot - short, one-off logic you don't want to build a node for.
How it actually works
Under the hood it does not use exec or eval - the author explicitly avoided those to stay on the right side of ComfyUI's security requirements. Instead your code is written to a temporary .py file and run with runpy.run_path(), which executes it as a module. Imports are pre-parsed and pulled into the module's globals with importlib, and stdout is captured, so print() output becomes the string result. None of that is a sandbox, by the way - more on that below.
The contract your code follows is short:
- You get three globals for free:
variable(a string, optional),image(always a tensor), andconfirm_risks(a boolean). - Set the global
outputto a string, or justprint()something and it gets captured. - Set the global
imageback to a tensor for image output; if you don't, the input image passes through unchanged. - No top-level
return. Assign globals instead.
The image is the one thing that trips people up. It arrives as a torch tensor; if you want PIL processing, convert it (squeeze the batch dim, ToPILImage()), and convert back with ToTensor() before assigning to image. The README ships a tensor_to_pil helper worth copying.
The inputs that matter
There are only four, and you'll mostly touch two:
- code - the Python itself, a multiline string. Default is
print(variable), which just echoes whatever you feed intovariable. - confirm_risks - a boolean, off by default. The node scans your code for a fixed list of risky imports (
os,sys,subprocess,shutil,socket,requests,ctypes,urllib,sqlite3,pickle, and a few more) plus risky calls likeos.systemorsubprocess.run. If it finds any and you haven't ticked this, it refuses to run and returns a warning listing the flagged module, level, and why - read the STRING output to see it. - variable - an optional freeform string you can inject, handy for threading prompt text or a filename in from elsewhere in the graph.
- image - optional image input; wire it in when your code manipulates pixels.
It returns two outputs: STRING (your output global, or captured print text) and IMAGE (your image global, or the input passed through). Both can feed into any node that takes those types - put the string into a caption/save node, the image back into the graph.
Install
Via ComfyUI Manager, search anyPython, or the manual way:
cd ComfyUI/custom_nodes
git clone https://github.com/prabinpebam/anyPython
Then restart ComfyUI. There's no requirements.txt - it runs on runpy, importlib, tempfile and other stdlib modules, plus numpy/Pillow/OpenCV that ComfyUI already ships, so nothing extra to install and no model files. A node.zip sits in the repo but ignore it; the clone is fine.
Security, seriously
This is the part to actually read. The risk toggle is a heuristic linter, not an isolation boundary - your code runs with your full user privileges, exactly like any custom node. The import scan only matches import/from lines at the start of a line and a fixed operation list; anything obfuscated, or a call the list doesn't cover, sails through unflagged. The README says it plainly: since this runs any code, it can run malicious code, and a workflow someone shares to you can arrive with a pre-populated anyPython node full of it. This ecosystem has already been burned exactly this way - a captioning node shipped credential-stealing malware and ended in a federal prosecution. So follow the author's own rule: never run an anyPython node from a workflow you didn't write or fully understand. If you're unsure what the code does, paste it into an LLM and ask before you queue.
Troubleshooting
- Nothing runs and you see a "SECURITY RISKS DETECTED" block - that's the guard, not a crash. Tick
confirm_risksand rerun, or drop the risky import. - You get
Error: ...as the string output - your code raised; the exception text is right there in the STRING output. The node doesn't kill the whole queue, it just reports. - The image comes back black or the wrong shape - you forgot to convert back to a tensor, or left the batch dimension in. Squeeze on the way in,
ToTensor()on the way out. - "No module named X" - it isn't in ComfyUI's Python environment; install it into that environment, not your system one.
One honest caveat: this is a tiny, low-traffic pack from a solo author - a convenience, not infrastructure. If you keep pasting the same script, that's the sign you've outgrown it and should write the actual node.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| code | STRING | print(variable) | — |
| confirm_risks | BOOLEAN | false | — |
| variableopt | STRING | 5 | — |
| imageopt | IMAGE | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| STRING | STRING | — |
| IMAGE | IMAGE | — |