Adding columns to Google Sheets - python

I am trying to add columns to a Google Sheets, but I get an error. I need to add a copy of the previous column.
Code:
def insert_column():
sa = gspread.service_account(filename="service_account.json")
sh = sa.open("**NAME**")
wks = sh.worksheet("Class Data")
data = {
"requests": [
{
"insertDimension": {
"range": {
"sheetId": 0,
"dimension": "COLUMNS",
"startIndex": 4,
"endIndex": 5
},
"inheritFromBefore": True
}
},
],
}
wks.batch_update(data).execute()
An Error: TypeError: string indices must be integers
I think the problem is here wks.batch_update(data).execute() , but I don't know how to solve it.

When I saw the document of gspread, it seems that batch_update(body) is the method of class gspread.spreadsheet.Spreadsheet. But, you are using this method as the method of class gspread.worksheet.Worksheet. I think that this is the reason for your issue of TypeError: string indices must be integers. And also, execute() is not required to be used.
When these points are reflected in your script, it becomes as follows.
Modified script:
def insert_column():
sa = gspread.service_account(filename="service_account.json")
sh = sa.open("**NAME**")
# wks = sh.worksheet("Class Data") # In this script, this line is not used.
data = {
"requests": [
{
"insertDimension": {
"range": {
"sheetId": 0, # <--- Please set the sheet ID of "Class Data" sheet.
"dimension": "COLUMNS",
"startIndex": 4,
"endIndex": 5
},
"inheritFromBefore": True
}
},
],
}
sh.batch_update(data)
Note:
This modified script supposes that your service account can access to the Spreadsheet. Please be careful about this.
Reference
batch_update(body)

Related

How to parse nested JSON object?

I am working on a new project in HubSpot that returns nested JSON like the sample below. I am trying to access the associated contacts id, but am struggling to reference it correctly (the id I am looking for is the value '201' in the example below). I've put together this script, but this script only returns the entire associations portion of the JSON and I only want the id. How do I reference the id correctly?
Here is the output from the script:
{'contacts': {'paging': None, 'results': [{'id': '201', 'type': 'ticket_to_contact'}]}}
And here is the script I put together:
import hubspot
from pprint import pprint
client = hubspot.Client.create(api_key="API_KEY")
try:
api_response = client.crm.tickets.basic_api.get_page(limit=2, associations=["contacts"], archived=False)
for x in range(2):
pprint(api_response.results[x].associations)
except ApiException as e:
print("Exception when calling basic_api->get_page: %s\n" % e)
Here is what the full JSON looks like ('contacts' property shortened for readability):
{
"results": [
{
"id": "34018123",
"properties": {
"content": "Hi xxxxx,\r\n\r\nCan you clarify on how the blocking of script happens? Is it because of any CSP (or) the script will decide run time for every URL’s getting triggered from browser?\r\n\r\nRegards,\r\nLogan",
"createdate": "2019-07-03T04:20:12.366Z",
"hs_lastmodifieddate": "2020-12-09T01:16:12.974Z",
"hs_object_id": "34018123",
"hs_pipeline": "0",
"hs_pipeline_stage": "4",
"hs_ticket_category": null,
"hs_ticket_priority": null,
"subject": "RE: call followup"
},
"createdAt": "2019-07-03T04:20:12.366Z",
"updatedAt": "2020-12-09T01:16:12.974Z",
"archived": false
},
{
"id": "34018892",
"properties": {
"content": "Hi Guys,\r\n\r\nI see that we were placed back on the staging and then removed again.",
"createdate": "2019-07-03T07:59:10.606Z",
"hs_lastmodifieddate": "2021-12-17T09:04:46.316Z",
"hs_object_id": "34018892",
"hs_pipeline": "0",
"hs_pipeline_stage": "3",
"hs_ticket_category": null,
"hs_ticket_priority": null,
"subject": "Re: Issue due to server"
},
"createdAt": "2019-07-03T07:59:10.606Z",
"updatedAt": "2021-12-17T09:04:46.316Z",
"archived": false,
"associations": {
"contacts": {
"results": [
{
"id": "201",
"type": "ticket_to_contact"
}
]
}
}
}
],
"paging": {
"next": {
"after": "35406270",
"link": "https://api.hubapi.com/crm/v3/objects/tickets?associations=contacts&archived=false&hs_static_app=developer-docs-ui&limit=2&after=35406270&hs_static_app_version=1.3488"
}
}
}
You can do api_response.results[x].associations["contacts"]["results"][0]["id"].
Sorted this out, posting in case anyone else is struggling with the response from the HubSpot v3 Api. The response schema for this call is:
Response schema type: Object
String results[].id
Object results[].properties
String results[].createdAt
String results[].updatedAt
Boolean results[].archived
String results[].archivedAt
Object results[].associations
Object paging
Object paging.next
String paging.next.after
String paging.next.linkResponse schema type: Object
String results[].id
Object results[].properties
String results[].createdAt
String results[].updatedAt
Boolean results[].archived
String results[].archivedAt
Object results[].associations
Object paging
Object paging.next
String paging.next.after
String paging.next.link
So to access the id of the contact associated with the ticket, you need to reference it using this notation:
api_response.results[1].associations["contacts"].results[0].id
notes:
results[x] - reference the result in the index
associations["contacts"] -
associations is a dictionary object, you can access the contacts item
by it's name
associations["contacts"].results is a list - reference
by the index []
id - is a string
In my case type was ModelProperty or CollectionResponseProperty couldn't reach dict anyhow.
For the record this got me to go through the results.
for result in list(api_response.results):
ID = result.id

