feat: use column letters (A, B, C...) in Google Sheet nodes

This commit is contained in:
Ivor Strelar
2026-06-30 14:15:07 +02:00
parent 61cf275578
commit 1689aa0723
3 changed files with 40 additions and 32 deletions
+19 -14
View File
@@ -4,10 +4,21 @@ import re
import requests
def col_letter_to_index(col_str: str) -> int:
"""Convert a column letter (A, B, C, ... Z, AA, AB, ...) to a 0-based index."""
col_str = col_str.strip().upper()
if not col_str or not col_str.isalpha():
raise ValueError(f"Invalid column label '{col_str}'. Use letters like A, B, C, AA, AB, etc.")
result = 0
for char in col_str:
result = result * 26 + (ord(char) - ord("A") + 1)
return result - 1
class SFGoogleSheetCell:
"""
Reads a single cell from a publicly shared Google Sheet.
Row and column are 1-indexed to match Google Sheets display numbers.
Row is 1-indexed. Column uses letter notation (A, B, C, ...) matching Google Sheets.
The sheet must be shared as "Anyone with the link can view."
"""
@@ -47,12 +58,10 @@ class SFGoogleSheetCell:
},
),
"col": (
"INT",
"STRING",
{
"default": 1,
"min": 1,
"step": 1,
"tooltip": "Column number starting from 1 (A=1, B=2, C=3, etc.).",
"default": "A",
"tooltip": "Column letter as shown in Google Sheets (A, B, C, ... Z, AA, AB, ...).",
},
),
}
@@ -63,11 +72,11 @@ class SFGoogleSheetCell:
FUNCTION = "get_cell"
CATEGORY = "Stillfront/Utils"
def get_cell(self, url: str, sheet_gid: str, row: int, col: int) -> tuple:
def get_cell(self, url: str, sheet_gid: str, row: int, col: str) -> tuple:
spreadsheet_id = self._extract_id(url)
gid = sheet_gid.strip() or "0"
col_idx = col_letter_to_index(col)
# gviz/tq endpoint correctly handles any sheet GID, unlike export?format=csv
csv_url = (
f"https://docs.google.com/spreadsheets/d/{spreadsheet_id}"
f"/gviz/tq?tqx=out:csv&gid={gid}"
@@ -87,19 +96,15 @@ class SFGoogleSheetCell:
content = response.content.decode("utf-8")
table = list(csv.reader(io.StringIO(content)))
# Convert 1-indexed user input to 0-indexed Python list access
row_idx = row - 1
col_idx = col - 1
if row_idx >= len(table):
raise ValueError(
f"Row {row} is out of range — the sheet has {len(table)} rows."
)
raise ValueError(f"Row {row} is out of range — the sheet has {len(table)} rows.")
row_data = table[row_idx]
if col_idx >= len(row_data):
raise ValueError(
f"Column {col} is out of range — row {row} has {len(row_data)} columns."
f"Column '{col.upper()}' is out of range — row {row} has {len(row_data)} columns."
)
return (str(row_data[col_idx]),)
+20 -17
View File
@@ -3,13 +3,15 @@ import io
import re
import requests
from .sf_google_sheet_cell import col_letter_to_index
class SFGoogleSheetRange:
"""
Reads a range of cells from a publicly shared Google Sheet and joins them
into a single string using a configurable delimiter.
Cells are read left to right, top to bottom.
Row and column numbers are 1-indexed to match Google Sheets display numbers.
Row numbers are 1-indexed. Columns use letter notation (A, B, C, ...) matching Google Sheets.
The sheet must be shared as "Anyone with the link can view."
"""
@@ -48,12 +50,10 @@ class SFGoogleSheetRange:
},
),
"start_col": (
"INT",
"STRING",
{
"default": 1,
"min": 1,
"step": 1,
"tooltip": "First column of the range (1 = column A).",
"default": "A",
"tooltip": "First column of the range (e.g. A, B, C, AA, ...).",
},
),
"end_row": (
@@ -66,12 +66,10 @@ class SFGoogleSheetRange:
},
),
"end_col": (
"INT",
"STRING",
{
"default": 1,
"min": 1,
"step": 1,
"tooltip": "Last column of the range (inclusive).",
"default": "A",
"tooltip": "Last column of the range (inclusive, e.g. A, B, C, AA, ...).",
},
),
"delimiter": (
@@ -98,15 +96,20 @@ class SFGoogleSheetRange:
url: str,
sheet_gid: str,
start_row: int,
start_col: int,
start_col: str,
end_row: int,
end_col: int,
end_col: str,
delimiter: str,
) -> tuple:
start_col_idx = col_letter_to_index(start_col)
end_col_idx = col_letter_to_index(end_col)
if start_row > end_row:
raise ValueError(f"start_row ({start_row}) must be less than or equal to end_row ({end_row}).")
if start_col > end_col:
raise ValueError(f"start_col ({start_col}) must be less than or equal to end_col ({end_col}).")
raise ValueError(f"start_row ({start_row}) must be ≤ end_row ({end_row}).")
if start_col_idx > end_col_idx:
raise ValueError(
f"start_col '{start_col.upper()}' must be ≤ end_col '{end_col.upper()}'."
)
table = self._fetch_sheet(url, sheet_gid)
@@ -115,7 +118,7 @@ class SFGoogleSheetRange:
if r >= len(table):
break
row_data = table[r]
for c in range(start_col - 1, end_col):
for c in range(start_col_idx, end_col_idx + 1):
value = row_data[c] if c < len(row_data) else ""
cells.append(str(value))
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "comfyui-sf-nodes"
description = "Custom nodes for ComfyUI including LLM Chat with support for Claude, Gemini, and OpenAI models, WaveSpeed AI image/video generation, VertexAI integration, and workflow utilities"
version = "1.0.4"
version = "1.0.5"
license = { file = "LICENSE" }
dependencies = [
"requests>=2.31.0",