Custom App args

It was asked in a support question whether a Toolkit App can be set up to receive custom arguments when it is triggered to run.
For example, when you run an app, you may want to provide some kind of state flag which causes the app to launch differently depending on the state.

The answer is yes it is possible. Here are a couple of examples of where this is already used:

Programming your app to accept args

If you’re writing a custom app, all you need to do is set the callback method that gets registered with the engine to accept the args you need.
Here is a simple app set up to require two args, accept any additional ones, and print them:

from sgtk.platform import Application


class AnimalApp(Application):

    def init_app(self):
        self.engine.register_command("print_animal", self.run_method)

    def run_method(self, animal, age, *args):
        print ("",animal)
        print ("age",age)
        print ("args", args)

Running from the tank command

Now if you run the following tank command in a shell:

 ./tank print_animal cat 7 Tortoiseshell large

it will result in the following being output:

...

----------------------------------------------------------------------
Command: Print animal
----------------------------------------------------------------------

libpng warning: iCCP: known incorrect sRGB profile
('animal', 'cat')
('age', '7')
('args', ('Tortoiseshell', 'large'))

Running from a script

If you wanted to call your app from a script on the tk-shell engine you could do the following:

# This assumes you have a reference to the `tk-shell` engine.
engine.execute_command("print_animal", ["dog", "3", "needs a bath"])
>>
# ('animal', 'dog')
# ('age', '3')
# ('args', ('needs a bath',))

if you were in Maya you would do something like:

import sgtk

# get the engine we are currently running in.
engine = sgtk.platform.current_engine()
# Run the app.
engine.commands['print_animal']['callback']("unicorn",4,"it's soooo fluffy!!!!")

>>
# ('animal', 'unicorn')
# ('age', 4)
# ('args', ("it's soooo fluffy!!!!",))

However, if you tried to launch the app from the menu in Maya you would get an error like this:

// Error: Shotgun tk-maya: An exception was raised from Toolkit
Traceback (most recent call last):
  File "/Users/philips1/Library/Caches/Shotgun/bundle_cache/app_store/tk-maya/v0.10.1/python/tk_maya/menu_generation.py", line 234, in _execute_within_exception_trap
    self.callback()
  File "/Users/philips1/Library/Caches/Shotgun/mysite/p89c1.basic.maya/cfg/install/core/python/tank/platform/engine.py", line 1082, in callback_wrapper
    return callback(*args, **kwargs)
TypeError: run_method() takes at least 3 arguments (1 given) // 

And that is because the app is set to require the arguments, and the menu button doesn’t know to provide them. So actually it is better to write your app’s run_method to use keyword arguments like this:

    def run_method(self, animal=None, age=None, *args):
        print ("",animal)
        print ("age",age)
        print ("args", args)

Then you can handle what happens if the args are not provided and implement a fallback behavior.

8 Likes

It’s probably also worth mentioning, that adding args to the registered callback method, is probably only really useful for:

  • Testing purposes where you want to launch the app directly through code with specific settings.
  • If another app wants to be able to launch your app and provide additional settings, like with the tk-shotgun-launchpublish > tk-multi-launchapp, providing the file to launch with.

The other approach would be to just have a public method on the app which you can call, instead of going via the registered callback:

# You can print `engine.apps.keys()` to get a list of the app keys.
engine.apps["tk-multi-starterapp"].run_method("monkey",12)
4 Likes

Great examples Phil! Thanks for taking the time to put them together! Very helpful

2 Likes

is run_method something that comes with every app?

I was trying it but on tk-multi-publish2 I get:

'MultiPublish2' object has no attribute 'run_method'

1 Like

@Ricardo_Musch, run_method() is a function of his AnimalApp class in the first code snippet.

4 Likes

I skipped over that somehow! :see_no_evil:

Thanks!

2 Likes