Issue: RH8 ScriptEditor can't run my normal python code

Hi there,

I am trying to runa py3 script in the scriptEditor that writes data to Google Firebase, but I get an unexpected error.

  • The script runs fine if I run in python3.11 from the powershell, outside of Rhino.
  • reading from the database works in RH8 as expected

Can anyone help me with this? (@eirannejad maybe :smiley: ?)

Thanks,
Tim

"""Requirements"""
print('installing python packages once...')
# r: firebase-admin
# r: google-cloud-firestore
print('packages installed')#! python3

import sys, os
sys.path.append(os.getcwd() + '/../')

import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore


def main():
    app = firebase_admin._apps.get('[DEFAULT]')
    if not app:
        cred = credentials.Certificate(r"path\to\my\credentials.json")
        app = firebase_admin.initialize_app(cred)
    db = firestore.client()

    doc_ref = db.collection(u'application_metadata').document( u'test' )
    doc_ref.set({'uuid':'test'})

if __name__ == '__main__':
    main()

the error message seems to point to one of the dependencies that is not working when executing the script inside the RH8 scripteditor.

Traceback (most recent call last):
  File "file:///T:/Shared%20drives/Library%20DS/Scripts/tnm_suite_dev/playground/test_firebase.py", line 33, in <module>
  File "file:///T:/Shared%20drives/Library%20DS/Scripts/tnm_suite_dev/playground/test_firebase.py", line 30, in main
  File "C:\Users\info\.rhinocode\py39-rh8\site-envs\default-vc4N90f8\google\cloud\firestore_v1\document.py", line 166, in set
    batch, kwargs = self._prep_set(document_data, merge, retry, timeout)
  File "C:\Users\info\.rhinocode\py39-rh8\site-envs\default-vc4N90f8\google\cloud\firestore_v1\base_document.py", line 217, in _prep_set
    batch.set(self, document_data, merge=merge)
  File "C:\Users\info\.rhinocode\py39-rh8\site-envs\default-vc4N90f8\google\cloud\firestore_v1\base_batch.py", line 111, in set
    write_pbs = _helpers.pbs_for_set_no_merge(
  File "C:\Users\info\.rhinocode\py39-rh8\site-envs\default-vc4N90f8\google\cloud\firestore_v1\_helpers.py", line 723, in pbs_for_set_no_merge
    set_pb = extractor.get_update_pb(document_path)
  File "C:\Users\info\.rhinocode\py39-rh8\site-envs\default-vc4N90f8\google\cloud\firestore_v1\_helpers.py", line 586, in get_update_pb
    name=document_path, fields=encode_dict(self.set_fields)
  File "C:\Users\info\.rhinocode\py39-rh8\site-envs\default-vc4N90f8\google\cloud\firestore_v1\_helpers.py", line 238, in encode_dict
    return {key: encode_value(value) for key, value in values_dict.items()}
  File "C:\Users\info\.rhinocode\py39-rh8\site-envs\default-vc4N90f8\google\cloud\firestore_v1\_helpers.py", line 238, in <dictcomp>
    return {key: encode_value(value) for key, value in values_dict.items()}
  File "C:\Users\info\.rhinocode\py39-rh8\site-envs\default-vc4N90f8\google\cloud\firestore_v1\_helpers.py", line 195, in encode_value
    return document.Value(string_value=value)
  File "C:\Users\info\.rhinocode\py39-rh8\site-envs\default-vc4N90f8\proto\message.py", line 615, in __init__
    super().__setattr__("_pb", self._meta.pb(**params))
TypeError: 'NoneType' object is not callable

@timcastelijn The error is from inside proto library. I suggest using the debugger to dig into the call stack and see what would a value be Null. I am not personally familar with the firebase_admin module.

Just make sure that these modules are installed for python 3.9 that is shipped with Rhino 8

I donā€™t have access to the app or credentials so there is really no easy way for me to test this. Let me know if stepping into the firebase module in debugger does not work

Hi @eirannejad

Thanks for our help!
I made a test project in Google Firebase to share the credentials with you.

It turned out that adding # flag: python.reloadEngine (topic) or clicking ā€œTools>Reload Python3ā€ results in the NoneType error. It appears to me that some cached data is cleared that is later referred to by this line:

app = firebase_admin._apps.get('[DEFAULT]')

I think Iā€™ll need to find an alternative way for reloading my local modules whenever the files have changed.

I have no experience with the module debugger, can I use this feature from inside Rhino?

Thanks again,
Tim

Yes. You can hover over the left side of script lines and create a new breakpoint. The toolbar activates the debug buttons and then you can run/debug the script.

Hi @eirannejad,

currently I have 2 cases:

  1. when I run the script once, everything works as expected
  2. when I ā€˜reload Python 3 (Cpython) Engineā€™ and run the script again I get the NoneType error (n.b. I use this during development, because my local modules are not reloaded when I change the fiels)

I suggest using the debugger to dig into the call stack and see what would a value be Null

Iā€™ve used the module debugger, the variable values from case1 are comparable to case2. There are no unexpected ā€˜Noneā€™ values. Also, the call stack doesnā€™t show a lot of information at the time the script crashes:

Iā€™ve created an isolated Firestore project to be able to share the credentials with you. Is there a way to share it privately on this forum? In case you have time for this, could you have a look at it?

Thanks!
Tim

"""Requirements"""
print('installing python packages once...')
# r: firebase-admin
# r: google-cloud-firestore

# flag: python.reloadEngine
print('packages installed')#! python3

from uuid import uuid4
from datetime import datetime
from time import sleep

import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore


def main():
    
    app = firebase_admin._apps.get('[DEFAULT]')
    if not app:
        cred = credentials.Certificate(r"C:\Users\info\Downloads\credentials.json")
        app = firebase_admin.initialize_app(cred)

    db = firestore.client()

    uuid = '%s' % uuid4()

    # write to database
    doc_ref = db.collection(u'test_data').document( u'%s' % uuid )
    doc_ref.set({
        "uuid":uuid,
        "created_at":datetime.utcnow()
    })
    print('write doc %s' % uuid)
    sleep(0.5)

    # read from database
    doc_ref2 = db.collection(u'test_data').document(u'%s' % uuid)
    doc = doc_ref2.get()
    print(doc.to_dict())


if __name__ == '__main__':
    main()```

hi @eirannejad,

judging by the line above, I think self._meta.pb() from the googleapis protobuffer package, line763 is None after runing ā€˜tools>reset Python 3 (Cpython) Engineā€™

I do not understand how ā€™ Reset Python 3 Engineā€™ works under the hood, but to me it seems that the package itself is not (entirely) re-imported after resetting, but the function is cleared from the memory.

hi @eirannejad,

Iā€™ve implemented this ModuleReloader class as a workaround. It reloads all local modules whenever the files are changed, so I donā€™t have to use ā€œReset Python3 engineā€

ModuleReloader.py (2.5 KB)

1 Like