Nodes/python-interpreter-node/Python Interpreter
ComfyUI Node

Python Interpreter

Run real Python in the middle of your ComfyUI graph

By christian-byrne·Created 2 years ago·Updated about a year ago· 76
Python Interpreter
  • image1
  • image2
  • mask1
  • mask2
  • list1
  • dict1
  • any1
  • any2
  • any3
  • any4
  • image1
  • image2
  • mask1
  • mask2
  • number1
  • number2
  • text1
  • text2
  • list1
  • dict1
  • any1
  • any2
  • any3
  • any4
raw_code
number10.00
number20
text1hello
text2world
verbosetrue

You will eventually hit the wall. You need to loop over a batch of images, pull the newest file from a folder, flip a mask, or blend tensors in a way no existing node covers. The options are grim: hunt for yet another custom node, write your own, or give up. Python Interpreter is the third door - a code editor sitting right in the graph that runs when the workflow queues. It's the escape hatch, and for one-off math nobody ships a node for, it's the one I reach for.

ComfyUI's node class is Exec Python Code Script, shown in the menu as Python Interpreter. You get one big code box, a set of typed inputs, and the same names come back out the other side. Your print()s and tracebacks appear right in the node, so it doubles as a debugging bench for tensor ops. The closest relative is WASasquatch's ASTERR; what sells this one is fourteen outputs instead of one. Return an image and a mask and a text string from one code block - this node just has the sockets.

How it works

Your code runs via exec() inside ComfyUI's own Python environment - same torch, same numpy, same installed packages as everything else. Nothing is sandboxed, no API, no key.

The clever (and confusing) part: every input isn't handed to your code as a raw value. Each one is wrapped in an object that pretends to be that value - it overloads the operators and forwards everything else to the underlying data. That's why number1 * 2 and image1.shape and text1.upper() all just work. It's also why plain reassignment doesn't:

# number1 = float(number1)   # does NOTHING to the output
number1.to(float(number1))   # this is what actually writes back

Because your names live in a dict of wrappers, Python's = rebinding points the name elsewhere without touching the wrapper - so the output never changes. That's what .to() is for: it replaces the data inside the wrapper. Two rules of thumb: reassign with .to(), and when you hand a variable to an external function, pass .data:

from torchvision.transforms import ToPILImage
pil_img = ToPILImage()(image1.data)   # not image1
image2.to(pil_img)                    # write the result back

In-place operators are the exception - number1 += 1, text1 += " ok" mutate the wrapper normally. One trap in the README itself: it shows number1++, which is not valid Python - there's no ++; use number1 += 1.

The inputs and outputs that matter

You really only touch a few:

  • raw_code - the code box. Required, and the entire point.
  • image1/image2 (IMAGE), mask1/mask2 (MASK) - images arrive as B,H,W,C float tensors scaled 0–1.
  • number1 (FLOAT), number2 (INT), text1/text2 (STRING) - the easy stuff. Wire a Primitive into them and use them in code.
  • verbose - whether to print full tracebacks in the output. Keep it on until things work.
  • list1, dict1, any1any4 - wildcard slots for whatever doesn't fit the types above.

Outputs are the same fourteen names, all typed *, carrying whatever you left in them. image2 into a Preview Image, text1 into a text consumer, number1 into a seed - the usual. Because the node is an output node, it always runs even when nothing downstream changed, which is what you want.

Installing it

ComfyUI Manager is the easy route, with one gotcha: the pack only shows up on the dev channel, so open Manager → Settings and switch channel to dev first, then search Python Interpreter. Or clone it manually:

cd ComfyUI/custom_nodes
git clone https://github.com/christian-byrne/python-interpreter-node

Restart ComfyUI. Requirements are light - Python 3.10+ and Pillow (its only requirements.txt entry), no model downloads. The README's demo workflows import sklearn and webcolors for color extraction, but those aren't in the requirements - copy one and hit ImportError, pip install sklearn webcolors into ComfyUI's Python env.

Where people get burned

  • Reassignment that silently does nothing. You image1 = 0.5 * image1 and wonder why the output is unchanged. Use .to().
  • Type-switching mid-code. Rebinding an input to a different type can cost you wrapper methods. If you need a novel type out, work in your own variables and .to() at the very end.
  • Missing libraries. The node runs in ComfyUI's environment, not whatever Python you have in a terminal - install into the right one.
  • The security one, which is real. This executes arbitrary code with your user's full permissions. The author's README says it plainly: do not put this on a server reachable by the public. Same reason installing any custom node is a trust decision - code runs on import, no sandbox.

Keep it as a local tool and it's the most useful "I just need this one weird transform" node in the drawer.

CategoryDevTools

Inputs (16)

NameTypeDefaultDescription
raw_codeSTRING
image1optIMAGE
image2optIMAGE
mask1optMASK
mask2optMASK
number1optFLOAT0.00
number2optINT0
text1optSTRINGhello
text2optSTRINGworld
list1opt*
dict1opt*
any1opt*
any2opt*
any3opt*
any4opt*
verboseoptBOOLEANtrueWhether to print full tracebacks in the output

Outputs (14)

NameTypeDescription
image1*
image2*
mask1*
mask2*
number1*
number2*
text1*
text2*
list1*
dict1*
any1*
any2*
any3*
any4*