None of these answers were adequate for my situation. See my solution (which is a little specific to the gspread library I was using, but you can adapt it) at
https://github.com/burnash/gspread/issues/524#issuecomment-1229082678. Copied below:
I have various kinds of data:
- zipcodes, which look like ints but can be prefixed with 0s, so therefore need to be stored as strings eg
"00123"
- booleans, eg
True
- floats, eg
3.0
I was finding that if I used value_input_option="RAW"
, then I would get the problems described here: all of the zipcodes, booleans, and floats (eg anything that google sheets is able to "cast" from a string to a better datatype) would all get that annoying leading apostrophe (which I'm guessing is a sheets notation to say "don't cast this").
OK, so then I tried value_input_option="USER_ENTERED"
. Now, the leading apostrophe is gone, but the casting is happening. So 00123
-> 123
, True
-> TRUE
, and 3.0
-> 3
. That also wasn't OK for my needs. This even happens if I pre-cast my values to strings, eg if I upload the string "3.0"
instead of the float 3.0
.
So, what I ended up doing was first pre-casting to strings, so I could get exactly what I wanted, and then using:
def set_sheet_values(worksheet: gspread.Worksheet, data: list[list[str]]):
# The .format() only affects existing cells, so if your data is larger than
# the current sheet, those newly added cells won't be affected.
# Therefore, resize before formatting so all columns will be affected.
worksheet.resize(rows=len(data), cols=len(data[0]))
# This is equivalent to in the web UI selecting all cells and
# then in the menu going `Format` > `Number` > `Plain Text`
# For more info see
# https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/cells?hl=en#cellformat
worksheet.format(
":",
{
"numberFormat": {
"type": "TEXT",
},
},
)
# Act as though the user just typed this in the web UI
# Because of the formatting, no "casting" happens
worksheet.update(data, value_input_option="USER_ENTERED")