Cannot import Google API libraries to Python Script

Hello everyone,

I am having troubles when taking a standalone script that I have been working on to a Python Script node inside of Dynamo.

Basically what I want to do is to upload images from the Revit document to Google Drive and then linking those uploaded images to cells in a Google Sheet.

I know that there is a package called BIMOne that allows writing data from Dynamo to Google Sheets, but as I also need to upload images to Drive I need to create a custom node with extended functionality.

The runtime error occurs at the moment of importing the Google API libraries, therefore that will be the only code written for now for illustrative purposes.

I also tried using PyRevit and producing a plugin instead of a custom Dynamo node, but same luck.

PS: The first error shown in the case of PyRevit also appeared in the case of the Dynamo node at another moment.

1 Like

One thought… Comment out each of the google import lines, and i comment them to so isolate which is causing the error. As is now you don’t know which of the imports is causing the failure.

Hello Jacob, thanks for your reply.

I tried commenting them one by one, but all are producing errors, it seems like Python is not able to recognize the packages, and when it does then it shows syntax errors.

This is the only environment where I am having problems, because if I run the script from VSCode it works well.

Maybe is it a compatibility problem between IronPython and the Google API libraries?

What Dynamo version are you in, and what version of Python are the google libraries written for (meaning 2 or 3)?

I am running in Revit 2020 with Dynamo 2.3, and the prerequisites of Google Drive and Google Sheets API shows that they should work with Python 2.6 or greater.

I started to test with the Dynamo 2.11 Sandbox as it integrated CPython and it seems to work.

The script is exactly the same in both nodes, but the only one where it works is the one with CPython. The output is the ID of an image stored in Google Drive.

I still need to install this 2.11 build in Revit 2020 and check it works, so this should not be considered a solution yet.

image

Nothing, new error as soon I switched to CPython after installing the 2.11 build in Revit 2020

2.11 is not supported in Revit 2020.

Does it work in Revit 2022?

Will try, the only catch with that is that in our firm we cannot upgrade our projects to Revit 2022 yet.

I think that CPython was implemented in Dynamo 2.7 right? Maybe Dynamo 2.7 is supported by Revit 2020, or not?

Nope - the only supported Dynamo builds on 2020 are the ones which come with the Revit installations - I believe that 2.3 is the highest it goes.

Got it, thank you so much for your time Jacob!

Will keep you posted on any update on this.

1 Like

Hello @Ricardosalasv
alternately you can use the GoogleAPI Net assemblies

https://www.nuget.org/packages?q=google.apis&prerelease=true&sortOrder=relevance

import sys
import clr
import System
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

clr.AddReferenceToFileAndPath(r'C:\Users\sneep\Downloads\GoogleApi\Google.Apis.dll')
clr.AddReferenceToFileAndPath(r'C:\Users\sneep\Downloads\GoogleApi\Google.Apis.Auth.dll')
clr.AddReferenceToFileAndPath(r'C:\Users\sneep\Downloads\GoogleApi\Google.Apis.Auth.PlatformServices.dll')
clr.AddReferenceToFileAndPath(r'C:\Users\sneep\Downloads\GoogleApi\Google.Apis.Drive.v3.dll')
clr.AddReferenceToFileAndPath(r'C:\Users\sneep\Downloads\GoogleApi\Google.Apis.Core.dll')

import Google.Apis.Auth.OAuth2 as gOauth2
import Google.Apis.Drive.v3 as gDrive
import Google.Apis.Services as gServices
import Google.Apis as gApi
import Google.Apis.Util.Store as gUtilStore
from Google.Apis.Auth.OAuth2 import *
from Google.Apis.Drive.v3 import *
from Google.Apis.Drive.v3.Data import *
from Google.Apis.Services import *


clientSecretPath = IN[0]

scopes = System.Array[str]([DriveService.Scope.DriveReadonly])
applicationName = "MyNameApp"
with System.IO.FileStream(clientSecretPath, System.IO.FileMode.Open,System.IO.FileAccess.Read) as stream:
	credPath = "token.json"
	credential = gOauth2.GoogleWebAuthorizationBroker.AuthorizeAsync(gOauth2.GoogleClientSecrets.Load(stream).Secrets, 
				scopes,
				'user', 
				System.Threading.CancellationToken.None, 
				gUtilStore.FileDataStore(credPath,True)).Result

initializer = gServices.BaseClientService.Initializer()
initializer.HttpClientInitializer = credential
initializer.ApplicationName = applicationName
service = DriveService(initializer)
listRequest = service.Files.List()
listRequest.PageSize = 10
listRequest.Fields = "nextPageToken, files(id, name)"
files = listRequest.Execute().Files
OUT = service, files
4 Likes

Awesome solution @c.poupin!

2 Likes

just for the exercise here is the same example compatible with the 2 engines

import sys
import clr
import System
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('System.Threading')
from System.Threading import CancellationToken
# append the DLL folder to the path 
sys.path.append(r'C:\Users\sneep\Downloads\GoogleApi')
clr.AddReference('Google.Apis')
clr.AddReference('Google.Apis.Auth')
clr.AddReference('Google.Apis.Auth.PlatformServices')
clr.AddReference('Google.Apis.Drive.v3')
clr.AddReference('Google.Apis.Core')

import Google.Apis.Auth.OAuth2 as gOauth2
import Google.Apis.Drive.v3 as gDrive
import Google.Apis.Services as gServices
import Google.Apis as gApi
import Google.Apis.Util.Store as gUtilStore
from Google.Apis.Auth.OAuth2 import *
from Google.Apis.Drive.v3 import *
from Google.Apis.Drive.v3.Data import *
from Google.Apis.Services import *

clientSecretPath = IN[0]
scopes = System.Array[str]([DriveService.Scope.DriveReadonly])
applicationName = "MyApp"
stream = System.IO.FileStream(clientSecretPath, System.IO.FileMode.Open,System.IO.FileAccess.Read)
credPath = "token.json"
credential = gOauth2.GoogleWebAuthorizationBroker.AuthorizeAsync(gOauth2.GoogleClientSecrets.Load(stream).Secrets, 
    scopes,
    'user', 
    CancellationToken(False), 
    gUtilStore.FileDataStore(credPath,True)).Result
# Note :
# CancellationToken.None not work with CPython/PythonNet need to use CancellationToken(False) in this case
stream.Dispose()

initializer = gServices.BaseClientService.Initializer()
initializer.HttpClientInitializer = credential
initializer.ApplicationName = applicationName
service = DriveService(initializer)
listRequest = service.Files.List()
listRequest.PageSize = 10
listRequest.Fields = "nextPageToken, files(id, name)"
files = listRequest.Execute().Files
OUT = sys.version, service, files
2 Likes

Hello @c.poupin , thank you so much for that solution! I am testing it. I just downloaded manually the NuGet packages and the code seems to import them well. This will help me a lot!

As I am understanding, then I should work with the .NET assemblies syntax when using API related functions right? Or should I continue using the syntax from the Python API syntax?

A problem that I encountered trying to implement your code is that it says that it can’t access the token file. image

This is the code I am using, I just edited the fields related to my local environment and changed the scopes to match the ones of my console app.

Hello @Ricardosalasv
try to change the local path to a path where you have permissions
example

myDoc = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments)
credPath = myDoc + "\\token.json"
1 Like

It worked! It seems like it imported everything well and that it outputted everything as intended.

What I am thinking it did not get is the Spreadsheets API, I will have to take a look on the correct way of adding multiple scopes in this case.

I will keep you posted, thank you so much!

3 Likes