burnash / gspread

Google Sheets Python API
https://docs.gspread.org
MIT License
6.96k stars 935 forks source link

Feature Request: set_record + set_records #677

Open thp44 opened 5 years ago

thp44 commented 5 years ago

get_all_records() return nicely formatted dictionaries (thanks!)

set_record() (new feature) inset one dictionary to google sheet (values under right heading)

set_records() (new feature) inset list of dictionaries to google sheet (values under right heading)

muddi900 commented 6 days ago

This would be simple to implement, but it would be very slow.

We can add a mapping of the columns when the get_all_records are generated to the index.

Most of the work would be validation and testing.

alifeee commented 6 days ago

The way I could see this feature working is similar to Python's CSV DictWriter class

def append_records(
  headers: List[str],
  records: List[Dict[str, str]],
  default_blank: Any = None,
  ignore_extra_dict_items: bool = False,
  # extra kwargs?
)
  # use a provided "headers" array, probably obtained with worksheet.row_values(1)
  # new_rows = []
  # for each object in records
    # for each header in headers
      # if header not in headers, raise error! (unless kwarg)
      # if header not in object, raise error! (unless default blank)
      # new_rows[i].append(object[header])
  # use worksheet.append_rows to add new_rows to worksheet

and append_record (singular) would call append_records with a wrapped record, like [record] (like append_row and appeend_rows)

Questions I would have:

This would be simple to implement, but it would be very slow.

slow? not sure what you mean

We can add a mapping of the columns when the get_all_records are generated to the index.

also not sure what you mean

if you desire to implement it, I think this could be a nice feature @muddi900 :)

muddi900 commented 6 days ago

It would be slow in the sense that the order may not be correct each time. So we have to make sure the order is correct. Or use memoization: create an list of None the size of the record, loop through the whole record each time and fill the appropriate value according column mapping.

alifeee commented 5 days ago

not sure what you mean? dictionaries do not have an order as I understand it (or should not)

So I would see the list being created with something like

default_blank = None
ignore_extra_headers = False
data = {"fruit": "Apple", "tastiness": "very tasty"}
headers = ["fruit", "tastiness"]

new_row = []
if not set(data).issubset(set(headers)) and ignore_extra_headers == False:
  raise ValueError("Extra headers found in data")
for key in headers:
  if key not in data and default_blank is None:
    raise ValueError(f"No key <{key}> found in data")
  else:
    new_row.append(default_blank)
    continue
  new_row.append(data[key])
# new_row is ["Apple", "very tasty"]
lavigne958 commented 3 days ago

I agree with your code @alifeee , small detail here, remember that data is List[Dict[str,str]] as we have a dict per row. it looks good and the slowness here is depending on the length of data, with 1M rows of course it would take some time to run. Though I don't think a sheet can hold 1M rows :thinking: (may be it does ? )

so far we need to wrap the above code in a for loop iterating on data and run that for each dict found in the list data. it takes sometime to run if we have a lot of rows in data but nothing to long I believe.

alifeee commented 2 days ago

yes. my example, effectively, was an implementation of set_record (singular data), instead of set_records (plural data)

I think slowness will not be a problem. We will see if it is after making the code.

lavigne958 commented 1 day ago

alright then, let's put it in the next milestone.