_.invoke
Run a method on every item in a collection, in the graph
- list_or_dict
- arguments
- *
_.invoke calls a method on every element of a collection and collects the results. Give it a list of strings and the method lower, and you get back a list of lowercased strings. Give it a list of numbers and __abs__, and you get absolute values. It's the "map a method call over a list" node - the kind of thing that's trivial in Python ([x.lower() for x in items]) and genuinely awkward to express in vanilla ComfyUI, which is exactly why it exists here.
How it works
The port decides what to call based on what methodName refers to:
def invoke(self, method, *args):
def inv(value, *ar):
if (_(method).isFunction() or _(method).isLambda() or _(method).isMethod()):
return method(value, *args)
else:
return getattr(value, method)(*args)
return self._wrap(self._clean.map(inv))
Two paths: if the methodName value is itself a function/lambda/method, it's called with each element as its argument. Otherwise it's treated as a string name, and each element has that attribute fetched and called on it. Extra arguments you pass get forwarded to every invocation. Either way the per-item results come back as one list.
The inputs that matter
- list_or_dict - the primary input (
*), the collection whose elements get the method called on them. Also accepts a_.CHAINto continue chaining. - methodName - a
STRING(default empty). The method name (likelower,strip,upper) or, if you're feeling exotic, a callable value. - arguments - an
*input for extra args forwarded to each call. Per the tooltip, multiple values go in as a JSON array, e.g.[2]if the method takes an argument.
Output is a single * - the list of results, untyped because the generator can't know what your method returns.
Where you'd actually use it
Text normalization is the killer use: a list of tags or filenames from a loader, run _.invoke with strip (or lower) and every string comes back cleaned - no per-item iteration needed. It's also the natural companion to _.pluck (grab a property off every item) when what you actually want is to call something on every item.
The catch: the method has to exist on your elements. Call lower on a list of integers and the workflow will log a Python AttributeError rather than gracefully skipping. Check your element types first.
Installing
Part of comfy-ovum (MIT). ComfyUI Manager → search comfy-ovum → install → restart, or:
cd ComfyUI/custom_nodes
git clone https://github.com/sfinktah/comfy-ovum
Underscore nodes run on the bundled underscore3 port - no extra install. Pack-wide requirements.txt includes pymediainfo (system libmediainfo on Linux), tomli-w, requests, braceexpand, pillow, numpy, markdown-it-py, aiohttp.
Gotchas
The pack's README is upfront that the underscore family is WIP and "an absolute disaster to use in production," and _.invoke is where you should take that literally - it's a thin wrapper over getattr + call, so it's only as safe as the methods you ask for. For batch text cleanup on known types it's genuinely handy. For arbitrary data, expect to babysit it.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| list_or_dictopt | * | Primary input object (expected collection). You can still pass any JSON-serializable value. Also accepts _.CHAIN to continue chaining. | |
| methodNameopt | STRING | methodName (string) | |
| argumentsopt | * | arguments: JSON allowed for arrays/objects where applicable. For multiple values, provide a JSON array (e.g., [1,2,3]). |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| * | * | — |