0

Proper way to use a framework from within a hook

Hi

I'm working on hooking into the publish, loader and workfiles apps to transfer files to and from our amazon s3 account as needed. My idea was to create a new framework that would be used by other apps to handle the connection and transfer. That would in turn use the tk-framework-login to handle the credentials. I was hoping to do most (if not all) of the work using hooks of existing apps, such as the copy_file hook for tk-multi-publish.

Now to the question at hand, what is the best way to use a framework from inside a hook? I've added my framework to the environment but I can't use the usual tank.platform.import_framework() inside a hook.

Right now I'm doing the following ugly hack:

frameworks_to_load = [{"name": "mg-framework-aws", "version": "v0.0.1"}]
frameworks = dict()
def _load_frameworks():
    engine = tank.platform.engine.current_engine()

    # This will fail if tank.platform.validation.validate_and_return_frameworks
    # calls something else of descriptor than get_required_frameworks
    descriptor = type("descriptorhack", (object,),{"get_required_frameworks": (lambda x: frameworks_to_load)})

    env = engine.get_env()

    load_frameworks = tank.platform.validation.validate_and_return_frameworks(descriptor(), env)

    for load_framework in load_frameworks:
        framework = tank.platform.framework.load_framework(engine, env, load_framework)
        frameworks[framework.name] = framework

_load_frameworks()
login = frameworks["mg-framework-aws"].import_module("login")

10 comments

  • 0
    Avatar
    Nils Lerin

    Unless I want to explicitly specify the version for the framework to use then I chould just do:

    AWS_FRAMEWORK_NAME = "mg-framework-aws_v0.x.x"
    aws_fw = self.load_framework(AWS_FRAMEWORK_NAME)
    aws_fw.handler = aws_fw.import_module("handler")
    

    I think I'll stick to that

  • 0
    Avatar
    Permanently deleted user

    Hej Nils!

    Looks like you found the answer! Yes, using load_framework is the recommended way to go.

    For future readers of this post, here is a link to the API documentation for the load_framework method: https://support.shotgunsoftware.com/entries/95441117

    The only thing to bear in mind while using load_framework inside your hook is that you need to define the framework inside your environment file. This is so that all toolkit's standard update and code management methods will work the same way for frameworks running in hooks that they do everywhere else!

    If you did want to explicitly specify the version of the framework to use, you can use this too - but in the environment rather than in the code - simply omit the x.x.x in favour of an actual version number, and toolkit would "lock on" to that version number.

    frameworks:
      # Always want to use 1.0.5 of the framework
      mg-framework-aws_v1.0.5:
        location: {...}
      # This framework instance will auto update when running tank updates.
      # whenever a v1.something update is available, this will be picked up and used.
      mg-framework-aws_v1.x.x:
        location: {...}
    

    In your hook code, you then refer to the instance name:

    aws_fw_v105 = self.load_framework("mg-framework-aws_v1.0.5")
    aws_fw_latest = self.load_framework("mg-framework-aws_v1.x.x")
    

    Thanks for your great question! Sounds like you are building a really cool setup. Don't hesitate to reach out if you need help with anything else!

    Manne

     

  • 0
    Avatar
    Nils Lerin

    Thanks for the details on that, make perfect sense.

    /Nils

  • 0
    Avatar
    Nils Lerin

    Hi again Manne!

    I just ran into the need to load a framework from a core hook, get_current_login. What I would like to do is to return the user currently logged in through the login-framework instead of the default which is the os username. Is there a workaround?

    - Nils

  • 0
    Avatar
    Permanently deleted user

    Hello Nils!

    Apologies for not responding to this earlier - I suspect this is all water under the bridge for you now, but still wanted to follow up.

    We don't currently have a way to run frameworks from inside of core hooks. We recently extended the core to support the new-style hook syntax, but there is currently no way to configure which frameworks that should be loaded as part of the core.

    One of our high priorities coming up very soon will be to add native support for logging in with a username into toolkit – we may add framework loading to the core for this. We have also talked a little bit in the past about breaking out some of the core functionality into separate frameworks - stuff like the folder creation, even the template system itself. But that's all on a brainstorm level at the moment.

    Thanks!
    Manne

  • 0
    Avatar
    Nils Lerin
    Hi Manne. Yes I found a workaround that works pretty good. Does that mean that toolkit will also connect to sg using user credentials instead of the almighty api key? If so I'm really looking forward to that update
  • 0
    Avatar
    Permanently deleted user

    Yepp, that's exactly the plan!

  • 0
    Avatar
    René Calles

    Hi Nils,

    do you mind to share your workaround as i'm actually looking into the exact same thing regarding the get_current_login hook.

    ~René

  • 0
    Avatar
    Nils Lerin

    Hi René

    Sure. I edited the core engine_init hook to set tank.util.login.g_shotgun_current_user_cache to the user logged in through tk-framework-login. Here's the way I did it. Hopefully in the next release toolkit will  be initialized with a shotgun user and we won't need this workaround

    LOGIN_FRAMEWORK_NAME = "tk-framework-login_v1.x.x"

    class EngineInit(Hook):

    def execute(self, engine, **kwargs):
    if engine and (engine.name == "tk-maya" or engine.name == "tk-motionbuilder"):
    g_shotgun_current_user_cache = tank.util.login.g_shotgun_current_user_cache
    if g_shotgun_current_user_cache == "unknown" or g_shotgun_current_user_cache is None:
    login_framework = tank.platform.framework.load_framework(engine, engine.get_env(), LOGIN_FRAMEWORK_NAME)
    login_handler = login_framework.import_module("shotgun_login").ShotgunLogin()
    login_handler.set_default_site(engine.shotgun.base_url)
    login_info = login_handler.login()
    if not login_info:
    engine.log_warning("Failed to get shotgun login details. Username will be set to default")
    else:
    fields = ["id", "type", "email", "login", "name", "image"]
    tank.util.login.g_shotgun_current_user_cache = engine.shotgun.find_one(
    "HumanUser", filters=[["login", "is", login_info["login"]["login"]]], fields=fields)

  • 0
    Avatar
    René Calles

    Thanks Nils,

    that helps a lot. 

    Cheers,
    René

Please sign in to leave a comment.