How to predefined number of rows and cols within gspread

I do have a scraped data which i overwriting google sheet daily with it.
The point here that I'm unable to find an option where i can set number of rows and cols for the existing google sheet.
I noticed that can be done only for new created sheet according to documentation but i don't know how to do it for existing sheet!
def api(key):
myfilt = [list of lists]
columns = [name of columns]
gc = gspread.service_account(filename='Auth.json')
sh = gc.open_by_key(key)
worksheet = sh.sheet1
worksheet.clear()
head = worksheet.insert_row(columns, 1)
res = worksheet.insert_rows(myfilt, 2)
api("MyAPIHere")
My target here is to predefined number of rows according to len(myfilt) and number of cols according to len(cols)
I believe your goal as follows.
You want to change the max row and column number of the existing sheet in the Google Spreadsheet.
You want to achieve this using gspread with python.
You have already been able to get and put values for Google Spreadsheet using Sheets API.
Points for achieving your goal:
In this case, it is required to use the method of "spreadsheets.batchUpdate" in Sheets API. And I would like to propose the following flow.
Insert one row.
Insert one column.
Delete rows from 2 to end.
Delete columns from 2 to end.
Insert rows. In this case, you can set the number of rows you want to insert.
Insert columns. In this case, you can set the number of columns you want to insert.
1 and 2 are used for avoiding the error. Because when the DeleteDimensionRequest is run for the sheet which has only one row or one column, an error occurs.
When above flow is reflected to the script using gspread, it becomes as follows.
Sample script:
Please set the Spreadsheet ID and sheet name.
spreadsheetId = "###" # Please set the Spreadsheet ID.
sheetName = "###" # Please set the sheet name.
client = gspread.authorize(credentials)
spreadsheet = client.open_by_key(spreadsheetId)
# worksheet = spreadsheet.worksheet(sheetName)
sheetId = spreadsheet.worksheet(sheetName)._properties['sheetId']
rows = len(myfilt)
columns = len(cols)
req = {
"requests": [
{
"insertDimension": {
"range": {
"sheetId": sheetId,
"startIndex": 0,
"endIndex": 1,
"dimension": "ROWS"
}
}
},
{
"insertDimension": {
"range": {
"sheetId": sheetId,
"startIndex": 0,
"endIndex": 1,
"dimension": "COLUMNS"
}
}
},
{
"deleteDimension": {
"range": {
"sheetId": sheetId,
"startIndex": 1,
"dimension": "ROWS"
}
}
},
{
"deleteDimension": {
"range": {
"sheetId": sheetId,
"startIndex": 1,
"dimension": "COLUMNS"
}
}
},
{
"insertDimension": {
"range": {
"sheetId": sheetId,
"startIndex": 0,
"endIndex": rows - 1,
"dimension": "ROWS"
}
}
},
{
"insertDimension": {
"range": {
"sheetId": sheetId,
"startIndex": 0,
"endIndex": columns - 1,
"dimension": "COLUMNS"
}
}
}
]
}
res = spreadsheet.batch_update(req)
print(res)
References:
Method: spreadsheets.batchUpdate
DeleteDimensionRequest
InsertDimensionRequest
batch_update(body)
I used the following to solve my issue as well:
worksheet.clear() # to clear the sheet firstly.
head = worksheet.insert_row(header, 1) # inserting the header at first row
res = worksheet.insert_rows(mydata, 2) # inserting my data.
worksheet.resize(rows=len(mydata) + 1, cols=len(header)) # resize according to length of cols and rows.

