Skip to content

Commit 5c27e98

Browse files
committed
clean up duplicate code from merge conflict
1 parent bd08a87 commit 5c27e98

2 files changed

Lines changed: 0 additions & 358 deletions

File tree

src/comfy_sdk/workflows.py

Lines changed: 0 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -174,104 +174,6 @@ def add_node(
174174

175175
return node_id
176176

177-
def remove_node(self, node_id: str) -> None:
178-
"""Remove a node and redirect links through it back to their sources.
179-
180-
Deletes the node identified by ``node_id`` from the graph. Any input
181-
connections (links) in other nodes that reference this node's outputs
182-
are redirected to the source that fed into the removed node, effectively
183-
unwinding any insertion point.
184-
185-
If the removed node has exactly one input that is a link, all downstream
186-
consumers of its outputs are redirected to that source. Otherwise (zero
187-
or multiple link inputs), downstream links are simply deleted.
188-
"""
189-
removed = self.json.pop(node_id, None)
190-
if removed is None:
191-
return
192-
193-
# Collect link inputs from the removed node
194-
link_inputs: list[tuple[str, int]] = []
195-
removed_inputs = removed.get("inputs") or {}
196-
for value in removed_inputs.values():
197-
if _is_link(value):
198-
link_inputs.append((value[0], int(value[1])))
199-
200-
if len(link_inputs) == 1:
201-
# Single link input: redirect all downstream consumers to that source
202-
src_node, src_output = link_inputs[0]
203-
for node in self.json.values():
204-
inputs = node.get("inputs")
205-
if not inputs:
206-
continue
207-
for key, value in list(inputs.items()):
208-
if _is_link(value) and value[0] == node_id:
209-
if src_node in self.json:
210-
inputs[key] = [src_node, src_output]
211-
else:
212-
del inputs[key]
213-
else:
214-
# Zero or multiple link inputs: just delete downstream links
215-
for node in self.json.values():
216-
inputs = node.get("inputs")
217-
if not inputs:
218-
continue
219-
to_delete = []
220-
for key, value in inputs.items():
221-
if _is_link(value) and value[0] == node_id:
222-
to_delete.append(key)
223-
for key in to_delete:
224-
del inputs[key]
225-
226-
def remove_node(self, node_id: str) -> None:
227-
"""Remove a node and redirect links through it back to their sources.
228-
229-
Deletes the node identified by ``node_id`` from the graph. Any input
230-
connections (links) in other nodes that reference this node's outputs
231-
are redirected to the source that fed into the removed node, effectively
232-
unwinding any insertion point.
233-
234-
If the removed node has exactly one input that is a link, all downstream
235-
consumers of its outputs are redirected to that source. Otherwise (zero
236-
or multiple link inputs), downstream links are simply deleted.
237-
"""
238-
removed = self.json.pop(node_id, None)
239-
if removed is None:
240-
return
241-
242-
# Collect link inputs from the removed node
243-
link_inputs: list[tuple[str, int]] = []
244-
removed_inputs = removed.get("inputs") or {}
245-
for value in removed_inputs.values():
246-
if _is_link(value):
247-
link_inputs.append((value[0], int(value[1])))
248-
249-
if len(link_inputs) == 1:
250-
# Single link input: redirect all downstream consumers to that source
251-
src_node, src_output = link_inputs[0]
252-
for node in self.json.values():
253-
inputs = node.get("inputs")
254-
if not inputs:
255-
continue
256-
for key, value in list(inputs.items()):
257-
if _is_link(value) and value[0] == node_id:
258-
if src_node in self.json:
259-
inputs[key] = [src_node, src_output]
260-
else:
261-
del inputs[key]
262-
else:
263-
# Zero or multiple link inputs: just delete downstream links
264-
for node in self.json.values():
265-
inputs = node.get("inputs")
266-
if not inputs:
267-
continue
268-
to_delete = []
269-
for key, value in inputs.items():
270-
if _is_link(value) and value[0] == node_id:
271-
to_delete.append(key)
272-
for key in to_delete:
273-
del inputs[key]
274-
275177
def __repr__(self) -> str:
276178
return f"Workflow(nodes={len(self.json)})"
277179

tests/test_workflows.py

Lines changed: 0 additions & 260 deletions
Original file line numberDiff line numberDiff line change
@@ -199,136 +199,6 @@ def test_add_node_auto_id_on_empty_graph():
199199
assert new_id == "1"
200200

201201

202-
def test_add_node_redirects_downstream_single_consumer():
203-
graph = {
204-
"1": {
205-
"class_type": "UNETLoader",
206-
"inputs": {"unet_name": "model.safetensors"},
207-
},
208-
"2": {
209-
"class_type": "LoraLoaderModelOnly",
210-
"inputs": {
211-
"lora_name": "lora.safetensors",
212-
"strength_model": 1,
213-
"model": ["1", 0],
214-
},
215-
},
216-
"4": {
217-
"class_type": "KSampler",
218-
"inputs": {
219-
"seed": 0,
220-
"model": ["2", 0],
221-
},
222-
},
223-
}
224-
wf = Workflow(graph)
225-
new_id = wf.add_node(
226-
"ModelAttentionBackend",
227-
before="4",
228-
inputs={
229-
"attention": "pytorch attention",
230-
"model": ["2", 0],
231-
},
232-
)
233-
assert new_id == "5"
234-
assert wf.json[new_id]["class_type"] == "ModelAttentionBackend"
235-
assert wf.json[new_id]["inputs"]["model"] == ["2", 0]
236-
assert wf.json["4"]["inputs"]["model"] == [new_id, 0]
237-
238-
239-
def test_add_node_redirects_multiple_downstream():
240-
graph = {
241-
"1": {
242-
"class_type": "LoadImage",
243-
"inputs": {"image": "example.png"},
244-
},
245-
"2": {
246-
"class_type": "PreviewImage",
247-
"inputs": {"images": ["1", 0]},
248-
},
249-
"3": {
250-
"class_type": "PreviewImage",
251-
"inputs": {"images": ["1", 0]},
252-
},
253-
"4": {
254-
"class_type": "PreviewImage",
255-
"inputs": {"images": ["1", 0]},
256-
},
257-
}
258-
wf = Workflow(graph)
259-
new_id = wf.add_node(
260-
"ImageScaleToTotalPixels",
261-
after="1",
262-
inputs={
263-
"upscale_method": "nearest-exact",
264-
"megapixels": 1,
265-
"image": ["1", 0],
266-
},
267-
)
268-
assert new_id == "5"
269-
assert wf.json[new_id]["inputs"]["image"] == ["1", 0]
270-
assert wf.json["2"]["inputs"]["images"] == [new_id, 0]
271-
assert wf.json["3"]["inputs"]["images"] == [new_id, 0]
272-
assert wf.json["4"]["inputs"]["images"] == [new_id, 0]
273-
274-
275-
def test_add_node_no_redirect_when_upstream_not_in_graph():
276-
graph = {
277-
"1": {
278-
"class_type": "CLIPTextEncode",
279-
"inputs": {"text": "hello"},
280-
},
281-
}
282-
wf = Workflow(graph)
283-
new_id = wf.add_node(
284-
"KSampler",
285-
inputs={"model": ["999", 0]},
286-
)
287-
assert new_id == "2"
288-
assert wf.json[new_id]["inputs"]["model"] == ["999", 0]
289-
290-
291-
def test_add_node_no_redirect_when_no_downstream_consumers():
292-
graph = {
293-
"1": {
294-
"class_type": "CheckpointLoader",
295-
"inputs": {"ckpt_name": "model.safetensors"},
296-
},
297-
}
298-
wf = Workflow(graph)
299-
new_id = wf.add_node(
300-
"LoraLoader",
301-
inputs={"model": ["1", 0], "clip": ["1", 1]},
302-
)
303-
assert new_id == "2"
304-
assert wf.json[new_id]["inputs"]["model"] == ["1", 0]
305-
assert wf.json[new_id]["inputs"]["clip"] == ["1", 1]
306-
307-
308-
def test_add_node_both_before_and_after_raises():
309-
wf = Workflow({"1": {"class_type": "X", "inputs": {}}})
310-
try:
311-
wf.add_node("Y", before="1", after="1", inputs={})
312-
except ValueError as e:
313-
assert "not both" in str(e)
314-
else:
315-
assert False, "Expected ValueError"
316-
317-
318-
def test_add_node_no_inputs_no_redirect():
319-
wf = Workflow({"1": {"class_type": "X", "inputs": {}}})
320-
new_id = wf.add_node("Y")
321-
assert new_id == "2"
322-
assert wf.json[new_id]["class_type"] == "Y"
323-
assert "inputs" not in wf.json[new_id]
324-
325-
326-
def test_add_node_auto_id_on_empty_graph():
327-
wf = Workflow({})
328-
new_id = wf.add_node("X")
329-
assert new_id == "1"
330-
331-
332202
def test_remove_node_model_attention_backend():
333203
graph = {
334204
"1": {
@@ -469,133 +339,3 @@ def test_remove_node_redirects_preview_any():
469339

470340
assert "2" not in wf.json
471341
assert wf.json["3"]["inputs"]["text"] == ["1", 0]
472-
473-
474-
def test_add_node_redirects_downstream_single_consumer():
475-
graph = {
476-
"1": {
477-
"class_type": "UNETLoader",
478-
"inputs": {"unet_name": "model.safetensors"},
479-
},
480-
"2": {
481-
"class_type": "LoraLoaderModelOnly",
482-
"inputs": {
483-
"lora_name": "lora.safetensors",
484-
"strength_model": 1,
485-
"model": ["1", 0],
486-
},
487-
},
488-
"4": {
489-
"class_type": "KSampler",
490-
"inputs": {
491-
"seed": 0,
492-
"model": ["2", 0],
493-
},
494-
},
495-
}
496-
wf = Workflow(graph)
497-
new_id = wf.add_node(
498-
"ModelAttentionBackend",
499-
before="4",
500-
inputs={
501-
"attention": "pytorch attention",
502-
"model": ["2", 0],
503-
},
504-
)
505-
assert new_id == "5"
506-
assert wf.json[new_id]["class_type"] == "ModelAttentionBackend"
507-
assert wf.json[new_id]["inputs"]["model"] == ["2", 0]
508-
assert wf.json["4"]["inputs"]["model"] == [new_id, 0]
509-
510-
511-
def test_add_node_redirects_multiple_downstream():
512-
graph = {
513-
"1": {
514-
"class_type": "LoadImage",
515-
"inputs": {"image": "example.png"},
516-
},
517-
"2": {
518-
"class_type": "PreviewImage",
519-
"inputs": {"images": ["1", 0]},
520-
},
521-
"3": {
522-
"class_type": "PreviewImage",
523-
"inputs": {"images": ["1", 0]},
524-
},
525-
"4": {
526-
"class_type": "PreviewImage",
527-
"inputs": {"images": ["1", 0]},
528-
},
529-
}
530-
wf = Workflow(graph)
531-
new_id = wf.add_node(
532-
"ImageScaleToTotalPixels",
533-
after="1",
534-
inputs={
535-
"upscale_method": "nearest-exact",
536-
"megapixels": 1,
537-
"image": ["1", 0],
538-
},
539-
)
540-
assert new_id == "5"
541-
assert wf.json[new_id]["inputs"]["image"] == ["1", 0]
542-
assert wf.json["2"]["inputs"]["images"] == [new_id, 0]
543-
assert wf.json["3"]["inputs"]["images"] == [new_id, 0]
544-
assert wf.json["4"]["inputs"]["images"] == [new_id, 0]
545-
546-
547-
def test_add_node_no_redirect_when_upstream_not_in_graph():
548-
graph = {
549-
"1": {
550-
"class_type": "CLIPTextEncode",
551-
"inputs": {"text": "hello"},
552-
},
553-
}
554-
wf = Workflow(graph)
555-
new_id = wf.add_node(
556-
"KSampler",
557-
inputs={"model": ["999", 0]},
558-
)
559-
assert new_id == "2"
560-
assert wf.json[new_id]["inputs"]["model"] == ["999", 0]
561-
562-
563-
def test_add_node_no_redirect_when_no_downstream_consumers():
564-
graph = {
565-
"1": {
566-
"class_type": "CheckpointLoader",
567-
"inputs": {"ckpt_name": "model.safetensors"},
568-
},
569-
}
570-
wf = Workflow(graph)
571-
new_id = wf.add_node(
572-
"LoraLoader",
573-
inputs={"model": ["1", 0], "clip": ["1", 1]},
574-
)
575-
assert new_id == "2"
576-
assert wf.json[new_id]["inputs"]["model"] == ["1", 0]
577-
assert wf.json[new_id]["inputs"]["clip"] == ["1", 1]
578-
579-
580-
def test_add_node_both_before_and_after_raises():
581-
wf = Workflow({"1": {"class_type": "X", "inputs": {}}})
582-
try:
583-
wf.add_node("Y", before="1", after="1", inputs={})
584-
except ValueError as e:
585-
assert "not both" in str(e)
586-
else:
587-
assert False, "Expected ValueError"
588-
589-
590-
def test_add_node_no_inputs_no_redirect():
591-
wf = Workflow({"1": {"class_type": "X", "inputs": {}}})
592-
new_id = wf.add_node("Y")
593-
assert new_id == "2"
594-
assert wf.json[new_id]["class_type"] == "Y"
595-
assert "inputs" not in wf.json[new_id]
596-
597-
598-
def test_add_node_auto_id_on_empty_graph():
599-
wf = Workflow({})
600-
new_id = wf.add_node("X")
601-
assert new_id == "1"

0 commit comments

Comments
 (0)