I finally got this figured out. I wish I could get the 20 hours of time I spent back, hah hah! Basically, the main problem here is that I’m using a distributed configuration. Things like sgtk_from_path() and sgtk_from_entity() only work if you use a centralized configuration.
Furthermore - RV uses a very basic config, and it doesn’t have any local cache storage available, so it can’t download a config. It initializes TK with no context, and forces the bootstrap manager to not lookup/download any pipeline configs. If you try to force it to bootstrap with a specific pipeline config you won’t be able to start the tk-rv engine, and if you try to start a different engine you’ll also get an error since the other engines are not in the code that comes pre-packaged with RV.
The big bummer about this configuration, in addition, is RV’s bare-bones config does not give you any templates, so anything that you have defined in a project-specific templates.yml file will be unavailable.
I also abandoned any sort of event handling or event firing. I found that the sgtk_bootstrap plugin does not consistently fire the sgtk-authenticated-user-changed event, so if I listen for that event, I won’t be guaranteed that I’ll receive it. Also sgtk_bootstrap starts the engine asynchronously, which would explain why that event isn’t fired on startup.
The Python package that I built is designed to apply shot-specific CDLs and look LUTs, and to source these paths from SG in a hopefully platform-independent way. In the init method, I set several class variables to None, such as self.sg. I also set a boolean, self.tkini, to False. For the source_setup method, I test to see if self.tkini is False, and if so, I do the following:
global sgtk
try:
module_test = dir(sgtk)
except NameError:
try:
import sgtk
except ModuleNotFoundError:
plugin_root = os.path.join(sgtk_bootstrap.sgtk_dist_dir(), "baked", "plugin")
sys.path.insert(0, os.path.join(plugin_root, "python"))
from sgtk_plugin_basic_rv import manifest
core_path = manifest.get_sgtk_pythonpath(plugin_root)
self._logger.info("Looking for tk-core here: %s" % str(core_path))
# now we can kick off sgtk
sys.path.insert(0, core_path)
self._logger.info("About to import sgtk...")
import sgtk
self.engine = sgtk.platform.current_engine()
if not self.engine:
self._logger.warning("Giving up on the external-sgtk-initialize event. Skipping engine.")
self.user = sgtk.get_authenticated_user()
if not self.user:
from sgtk_auth import get_toolkit_user
(user, url) = get_toolkit_user()
self.user = user
sgtk.set_authenticated_user(self.user)
self.shotgun = self.user.create_sg_connection()
else:
self.shotgun = self.engine.shotgun
self.storagekey = sgtk.util.ShotgunPath.get_shotgun_storage_key()
self.local_storages = self.shotgun.find("LocalStorage", [], [self.storagekey])
self.tkini = True
return
I do a check for sgtk.platform.current_engine() to see if the tk-rv bootstrap has occurred. This works sometimes, so I just return if the current engine is not None. However if it isn’t, I make my own connection to SG.
If anyone from the RV team happens to read this - I would make a case for a complete redesign of RV’s scripting abilities. First, ditch Mu - not sure why that was chosen in the first place, but it’s a language that nobody knows, is not used anywhere else, and the documentation is non-existent except for on Autodesk’s site, and a lot of it is missing even there. I’d love to see an entirely Python API that makes sgtk available in the PYTHONPATH by default, and has already handled all of the authentication/bootstrapping.