Dictionary length is equal to 3 but when trying to access an index receiving KeyError

I am attempting to parse a json response that looks like this:
{
"links": {
"next": "http://www.neowsapp.com/rest/v1/feed?start_date=2015-09-08&end_date=2015-09-09&detailed=false&api_key=xxx",
"prev": "http://www.neowsapp.com/rest/v1/feed?start_date=2015-09-06&end_date=2015-09-07&detailed=false&api_key=xxx",
"self": "http://www.neowsapp.com/rest/v1/feed?start_date=2015-09-07&end_date=2015-09-08&detailed=false&api_key=xxx"
},
"element_count": 22,
"near_earth_objects": {
"2015-09-08": [
{
"links": {
"self": "http://www.neowsapp.com/rest/v1/neo/3726710?api_key=xxx"
},
"id": "3726710",
"neo_reference_id": "3726710",
"name": "(2015 RC)",
"nasa_jpl_url": "http://ssd.jpl.nasa.gov/sbdb.cgi?sstr=3726710",
"absolute_magnitude_h": 24.3,
"estimated_diameter": {
"kilometers": {
"estimated_diameter_min": 0.0366906138,
"estimated_diameter_max": 0.0820427065
},
"meters": {
"estimated_diameter_min": 36.6906137531,
"estimated_diameter_max": 82.0427064882
},
"miles": {
"estimated_diameter_min": 0.0227984834,
"estimated_diameter_max": 0.0509789586
},
"feet": {
"estimated_diameter_min": 120.3760332259,
"estimated_diameter_max": 269.1689931548
}
},
"is_potentially_hazardous_asteroid": false,
"close_approach_data": [
{
"close_approach_date": "2015-09-08",
"close_approach_date_full": "2015-Sep-08 09:45",
"epoch_date_close_approach": 1441705500000,
"relative_velocity": {
"kilometers_per_second": "19.4850295284",
"kilometers_per_hour": "70146.106302123",
"miles_per_hour": "43586.0625520053"
},
"miss_distance": {
"astronomical": "0.0269230459",
"lunar": "10.4730648551",
"kilometers": "4027630.320552233",
"miles": "2502653.4316094954"
},
"orbiting_body": "Earth"
}
],
"is_sentry_object": false
},
}
I am trying to figure out how to parse through to get "miss_distance" dictionary values ? I am unable to wrap my head around it.
Here is what I have been able to do so far:
After I get a Response object from request.get()
response = request.get(url
I convert the response object to json object
data = response.json() #this returns dictionary object
I try to parse the first level of the dictionary:
for i in data:
if i == "near_earth_objects":
dataset1 = data["near_earth_objects"]["2015-09-08"]
#this returns the next object which is of type list
Please someone can explain me :
1. How to decipher this response in the first place.
2. How can I move forward in parsing the response object and get to miss_distance dictionary ?
Please any pointers/help is appreciated.
Thank you
Your data will will have multiple dictionaries for the each date, near earth object, and close approach:
near_earth_objects = data['near_earth_objects']
for date in near_earth_objects:
objects = near_earth_objects[date]
for object in objects:
close_approach_data = object['close_approach_data']
for close_approach in close_approach_data:
print(close_approach['miss_distance'])
The code below gives you a table of date, miss_distances for every object for every date
import json
raw_json = '''
{
"near_earth_objects": {
"2015-09-08": [
{
"close_approach_data": [
{
"miss_distance": {
"astronomical": "0.0269230459",
"lunar": "10.4730648551",
"kilometers": "4027630.320552233",
"miles": "2502653.4316094954"
},
"orbiting_body": "Earth"
}
]
}
]
}
}
'''
if __name__ == "__main__":
parsed = json.loads(raw_json)
# assuming this json includes more than one near_earch_object spread across dates
near_objects = []
for date, near_objs in parsed['near_earth_objects'].items():
for obj in near_objs:
for appr in obj['close_approach_data']:
o = {
'date': date,
'miss_distances': appr['miss_distance']
}
near_objects.append(o)
print(near_objects)
output:
[
{'date': '2015-09-08',
'miss_distances': {
'astronomical': '0.0269230459',
'lunar': '10.4730648551',
'kilometers': '4027630.320552233',
'miles': '2502653.4316094954'
}
}
]

Passing the answer of Watson Assistant to a variable Python

I am trying to get the output of Watson Assistant into a variable. So as far as I have searched, i need to get the "output" and "text" part of the json (at first it is a dict, but then we parse it to a json). But I cannot seem to get it:
I have searched in these 2 questions already:This one for watson This one for parsing the json
The code is really simple: accessing to my bot, and inputting "trips". I've taken out the api and workspace, but I have them (obviously).
if __name__ == '__main__':
assistant = watson_developer_cloud.AssistantV1(
iam_apikey='{YOUR API HERE}',
version='2018-09-20',
url='https://gateway-syd.watsonplatform.net/assistant/api'
)
response = assistant.message(
workspace_id='{YOUR WORKSPACE HERE}',
input={
'text': 'trips'
}
).get_result()
fullResponse=json.dumps(response, indent=2)
print(fullResponse)
print("testing to print the output: ")
respuesta=json.dumps(response, indent=2)
#print(respuesta['output'][0]['text'])
print(respuesta['output']['text'])
And the output:
Traceback (most recent call last):
"intents": [
File "C:/Users/.PyCharmCE2018.3/config/scratches/pruebaMain.py", line 105, in <module>
{
print(respuesta['output']['text'])
"intent": "trips",
TypeError: string indices must be integers
"confidence": 1
}
],
"entities": [],
"input": {
"text": "trips"
},
"output": {
"generic": [
{
"response_type": "text",
"text": "We got trips to different countries! Type continents to know more!"
}
],
"text": [
"We got trips to different countries! Type continents to know more!"
],
"nodes_visited": [
"node_2_1544696932582"
],
"log_messages": []
},
"context": {
"conversation_id": "{took it out for privacy}",
"system": {
"initialized": true,
"dialog_stack": [
{
"dialog_node": "root"
}
],
"dialog_turn_counter": 1,
"dialog_request_counter": 1,
"_node_output_map": {
"node_2_1544696932582": {
"0": [
0
]
}
},
"branch_exited": true,
"branch_exited_reason": "completed"
}
}
}
testing to print the output:
Process finished with exit code 1
So I want to get the answer of "We got trips to different countries! Type continents to know more!". I have read the documentation of the python API and some more info (https://github.com/IBM-Cloud/watson-conversation-variables) of but can't seem to find anything. I also tried accessing the json variable with $but did not work.
You don't have to use json.dumps here, you can directly use the response JSON returned from the service as shown in the code snippet below
import watson_developer_cloud
if __name__ == '__main__':
assistant = watson_developer_cloud.AssistantV1(
iam_apikey='APIKEY',
version='2018-09-20',
url='https://gateway.watsonplatform.net/assistant/api'
)
response = assistant.message(
workspace_id='WORKSPACE_ID',
input={
'text': 'trips'
}
).get_result()
print(response)
print(response['output']['text'][0])

build dynamical JSON/LIST obj in Python

I'm a real Python newbee and I'm having problems creating a JSON/LIST obj.
What I want to end up with is the following JSON to send o an API
{
"request": {
"slice": [
{
"origin": "AMS",
"destination": "SYD",
"date": "2015-06-23"
}
],
"passengers": {
"adultCount": 1,
"infantInLapCount": 0,
"infantInSeatCount": 0,
"childCount": 0,
"seniorCount": 0
},
"solutions": 20,
"refundable": false
}
}
I figured to make a list and then to convert to JSON with the dumps() function. This works. The thing is, I need to change the date field with an iterator to add a day, but I'm stuck on changing this field.
Any advice?
thx!
As your question is a bit vague i can only guess that you're trying to modify the JSON version of your data directly, while you should modify the Python object before converting it into JSON... something like this:
d = {
"request": {
"slice": [
{
"origin": "AMS",
"destination": "SYD",
"date": "2015-06-23"
}
],
"passengers": {
"adultCount": 1,
"infantInLapCount": 0,
"infantInSeatCount": 0,
"childCount": 0,
"seniorCount": 0
},
"solutions": 20,
"refundable": False # note how this is python False, not js false!
}
}
# then you can do:
d["request"]["slice"][0]["date"] = "2015-05-23"
# and finally convert to json:
j = json.dumps(d)
If it happens that you get JSON as a string, you should first convert it into a python object so you can work on it:
# if j is your json string, convert it into a python object
d = json.loads(j)
# then do your modifications as above:
d["request"]["slice"][0]["date"] = "2015-05-23"
# and finally convert back to json:
j = json.dumps(d)

Categories