Apps, Engines and Frameworks

This part of the API documentation covers all the classes and methods used when dealing with Engines, Apps and Frameworks. If you are interested in developing your own apps, engines or frameworks, the base classes needed to be derived from are outlined below. The documentation also covers how to initialize and shut down the Toolkit engine platform.

Note

In order to use the functionality of sgtk.platform, you need to run it from an initialized toolkit environment. For more information on how to set this up, see Initialization and startup.

Managing Engines and Apps

The methods in this section are used when you want to start up or manage a Toolkit engine. This typically happens directly once a host application (e.g. Maya or Nuke) has been launched. A running engine typically needs to be terminated before a new engine can be started. The method for terminating an engine can be found on the engine class itself. Methods defining a standard interface for launching host applications are also provided.

sgtk.platform.start_engine(engine_name, tk, context)[source]

Creates an engine and makes it the current engine. Returns the newly created engine object. Example:

>>> import sgtk
>>> tk = sgtk.sgtk_from_path("/studio/project_root")
>>> ctx = tk.context_empty()
>>> engine = sgtk.platform.start_engine('tk-maya', tk, ctx)
>>> engine
<Sgtk Engine 0x10451b690: tk-maya, env: shotgun>

Note

This is for advanced workflows. For standard use cases, use bootstrap_engine(). For more information, see Initialization and startup.

Parameters:
  • engine_name – Name of the engine to launch, e.g. tk-maya
  • tkSgtk instance to associate the engine with
  • contextContext object of the context to launch the engine for.
Returns:

Engine instance

Raises:

TankEngineInitError if an engine could not be started for the passed context.

sgtk.platform.current_engine()[source]

Returns the currently active engine.

Returns:Engine instance or None if no engine is running.
sgtk.platform.get_engine_path(engine_name, tk, context)[source]

Returns the path to the engine corresponding to the given engine name or None if the engine could not be found.

Similar to start_engine(), but instead of starting an engine, this method returns the path to a suitable engine. This helper method is sometimes useful when initializing engines for applications that do not have a built in python interpreter.

Example:

>>> import sgtk
>>> tk = sgtk.sgtk_from_path("/studio/project_root")
>>> ctx = tk.context_empty()
>>> sgtk.platform.get_engine_path('tk-maya', tk, ctx)
/studio/sgtk/install/engines/app_store/tk-maya/v0.1.0
Parameters:
  • engine_name – Name of the engine to launch, e.g. tk-maya
  • tkSgtk instance to associate the engine with
  • contextContext object of the context to launch the engine for.
Returns:

Path to where the engine code is located on disk.

sgtk.platform.find_app_settings(engine_name, app_name, tk, context, engine_instance_name=None)[source]

Utility method to find the settings for an app in an engine in the environment determined for the context by pick environment hook.

Parameters:
  • engine_name – system name of the engine to look for, e.g tk-maya
  • app_name – system name of the app to look for, e.g. tk-multi-publish
  • tkSgtk instance
  • contextContext object to use when picking environment
  • engine_instance_name – The instance name of the engine to look for.
Returns:

list of dictionaries containing the engine name, application name and settings for any matching applications that are found and that have valid settings

sgtk.platform.change_context(new_context)[source]

Running change_context will attempt to change the context the engine and its apps are running in on the fly. The current engine must accept the context change, otherwise a full restart of the engine will be run instead.

The determination of whether an engine supports context changing comes from its “context_change_allowed” property. If that property returns True, then the context change will be allowed to proceed. If it returns False, then the engine’s “change_context” method will raise TankContextChangeNotSupportedError, which will then trigger a restart of the engine and all of its apps.

In the event that the engine does support context changes, any apps that support context changing will do so, as well. Any that do not will themselves be restarted within the new context.

The benefit of supporting context changes in engines and apps is speed. The end result of this routine should be identical to that of a restart, but will require less time to complete.

For more information on supporting context changing, see the following:

Parameters:new_context (Context) – The new Context to change to.
sgtk.platform.restart(new_context=None)[source]

Restarts the currently running Toolkit platform. This includes reloading all configuration files as well as reloading the code for all apps and engines. (The Core API, however, is not reloaded). The call does not take any parameters and does not return any value.

Any open windows will remain open and will use the old code base and settings. In order to access any changes that have happened as part of a reload, you need to start up new app windows (typically done via the Shotgun menu) and these will use the fresh code and configs.

Parameters:new_context (Context) – The new Context to start the engine in, if desired. Default behavior is to restart the engine with its current context.

Engines

A Toolkit engine connects a runtime environment such as a DCC with the rest of the Toolkit ecosystem. As the engine starts up, it loads the various associated apps and frameworks defined in the configuration and acts as a host for all these objects, ensuring that they can operate in a consistent fashion across integrations.

Information for App Developers

If you are developing an app, you typically call out to the engine via the Application.engine() accessor. You use the engine for a couple of main things:

The engine acts as a bridge between the DCC and the App so that the app doesn’t have to contain DCC-specific code to create dialogs or manage menus etc. Typically, any DCC specific code is contained within a Hook, making it easy to design apps that can be extended easily to support new engine environments.

Information for Engine developers

The engine is a collection of files, similar in structure to an App. It has an engine.py file and this must derive from the Engine Base class. Different engines then re-implement various aspect of this base class depending on their internal complexity. A summary of functionality include:

  • The base class exposes various init and destroy methods which are executed at various points in the startup process. These can be overridden to control startup and shutdown execution.
  • The engine provides a commands dictionary containing all the command objects registered by apps. This is typically accessed when menu entries are created.
  • Methods for displaying UI dialogs and windows can be overridden if the way the engine runs QT does not the default base class behavior.

The typical things an engine needs to handle are:

  • Menu management. At engine startup, once the apps have been loaded, the engine needs to create its Shotgun menu and add the various apps to this menu.
  • Logging methods are typically overridden to write to the application log.
  • UI methods are typically overridden to ensure seamless integration of Windows launched by Toolkit apps and the underlying host application window management setup. Engines are launched via the stgk.platform.start_engine() command. This command will read the configuration files, launch the engines, load all apps etc. The goal with the engine is that once it has launched, the it provides a consistent python/QT interface to the apps. Since all engines implement the same base class, apps can call methods on the engines to for example create UIs. It is up to each engine to implement these methods so that they work nicely inside the host application.
  • An interface to startup DCC applications that centralizes the business logic of discovering executable paths, setting a proper environment for launch, and initializing toolkit integration during the launch phase. This is described in detail in the Launching Software section.

Engine Events

Engines have the ability to emit events that can then be handled by Toolkit Apps. The design follows closely that of Qt’s events, where event handler methods can be implemented in a Toolkit App to execute custom behavior tied to specific event types.

Emitting Engine Events

It is an engine’s responsibility to monitor its host DCC application’s event or signalling frameworks to then emit its associated event. The example below is listening for a Qt signal from a host’s “frontend” handle and then emits a FileOpenEvent:

def pre_app_init(self):
    """
    Runs before apps are initialized.
    """
    frontend.file_opened.connect(self._handle_file_open)

def _handle_file_open(self, file_path):
    """
    Emits a file open event that apps can listen for.

    :param str file_path: The path of the file opened.
    """
    event = sgtk.platform.events.FileOpenEvent(file_path)
    self.log_debug("Emitting event %s..." % event)
    self._emit_event(event)

Handling Engine Events

Toolkit Apps can receive and handle an event in one of two ways:

  • Override the type specific event handler. The advantages of this approach to event handling is that there is no need to type check the event before handling it, and the slight performance benefit of only running custom logic when an event of the type you’re interested in is emitted. In the case of a file-open event, the Toolkit App’s Application.event_file_open() method would be reimplemented.
  • Override the generic event handler. Every engine event that is emitted, regardless of type, will be sent to the Toolkit App’s Application.event_engine(event)() method. The approach to handling an engine event in this manner would be to type check the given event object using isinstance() and run the appropriate logic according to the results.

In the example below, the Toolkit App has reimplemented the Application.event_file_open() method in order to execute custom logic when the parent Engine has indicated that a new file has been opened by the host DCC application:

def event_file_open(self, event):
    """
    Handles event notifications from the parent engine.

    :param event: The event object that was emitted.
    :type event: :class:`~sgtk.platform.events.FileOpenEvent`
    """
    self.engine.log_debug("Handling event: %s" % event)
    self.set_version_entity_by_file(file_path=event.file_path)

Engine

class sgtk.platform.Engine(tk, context, engine_instance_name, env)[source]

Base class for an engine. When a new DCC integration is created, it should derive from this class.

Engine instances are constructed by the toolkit launch process and various factory methods such as start_engine().

Parameters:
  • tkSgtk instance
  • context (Context) – A context object to define the context on disk where the engine is operating
  • engine_instance_name – The name of the engine as it has been defined in the environment.
  • env – An Environment object to associate with this engine.

Engine Customizations

The following methods can be used by subclasses to customize engine behavior.

_create_dialog(title, bundle, widget, parent)[source]

Create a TankQDialog with the specified widget embedded. This also connects to the dialogs dialog_closed event so that it can clean up when the dialog is closed.

Note

For more information, see the documentation for show_dialog().

Parameters:
  • title – The title of the window
  • bundle – The app, engine or framework object that is associated with this window
  • widget (PySide.QtGui.QWidget) – A QWidget instance to be embedded in the newly created dialog.
_create_dialog_with_widget(title, bundle, widget_class, *args, **kwargs)[source]

Convenience method to create an sgtk TankQDialog with a widget instantiated from widget_class embedded in the main section.

Note

For more information, see the documentation for show_dialog().

Parameters:
  • title – The title of the window
  • bundle – The app, engine or framework object that is associated with this window
  • widget_class (PySide.QtGui.QWidget) – The class of the UI to be constructed. This must derive from QWidget.

Additional parameters specified will be passed through to the widget_class constructor.

_create_widget(widget_class, *args, **kwargs)[source]

Create an instance of the specified widget_class. This wraps the widget_class so that the TankQDialog it is embedded in can connect to it more easily in order to handle the close event.

When overriding in a derived engine, be sure to call the base implementations of _create_widget() and _create_dialog() to ensure that all dialogs and widgets are tracked efficiently and safely.

Note

For more information, see the documentation for show_dialog().

Parameters:widget_class (PySide.QtGui.QWidget) – The class of the UI to be constructed. This must derive from QWidget.

Additional parameters specified will be passed through to the widget_class constructor.

_define_qt_base()[source]

This will be called at initialisation time and will allow a user to control various aspects of how QT is being used by Tank. The method should return a dictionary with a number of specific keys, outlined below.

  • qt_core - the QtCore module to use
  • qt_gui - the QtGui module to use
  • wrapper - the Qt wrapper root module, e.g. PySide
  • dialog_base - base class for to use for Tank’s dialog factory
Returns:dict
_emit_event(event)[source]

Called by the engine whenever an event is to be emitted to child apps of this engine.

Note

Events will be emitted and child apps notified immediately.

Warning

Some event types might be triggered quite frequently. Apps that react to events should do so in a way that is aware of the potential performance impact of their actions.

Parameters:event (EngineEvent) – The event object that will be emitted.
_emit_log_message(handler, record)[source]

Called by the engine whenever a new log message is available. All log messages from the toolkit logging namespace will be passed to this method.

Note

To implement logging in your engine implementation, subclass this method and display the record in a suitable way - typically this means sending it to a built-in DCC console. In addition to this, ensure that your engine implementation does not subclass the (old) Engine.log_debug(), Engine.log_info() family of logging methods.

For a consistent output, use the formatter that is associated with the log handler that is passed in. A basic implementation of this method could look like this:

# call out to handler to format message in a standard way
msg_str = handler.format(record)

# display message
print msg_str

Warning

This method may be executing called from worker threads. In DCC environments, where it is important that the console/logging output always happens in the main thread, it is recommended that you use the async_execute_in_main_thread() to ensure that your logging code is writing to the DCC console in the main thread.

Parameters:
  • handler (LogHandler) – Log handler that this message was dispatched from
  • record (LogRecord) – Std python logging record
_ensure_core_fonts_loaded()[source]

Loads the Shotgun approved fonts that are bundled with tk-core.

This method ensures that the Shotgun approved fonts bundled with core are loaded into Qt’s font database. This allows them to be used by apps for a consistent look and feel.

If a QApplication exists during engine initialization, it is not necessary to call this method. Similarly, subclasses that make use of core’s bundled dark look and feel will have the bundled fonts loaded automatically.

This method can/should be called by subclasses that meet the following criteria:

  • Create their own QApplication instance after engine init
  • Do not use the bundled dark look and feel.
  • Have overridden Engine._create_dialog().
_get_dialog_parent()[source]

Get the QWidget parent for all dialogs created through show_dialog() show_modal().

Can be overriden in derived classes to return the QWidget to be used as the parent for all TankQDialog’s.

Returns:QT Parent window (PySide.QtGui.QWidget)
_initialize_dark_look_and_feel()[source]

Initializes a standard toolkit look and feel using a combination of QPalette and stylesheets.

If your engine is running inside an environment which already has a dark style defined, do not call this method. The Toolkit apps are designed to work well with most dark themes.

However, if you are for example creating your own QApplication instance you can execute this method to put the session into Toolkit’s standard dark mode.

This will initialize the plastique style (for Qt4) or the fusion style (for Qt5), and set it up with a standard dark palette and supporting stylesheet.

Qt4 setStyle documentation Qt5 setStyle documentation

Apps and UIs can then extend this further by using further css.

Due to restrictions in QT, this needs to run after a QApplication object has been instantiated.

_on_dialog_closed(dlg)[source]

Called when a dialog created by this engine is closed.

Parameters:dlg (PySide.QtGui.QWidget) – The dialog being closed

Derived implementations of this method should be sure to call the base implementation

Instance Methods & Properties

logger

Standard python logger for this engine, app or framework.

Use this whenever you want to emit or process log messages. If you are developing an app, engine or framework, call this method for generic logging.

Note

Inside the python area of your app, engine or framework, we recommend that you use sgtk.platform.get_logger() for your logging.

Logging will be dispatched to a logger parented under the main toolkit logging namespace:

# pattern
sgtk.env.environment_name.engine_instance_name

# for example
sgtk.env.asset.tk-maya

Note

If you want all log messages that you are emitting in your app, engine or framework to be written to a log file or to a logging console, you can attach a std log handler here.

get_metrics_properties()[source]

Returns a dictionary with properties to use when emitting a metric event for this engine.

The dictionary contains information about this engine: its name and version, and informations about the application hosting the engine: its name and version:

{
    'Host App': 'Maya',
    'Host App Version': '2017',
    'Engine': 'tk-maya',
    'Engine Version': 'v0.4.1',
}
Returns:A dictionary with metrics properties as per above.
shotgun

Returns a Shotgun API handle associated with the currently running environment. This method is a convenience method that calls out to shotgun().

Returns:Shotgun API handle
environment

A dictionary with information about the environment.

Returns:dictionary with keys name, description and disk_location.
instance_name

The instance name for this engine. The instance name is the entry that is defined in the environment file.

Returns:instance name as string, e.g. tk-maya
apps

Dictionary of apps associated with this engine

Returns:dictionary with keys being app name and values being app objects
commands

A dictionary representing all the commands that have been registered by apps in this engine via register_command(). Each dictionary item contains the following keys:

  • callback - function pointer to function to execute for this command
  • properties - dictionary with free form options - these are typically engine specific and driven by convention.
Returns:commands dictionary, keyed by command name
panels

Panels which have been registered with the engine via the register_panel() method. Returns a dictionary keyed by panel unique ids. Each value is a dictionary with keys callback and properties.

Returns all the panels which have been registered with the engine.

Returns:A dictionary keyed by panel unique ids. Each value is a dictionary with keys ‘callback’ and ‘properties’
has_ui

Indicates that the host application that the engine is connected to has a UI enabled. This always returns False for some engines (such as the shell engine) and may vary for some engines, depending if the host application for example is in batch mode or UI mode.

Returns:boolean value indicating if a UI currently exists
has_qt5

Indicates that the host application has access to Qt 5 and that the sgtk.platform.qt5 module has been populated with the Qt 5 modules and information.

Returns bool:boolean value indicating if Qt 5 is available.
has_qt4

Indicates that the host application has access to Qt 4 and that the sgtk.platform.qt module has been populated with the Qt 4 modules and information.

Returns bool:boolean value indicating if Qt 4 is available.
metrics_dispatch_allowed

Indicates this engine will allow the metrics worker threads to forward the user metrics logged via core, this engine, or registered apps to SG.

Returns:boolean value indicating that the engine allows user metrics to be forwarded to SG.
created_qt_dialogs

A list of dialog objects that have been created by the engine.

Returns:A list of TankQDialog objects.
host_info

Returns information about the application hosting this engine.

This should be re-implemented in deriving classes to handle the logic specific to the application the engine is designed for.

A dictionary with at least a “name” and a “version” key should be returned by derived implementations, with respectively the host application name and its release string as values, e.g. { "name": "Maya", "version": "2017.3"}.

Returns:A {"name": "unknown", "version" : "unknown"} dictionary.
register_toggle_debug_command

Indicates whether the engine should have a toggle debug logging command registered during engine initialization.

Return type:bool
pre_app_init()[source]

Sets up the engine into an operational state. Executed by the system and typically implemented by deriving classes. This method called before any apps are loaded.

post_app_init()[source]

Executed by the system and typically implemented by deriving classes. This method called after all apps have been loaded.

destroy()[source]

Destroy all apps, then call destroy_engine so subclasses can add their own tear down code.

Note

This method should not be subclassed. Instead, implement destroy_engine().

destroy_engine()[source]

Called when the engine should tear down itself and all its apps. Implemented by deriving classes.

change_context(new_context)[source]

Called when the engine is being asked to change contexts. This will only be allowed if the engine explicitly suppose on-the-fly context changes by way of its context_change_allowed property. Any apps that do not support context changing will be restarted instead. Custom behavior at the engine level should be handled by overriding one or both of pre_context_change and post_context_change methods.

Parameters:new_context (Context) – The context to change to.
show_busy(title, details)[source]

Displays or updates a global “busy window” tied to this engine. The window is a splash screen type window, floats on top and contains details of what is currently being processed.

This method pops up a splash screen with a message and the idea is that long running core processes can use this as a way to communicate their intent to the user and keep the user informed as slow processes are executed. If the engine has a UI present, this will be used to display the progress message. If the engine does not have UI support, a message will be logged. The UI always appears in the main thread for safety.

Only one global progress window can exist per engine at a time, so if you want to push several updates one after the other, just keep calling this method.

When you want to remove the window, call clear_busy().

Note! If you are calling this from the Core API you typically don’t have access to the current engine object. In this case you can use the convenience method tank.platform.engine.show_global_busy() which will attempt to broadcast the request to the currently active engine.

Params title:Short descriptive title of what is happening
Params details:Detailed message describing what is going on.
clear_busy()[source]

Closes any active busy window.

For more details, see the show_busy() documentation.

register_command(name, callback, properties=None)[source]

Register a command with a name and a callback function.

A command refers to an access point for some functionality. In most cases, commands will appear as items on a Shotgun dropdown menu, but it ultimately depends on the engine - in the Shell engine, commands are instead represented as a text base listing and in the Shotgun Desktop it is a scrollable list of larger icons.

Note

This method is used to add menu entries for launching toolkit UIs. If you wish to register a panel UI with toolkit, you need call this method in order to register a menu command with which a user can launch the panel. In addition to this, you also need to call register_panel() in order to register the panel so that the engine can handle its management and persistence.

An arbitrary list of properties can be passed into the engine in the form of a properties dictionary. The interpretation of the properties dictionary is engine specific, but in general the following properties are supported:

  • short_name - A shorter name, typically intended for console use (e.g. ‘import_cut’)

  • icon - A path to a 256x256 png app icon. If not specified, the icon for the app will be used.

  • description - a one line description of the command, suitable for a tooltip. If no description is passed, the one provided in the app manifest will be used.

  • title - Title to appear on shotgun action menu (e.g. “Create Folders”)

  • type - The type of command - hinting at which menu the command should appear. Options vary between engines and the following are supported:

    • context_menu - Supported on all engines. Places an item on the context menu (first item on the shotgun menu). The context menu is a suitable location for utility items, helpers and tools.
    • panel - Some DCCs have a special menu which is accessible only when right clicking on a panel. Passing panel as the command type hints to the system that the command should be added to this menu. If no panel menu is available, it will be added to the main menu. Nuke is an example of a DCC which supports this behavior.
    • node - Node based applications such as Nuke typically have a separate menu system for accessing nodes. If you want your registered command to appear on this menu, use this type.

Grouping commands into collections

It is possible to group several commands into a collection. Such a collection is called a group. For example, you may have three separate commands to launch Maya 2017, Maya 2016 and Maya 2015, all under a ‘Launch Maya’ group. It is up to each engine to implement this specification in a suitable way but typically, it would be displayed as a “Launch Maya” menu with three sub menu items to represent each version of Maya.

Each group has a concept of a group default - this is what would get executed if you click on the ‘Launch Maya’ group.

To register commands with groups, pass the following two parameters in the properties dictionary:

  • group - The name for a group this command should be considered a member of.
  • group_default - Boolean value indicating whether this command should represent the group as a whole.

Note

It is up to each engine to implement grouping and group defaults in an appropriate way. Some engines may not support grouping.

The following properties are supported for the Shotgun engine specifically:

  • deny_permissions - List of permission groups to exclude this menu item for (e.g. ["Artist"])
  • deny_platforms - List of platforms for which not to show the menu (e.g. ["windows", "mac", "linux"]). Please note that there are other ways to achieve this same result.
  • supports_multiple_selection - a special flag that allows multiple objects in Shotgun to be selected and operated on. An example showing how to write a multi select shotgun app is provided in a special branch in the sample starter app: https://github.com/shotgunsoftware/tk-multi-starterapp/tree/shotgun_multi_select
  • Please note that custom icons are not supported by the Shotgun engine.

Typical usage normally looks something like this - register_command is called from the Application.init_app() method of an app:

self.engine.register_command(
    "Work Area Info...",
    callback,
    {"type": "context_menu", "short_name": "work_area_info"}
)
Parameters:
  • name – Name of the command. This will be the key when accessed via the commands() dictionary.
  • callback – Callback to call upon command execution
  • properties – Dictionary with command properties.
register_panel(callback, panel_name='main', properties=None)[source]

Similar to register_command(), but instead of registering a menu item in the form of a command, this method registers a UI panel. A register_panel call should be used in conjunction with a register_command call.

Panels need to be registered if they should persist between DCC sessions (e.g. for example ‘saved layouts’).

Just like with the register_command() method, panel registration should be executed from within the init phase of the app. Once a panel has been registered, it is possible for the engine to correctly restore panel UIs at startup and profile switches.

Not all engines support this feature, but in for example Nuke, a panel can be added to a saved layout. Apps wanting to be able to take advantage of the persistence given by these saved layouts will need to call register_panel as part of their init_app phase.

In order to show or focus on a panel, use the show_panel() method instead.

Parameters:
  • callback – Callback to a factory method that creates the panel and returns a panel widget.
  • panel_name – A string to distinguish this panel from other panels created by the app. This will be used as part of the unique id for the panel.
  • properties – Properties dictionary. Reserved for future use.
Returns:

A unique identifier that can be used to consistently identify the panel across sessions. This identifier should be used to identify the panel in all subsequent calls, e.g. for example show_panel().

execute_in_main_thread(func, *args, **kwargs)[source]

Execute the specified function in the main thread when called from a non-main thread. This will block the calling thread until the function returns. Note that this method can introduce a deadlock if the main thread is waiting for a background thread and the background thread is invoking this method. Since the main thread is waiting for the background thread to finish, Qt’s event loop won’t be able to process the request to execute in the main thread:

>>> from sgtk.platform.qt import QtGui
>>> engine.execute_in_main_thread(QtGui.QMessageBox.information, None, "Hello", "Hello from the main thread!")

Note

This currently only works if Qt is available, otherwise it just executes immediately on the current thread.

Parameters:
  • func – function to call
  • args – arguments to pass to the function
  • kwargs – named arguments to pass to the function
Returns:

the result of the function call

async_execute_in_main_thread(func, *args, **kwargs)[source]

Execute the specified function in the main thread when called from a non-main thread. This call will return immediately and will not wait for the code to be executed in the main thread.

Note

This currently only works if Qt is available, otherwise it just executes immediately on the current thread.

Parameters:
  • func – function to call
  • args – arguments to pass to the function
  • kwargs – named arguments to pass to the function
get_matching_commands(command_selectors)[source]

Finds all the commands that match the given selectors.

Command selector structures are typically found in engine configurations and are typically defined on the following form in yaml:

menu_favourites:
- {app_instance: tk-multi-workfiles, name: Shotgun File Manager...}
- {app_instance: tk-multi-snapshot,  name: Snapshot...}
- {app_instance: tk-multi-workfiles, name: Shotgun Save As...}
- {app_instance: tk-multi-publish,   name: Publish...}

Note that selectors that do not match a command will output a warning.

Parameters:command_selectors

A list of command selectors, with each selector having the following structure:

{
  name: command-name,
  app_instance: instance-name
}

An empty name (“”) will select all the commands of the given instance-name.

Returns:A list of tuples for all commands that match the selectors. Each tuple has the format:
(instance-name, command-name, callback)
log_debug(msg)[source]

Logs a debug message.

Deprecated since version 0.18: Use Engine.logger() instead.

Note

Toolkit will probe for this method and use it to determine if the current engine supports the new Engine.logger() based logging or not. If you are developing an engine and want to upgrade it to use the new logging capabilities, you should remove the implementation of log_debug|error|info|...() methods and instead sublcass Engine._emit_log_message().

Parameters:msg – Message to log.
log_info(msg)[source]

Logs an info message.

Deprecated since version 0.18: Use Engine.logger() instead.

Parameters:msg – Message to log.
log_warning(msg)[source]

Logs an warning message.

Deprecated since version 0.18: Use Engine.logger() instead.

Parameters:msg – Message to log.
log_error(msg)[source]

Logs an error message.

Deprecated since version 0.18: Use Engine.logger() instead.

Parameters:msg – Message to log.
log_exception(msg)[source]

Logs an exception message.

Deprecated since version 0.18: Use Engine.logger() instead.

Parameters:msg – Message to log.
get_debug_tracked_qt_widgets()[source]

Returns a dictionary of debug info about created Qt dialogs and widgets.

The keys of the dictionary are the string representation of a widget and the corresponding value is a reference to that widget.

show_dialog(title, bundle, widget_class, *args, **kwargs)[source]

Shows a non-modal dialog window in a way suitable for this engine. The engine will attempt to parent the dialog nicely to the host application. The dialog will be created with a standard Toolkit window title bar where the title will be displayed.

Note

In some cases, it is necessary to hide the standard Toolkit title bar. You can do this by adding a property to the widget class you are displaying:

@property
def hide_tk_title_bar(self):
    "Tell the system to not show the standard toolkit toolbar"
    return True

Notes for engine developers

Qt dialog & widget management can be quite tricky in different engines/applications. Because of this, Sgtk provides a few overridable methods with the idea being that when developing a new engine, you only need to override the minimum amount necessary.

Making use of these methods in the correct way allows the base Engine class to manage the lifetime of the dialogs and widgets efficiently and safely without you having to worry about it.

The methods available are listed here in the hierarchy in which they are called:

show_dialog()/show_modal()
    _create_dialog_with_widget()
        _get_dialog_parent()
        _create_widget()
        _create_dialog()

For example, if you just need to make sure that all dialogs use a specific parent widget then you only need to override _get_dialog_parent() (e.g. the tk-maya engine). However, if you need to implement a two-stage creation then you may need to re-implement show_dialog() and show_modal() to call _create_widget() and _create_dialog() directly rather than using the helper method _create_dialog_with_widget() (e.g. the tk-3dsmax engine). Finally, if the application you are writing an engine for is Qt based then you may not need to override any of these methods (e.g. the tk-nuke engine).

Parameters:
  • title – The title of the window. This will appear in the Toolkit title bar.
  • bundle – The app, engine or framework object that is associated with this window
  • widget_class (PySide.QtGui.QWidget) – The class of the UI to be constructed. This must derive from QWidget.

Additional parameters specified will be passed through to the widget_class constructor.

Returns:the created widget_class instance
show_modal(title, bundle, widget_class, *args, **kwargs)[source]

Shows a modal dialog window in a way suitable for this engine. The engine will attempt to integrate it as seamlessly as possible into the host application. This call is blocking until the user closes the dialog. The dialog will be created with a standard Toolkit window title bar where the title will be displayed.

Note

In some cases, it is necessary to hide the standard Toolkit title bar. You can do this by adding a property to the widget class you are displaying:

@property
def hide_tk_title_bar(self):
    "Tell the system to not show the standard toolkit toolbar"
    return True
Parameters:
  • title – The title of the window
  • bundle – The app, engine or framework object that is associated with this window
  • widget_class (PySide.QtGui.QWidget) – The class of the UI to be constructed. This must derive from QWidget.

Additional parameters specified will be passed through to the widget_class constructor.

Returns:(a standard QT dialog status return code, the created widget_class instance)
show_panel(panel_id, title, bundle, widget_class, *args, **kwargs)[source]

Shows a panel in a way suitable for this engine. Engines should attempt to integrate panel support as seamlessly as possible into the host application. Some engines have extensive panel support and workflows, others have none at all.

If the engine does not specifically implement panel support, the window will be shown as a modeless dialog instead and the call is equivalent to calling show_dialog().

The dialog will be created with a standard Toolkit window title bar where the title will be displayed.

Note

In some cases, it is necessary to hide the standard Toolkit title bar. You can do this by adding a property to the widget class you are displaying:

@property
def hide_tk_title_bar(self):
    "Tell the system to not show the standard toolkit toolbar"
    return True
Parameters:
  • panel_id – Unique identifier for the panel, as obtained by register_panel().
  • title – The title of the panel
  • bundle – The app, engine or framework object that is associated with this window
  • widget_class (PySide.QtGui.QWidget) – The class of the UI to be constructed. This must derive from QWidget.

Additional parameters specified will be passed through to the widget_class constructor.

Returns:the created widget_class instance
cache_location

An item-specific location on disk where the app or engine can store random cache data. This location is guaranteed to exist on disk.

This location is configurable via the cache_location hook. It typically points at a path in the local filesystem, e.g on a mac:

~/Library/Caches/Shotgun/SITENAME/PROJECT_ID/BUNDLE_NAME

This can be used to store cache data that the app wants to reuse across sessions:

stored_query_data_path = os.path.join(self.cache_location, "query.dat")
context

The context associated with this item.

Returns:Context
context_change_allowed

Whether a context change is allowed without the need for a restart. If a bundle supports on-the-fly context changing, this property should be overridden in the deriving class and forced to return True.

Returns:bool
create_hook_instance(hook_expression, base_class=None)

Returns the instance of a hook object given an expression.

This is useful for complex workflows where it is beneficial to maintain a handle to a hook instance. Normally, hooks are stateless and every time a hook is called, a new instance is returned. This method provides a standardized way to retrieve an instance of a hook:

self._plugin = app_object.create_hook_instance("{config}/path/to/my_hook.py")
self._plugin.execute_method_x()
self._plugin.execute_method_y()
self._plugin.execute_method_z()

The hook expression is the raw value that is specified in the configuration file. If you want to access a configuration setting instead (like how for example execute_hook_method() works), simply call get_setting() to retrieve the value and then pass the settings value to this method.

Note

For more information about hook syntax, see Hook

An optional base_class can be provided to override the default Hook base class. This is useful for bundles that create hook instances at execution time and wish to provide default implementation without the need to configure the base hook. The supplied class must inherit from Hook.

Parameters:
  • hook_expression – Path to hook to execute. See above for syntax details.
  • base_class – A python class to use as the base class for the created hook. This will override the default hook base class, Hook.
Returns:

Hook instance.

description

A short description of the item

Returns:string
disk_location

The folder on disk where this item is located. This can be useful if you want to write app code to retrieve a local resource:

app_font = os.path.join(self.disk_location, "resources", "font.fnt")
display_name

The display name for the item (e.g. Maya Engine)

Returns:display name as string
documentation_url

Return the relevant documentation url for this item.

Returns:url string, None if no documentation was found
ensure_folder_exists(path)

Make sure that the given folder exists on disk. Convenience method to make it easy for apps and engines to create folders in a standardized fashion. While the creation of high level folder structure such as Shot and Asset folders is typically handled by the folder creation system in Toolkit, Apps tend to need to create leaf-level folders such as publish folders and work areas. These are often created just in time of the operation.

Note

This method calls out to the ensure_folder_exists core hook, making the I/O operation user configurable. We recommend using this method over the methods provided in sgtk.util.filesystem.

Parameters:path – path to create
execute_hook(key, base_class=None, **kwargs)

Execute a hook that is part of the environment configuration for the current bundle.

Convenience method that calls execute_hook_method() with the method_name parameter set to “execute”.

Warning

This method is present for backwards compatibility. For all new hooks, we recommend using execute_hook_method() instead.

You simply pass the name of the hook setting that you want to execute and the accompanying arguments, and toolkit will find the correct hook file based on the currently configured setting and then execute the execute() method for that hook.

An optional base_class can be provided to override the default Hook base class. This is useful for bundles that want to define and document a strict interface for hooks. The classes defined in the hook have to derived from this classes.

Note

For more information about hooks, see Hook

Parameters:
  • key – The name of the hook setting you want to execute.
  • base_class – A python class to use as the base class for the created hook. This will override the default hook base class, Hook.
Returns:

The return value from the hook

execute_hook_by_name(hook_name, **kwargs)

Execute an arbitrary hook located in the hooks folder for this project. The hook_name is the name of the python file in which the hook resides, without the file extension.

In most use cases, the execute_hook method is the preferred way to access a hook from an app.

Warning

Now deprecated - Please use execute_hook_expression() instead.

This method is typically only used when you want to execute an arbitrary list of hooks, for example if you want to run a series of arbitrary user defined pre-publish validation hooks.

Note

For more information about hooks, see Hook

Parameters:hook_name – name of the legacy hook file to execute.
execute_hook_expression(hook_expression, method_name, base_class=None, **kwargs)

Execute an arbitrary hook via an expression. While the methods execute_hook and execute_hook_method allows you to execute a particular hook setting as specified in the app configuration manifest, this methods allows you to execute a hook directly by passing a hook expression, for example {config}/path/to/my_hook.py

This is useful if you are doing rapid app development and don’t necessarily want to expose a hook as a configuration setting just yet. It is also useful if you have app settings that are nested deep inside of lists or dictionaries. In that case, you cannot use execute_hook, but instead will have to retrieve the value specifically and then run it.

An optional base_class can be provided to override the default Hook base class. This is useful for bundles that want to define and document a strict interface for hooks. The classes defined in the hook have to derived from this classes.

Note

For more information about hooks, see Hook

Parameters:
  • hook_expression – Path to hook to execute. See above for syntax details.
  • method_name – Method inside the hook to execute.
  • base_class – A python class to use as the base class for the created hook. This will override the default hook base class, Hook.
Returns:

The return value from the hook

execute_hook_method(key, method_name, base_class=None, **kwargs)

Execute a specific method in a hook that is part of the environment configuration for the current bundle.

You simply pass the name of the hook setting that you want to execute, the name of the method you want to execute and the accompanying arguments. Toolkit will find the correct hook file based on the currently configured setting and then execute the specified method.

Hooks form a flexible way to extend and make toolkit apps or engines configurable. A hook acts like a setting in that it needs to be configured as part of the app’s configuration, but instead of being a simple value, it is a code snippet contained inside a class.

Apps typically provide default hooks to make installation and overriding easy. Each hook is represented by a setting, similar to the ones you access via the get_setting() method, however instead of retrieving a fixed value, you execute code which generates a value.

This method will execute a specific method for a given hook setting. Toolkit will find the actual python hook file and handle initialization and execution for you, by looking at the configuration settings and resolve a path based on this.

Arguments should always be passed in by name. This is to make it easy to add new parameters without breaking backwards compatibility, for example execute_hook_method("validator", "pre_check", name=curr_scene, version=curr_ver).

An optional base_class can be provided to override the default Hook base class. This is useful for bundles that want to define and document a strict interface for hooks. The classes defined in the hook have to derived from this classes.

Note

For more information about hooks, see Hook

Parameters:
  • key – The name of the hook setting you want to execute.
  • method_name – Name of the method to execute
  • base_class – A python class to use as the base class for the created hook. This will override the default hook base class, Hook.
Returns:

The return value from the hook

frameworks

List of all frameworks associated with this item

Returns:List of framework objects
get_project_cache_location(project_id)

Gets the bundle’s cache-location path for the given project id.

Parameters:project_id (int) – The project Entity id number.
Returns:Cache location directory path.
Rtype str:
get_setting(key, default=None)

Get a value from the item’s settings:

>>> app.get_setting('entity_types')
['Sequence', 'Shot', 'Asset', 'Task']
Parameters:
  • key – config name
  • default – default value to return
Returns:

Value from the environment configuration

get_template(key)

Returns a template object for a particular template setting in the Framework configuration. This method will look at the app configuration, determine which template is being referred to in the setting, go into the main platform Template API and fetch that particular template object.

This is a convenience method. Shorthand for self.sgtk.templates[ self.get_setting(key) ].

Parameters:key – Setting to retrieve template for
Returns:Template object
get_template_by_name(template_name)

Note: This is for advanced use cases - Most of the time you should probably use get_template(). Find a particular template, the way it is named in the master config file templates.yml. This method will access the master templates file directly and pull out a specifically named template without using the app config. Note that using this method may result in code which is less portable across studios, since it makes assumptions about how templates are named and defined in the master config. Generally speaking, it is often better to access templates using the app configuration and the get_template() method.

This is a convenience method. Shorthand for self.sgtk.templates[template_name].

:param template_name :returns: Template object

icon_256

Path to a 256x256 pixel png file which describes the item

import_module(module_name)

Special import command for Toolkit bundles. Imports the python folder inside an app and returns the specified module name that exists inside the python folder.

Each Toolkit App or Engine can have a python folder which contains additional code. In order to ensure that Toolkit can run multiple versions of the same app, as well as being able to reload app code if it changes, it is recommended that this method is used whenever you want to access code in the python location.

For example, imagine you had the following structure:

tk-multi-mybundle
   |- app.py or engine.py or framework.py
   |- info.yml
   \- python
       |- __init__.py   <--- Needs to contain 'from . import tk_multi_mybundle'
       \- tk_multi_mybundle

The above structure is a standard Toolkit app outline. app.py is a light weight wrapper and the python module tk_multi_myapp module contains the actual code payload. In order to import this in a Toolkit friendly way, you need to run the following when you want to load the payload module inside of app.py:

module_obj = self.import_module("tk_multi_myapp")
name

The short name for the item (e.g. tk-maya)

Returns:name as string
post_context_change(old_context, new_context)

Called after a context change.

Implemented by deriving classes.

Parameters:
  • old_context (Context) – The context being changed away from.
  • new_context (Context) – The context being changed to.
pre_context_change(old_context, new_context)

Called before a context change.

Implemented by deriving classes.

Parameters:
  • old_context (Context) – The context being changed away from.
  • new_context (Context) – The context being changed to.
sgtk

Returns the Toolkit API instance associated with this item

Returns:Tank
site_cache_location

A site location on disk where the app or engine can store random cache data. This location is guaranteed to exist on disk.

This location is configurable via the cache_location hook. It typically points at a path in the local filesystem, e.g on a mac:

~/Library/Caches/Shotgun/SITENAME/BUNDLE_NAME

This can be used to store cache data that the app wants to reuse across sessions and can be shared across a site:

stored_query_data_path = os.path.join(self.site_cache_location, "query.dat")
style_constants

Returns a dictionary of style constants. These can be used to build UIs using standard colors and other style components. All keys returned in this dictionary can also be used inside a style.qss that lives at the root level of the app, engine or framework. Use a {{DOUBLE_BACKET}} syntax in the stylesheet file, for example:

QWidget
{ 
    color: {{SG_FOREGROUND_COLOR}};
}

This property returns the values for all constants, for example:

{ 
  "SG_HIGHLIGHT_COLOR": "#18A7E3",
  "SG_ALERT_COLOR": "#FC6246",
  "SG_FOREGROUND_COLOR": "#C8C8C8"
}
Returns:Dictionary. See above for example
support_url

Return the relevant support url for this item.

Returns:url string, None if no documentation was found
tank

Returns the Toolkit API instance associated with this item

Returns:Tank
version

The version of the item (e.g. ‘v0.2.3’)

Returns:string representing the version

Applications

Toolkit Apps are tools that can execute in multiple DCC environments.

Note

For an introduction to App development, see https://support.shotgunsoftware.com/entries/95440137

A good way to get started with App development is to clone our starter github repository https://github.com/shotgunsoftware/tk-multi-starterapp. Please note that there are different branches demonstrating different types of apps with a varying degree of complexity.

Application

class sgtk.platform.Application(engine, descriptor, settings, instance_name, env)[source]

Base class for all Applications (Apps) running in Toolkit.

Application instances are constructed by the toolkit launch process and various factory methods such as start_engine().

Parameters:
  • engine – The engine instance to connect this app to
  • app_name – The short name of this app (e.g. tk-nukepublish)
  • settings – a settings dictionary for this app
logger

Standard python logger for this engine, app or framework.

Use this whenever you want to emit or process log messages. If you are developing an app, engine or framework, call this method for generic logging.

Note

Inside the python area of your app, engine or framework, we recommend that you use sgtk.platform.get_logger() for your logging.

Logging will be dispatched to a logger parented under the main toolkit logging namespace:

# pattern
sgtk.env.environment_name.engine_instance_name

# for example
sgtk.env.asset.tk-maya

Note

If you want all log messages that you are emitting in your app, engine or framework to be written to a log file or to a logging console, you can attach a std log handler here.

shotgun

Returns a Shotgun API handle associated with the currently running environment. This method is a convenience method that calls out to shotgun().

Returns:Shotgun API handle
instance_name

The name for this app instance.

engine

The engine that this app is connected to.

get_metrics_properties()[source]

Returns a dictionary with properties to use when emitting a metric event for this application in the current engine.

The dictionary contains information about this application, about the current engine, and about the application hosting the engine. For each of them, a name and a version string are available:

{
    'Host App': 'Maya',
    'Host App Version': '2017',
    'Engine': 'tk-maya',
    'Engine Version': 'v0.4.1',
    'App': 'tk-multi-about',
    'App Version': '1.2.3'
}
Returns:Dictionary with info per above.
init_app()[source]

Implemented by deriving classes in order to initialize the app Called by the engine as it loads the app.

post_engine_init()[source]

Implemented by deriving classes in order to run code after the engine has completely finished initializing itself and all its apps. At this point, the engine has a fully populated apps dictionary and all loaded apps have been fully initialized and validated.

destroy_app()[source]

Implemented by deriving classes in order to tear down the app Called by the engine as it is being destroyed.

event_engine(event)[source]

Called when the parent engine emits an event. This method is intended to be overridden by deriving classes in order to implement event-specific behavior.

Note

This method is called for all engine event types. If overriding this method to implement an event handler in a specific app, the event object received will need to be checked via isinstance (or via its event_type property) to know what event has been triggered. As there are also type specific event handlers available, it is considered best practice to use those in all cases except those where a generic handler is absolutely required.

Warning

It is possible that events will be triggered quite frequently. It is important to keep performance in mind when writing an event handler.

Parameters:event (EngineEvent) – The event object that was emitted.
event_file_open(event)[source]

Called when the parent engine emits a file-open event. This method is intended to be overridden by deriving classes.

Warning

It is possible that events will be triggered quite frequently. It is important to keep performance in mind when writing an event handler.

Parameters:event (FileOpenEvent) – The event object that was emitted.
event_file_close(event)[source]

Called when the parent engine emits a file-close event. This method is intended to be overridden by deriving classes.

Warning

It is possible that events will be triggered quite frequently. It is important to keep performance in mind when writing an event handler.

Parameters:event (FileCloseEvent) – The event object that was emitted.
log_debug(msg)[source]

Logs a debug message.

Deprecated since version 0.18: Use Engine.logger() instead.

Parameters:msg – Message to log.
log_info(msg)[source]

Logs an info message.

Deprecated since version 0.18: Use Engine.logger() instead.

Parameters:msg – Message to log.
log_warning(msg)[source]

Logs an warning message.

Deprecated since version 0.18: Use Engine.logger() instead.

Parameters:msg – Message to log.
log_error(msg)[source]

Logs an error message.

Deprecated since version 0.18: Use Engine.logger() instead.

Parameters:msg – Message to log.
log_exception(msg)[source]

Logs an exception message.

Deprecated since version 0.18: Use Engine.logger() instead.

Parameters:msg – Message to log.
cache_location

An item-specific location on disk where the app or engine can store random cache data. This location is guaranteed to exist on disk.

This location is configurable via the cache_location hook. It typically points at a path in the local filesystem, e.g on a mac:

~/Library/Caches/Shotgun/SITENAME/PROJECT_ID/BUNDLE_NAME

This can be used to store cache data that the app wants to reuse across sessions:

stored_query_data_path = os.path.join(self.cache_location, "query.dat")
change_context(new_context)

Abstract method for context changing.

Implemented by deriving classes that wish to support context changes and require specific logic to do so safely.

Parameters:new_context – The context being changed to.
context

The context associated with this item.

Returns:Context
context_change_allowed

Whether a context change is allowed without the need for a restart. If a bundle supports on-the-fly context changing, this property should be overridden in the deriving class and forced to return True.

Returns:bool
create_hook_instance(hook_expression, base_class=None)

Returns the instance of a hook object given an expression.

This is useful for complex workflows where it is beneficial to maintain a handle to a hook instance. Normally, hooks are stateless and every time a hook is called, a new instance is returned. This method provides a standardized way to retrieve an instance of a hook:

self._plugin = app_object.create_hook_instance("{config}/path/to/my_hook.py")
self._plugin.execute_method_x()
self._plugin.execute_method_y()
self._plugin.execute_method_z()

The hook expression is the raw value that is specified in the configuration file. If you want to access a configuration setting instead (like how for example execute_hook_method() works), simply call get_setting() to retrieve the value and then pass the settings value to this method.

Note

For more information about hook syntax, see Hook

An optional base_class can be provided to override the default Hook base class. This is useful for bundles that create hook instances at execution time and wish to provide default implementation without the need to configure the base hook. The supplied class must inherit from Hook.

Parameters:
  • hook_expression – Path to hook to execute. See above for syntax details.
  • base_class – A python class to use as the base class for the created hook. This will override the default hook base class, Hook.
Returns:

Hook instance.

description

A short description of the item

Returns:string
disk_location

The folder on disk where this item is located. This can be useful if you want to write app code to retrieve a local resource:

app_font = os.path.join(self.disk_location, "resources", "font.fnt")
display_name

The display name for the item (e.g. Maya Engine)

Returns:display name as string
documentation_url

Return the relevant documentation url for this item.

Returns:url string, None if no documentation was found
ensure_folder_exists(path)

Make sure that the given folder exists on disk. Convenience method to make it easy for apps and engines to create folders in a standardized fashion. While the creation of high level folder structure such as Shot and Asset folders is typically handled by the folder creation system in Toolkit, Apps tend to need to create leaf-level folders such as publish folders and work areas. These are often created just in time of the operation.

Note

This method calls out to the ensure_folder_exists core hook, making the I/O operation user configurable. We recommend using this method over the methods provided in sgtk.util.filesystem.

Parameters:path – path to create
execute_hook(key, base_class=None, **kwargs)

Execute a hook that is part of the environment configuration for the current bundle.

Convenience method that calls execute_hook_method() with the method_name parameter set to “execute”.

Warning

This method is present for backwards compatibility. For all new hooks, we recommend using execute_hook_method() instead.

You simply pass the name of the hook setting that you want to execute and the accompanying arguments, and toolkit will find the correct hook file based on the currently configured setting and then execute the execute() method for that hook.

An optional base_class can be provided to override the default Hook base class. This is useful for bundles that want to define and document a strict interface for hooks. The classes defined in the hook have to derived from this classes.

Note

For more information about hooks, see Hook

Parameters:
  • key – The name of the hook setting you want to execute.
  • base_class – A python class to use as the base class for the created hook. This will override the default hook base class, Hook.
Returns:

The return value from the hook

execute_hook_by_name(hook_name, **kwargs)

Execute an arbitrary hook located in the hooks folder for this project. The hook_name is the name of the python file in which the hook resides, without the file extension.

In most use cases, the execute_hook method is the preferred way to access a hook from an app.

Warning

Now deprecated - Please use execute_hook_expression() instead.

This method is typically only used when you want to execute an arbitrary list of hooks, for example if you want to run a series of arbitrary user defined pre-publish validation hooks.

Note

For more information about hooks, see Hook

Parameters:hook_name – name of the legacy hook file to execute.
execute_hook_expression(hook_expression, method_name, base_class=None, **kwargs)

Execute an arbitrary hook via an expression. While the methods execute_hook and execute_hook_method allows you to execute a particular hook setting as specified in the app configuration manifest, this methods allows you to execute a hook directly by passing a hook expression, for example {config}/path/to/my_hook.py

This is useful if you are doing rapid app development and don’t necessarily want to expose a hook as a configuration setting just yet. It is also useful if you have app settings that are nested deep inside of lists or dictionaries. In that case, you cannot use execute_hook, but instead will have to retrieve the value specifically and then run it.

An optional base_class can be provided to override the default Hook base class. This is useful for bundles that want to define and document a strict interface for hooks. The classes defined in the hook have to derived from this classes.

Note

For more information about hooks, see Hook

Parameters:
  • hook_expression – Path to hook to execute. See above for syntax details.
  • method_name – Method inside the hook to execute.
  • base_class – A python class to use as the base class for the created hook. This will override the default hook base class, Hook.
Returns:

The return value from the hook

execute_hook_method(key, method_name, base_class=None, **kwargs)

Execute a specific method in a hook that is part of the environment configuration for the current bundle.

You simply pass the name of the hook setting that you want to execute, the name of the method you want to execute and the accompanying arguments. Toolkit will find the correct hook file based on the currently configured setting and then execute the specified method.

Hooks form a flexible way to extend and make toolkit apps or engines configurable. A hook acts like a setting in that it needs to be configured as part of the app’s configuration, but instead of being a simple value, it is a code snippet contained inside a class.

Apps typically provide default hooks to make installation and overriding easy. Each hook is represented by a setting, similar to the ones you access via the get_setting() method, however instead of retrieving a fixed value, you execute code which generates a value.

This method will execute a specific method for a given hook setting. Toolkit will find the actual python hook file and handle initialization and execution for you, by looking at the configuration settings and resolve a path based on this.

Arguments should always be passed in by name. This is to make it easy to add new parameters without breaking backwards compatibility, for example execute_hook_method("validator", "pre_check", name=curr_scene, version=curr_ver).

An optional base_class can be provided to override the default Hook base class. This is useful for bundles that want to define and document a strict interface for hooks. The classes defined in the hook have to derived from this classes.

Note

For more information about hooks, see Hook

Parameters:
  • key – The name of the hook setting you want to execute.
  • method_name – Name of the method to execute
  • base_class – A python class to use as the base class for the created hook. This will override the default hook base class, Hook.
Returns:

The return value from the hook

frameworks

List of all frameworks associated with this item

Returns:List of framework objects
get_project_cache_location(project_id)

Gets the bundle’s cache-location path for the given project id.

Parameters:project_id (int) – The project Entity id number.
Returns:Cache location directory path.
Rtype str:
get_setting(key, default=None)

Get a value from the item’s settings:

>>> app.get_setting('entity_types')
['Sequence', 'Shot', 'Asset', 'Task']
Parameters:
  • key – config name
  • default – default value to return
Returns:

Value from the environment configuration

get_template(key)

Returns a template object for a particular template setting in the Framework configuration. This method will look at the app configuration, determine which template is being referred to in the setting, go into the main platform Template API and fetch that particular template object.

This is a convenience method. Shorthand for self.sgtk.templates[ self.get_setting(key) ].

Parameters:key – Setting to retrieve template for
Returns:Template object
get_template_by_name(template_name)

Note: This is for advanced use cases - Most of the time you should probably use get_template(). Find a particular template, the way it is named in the master config file templates.yml. This method will access the master templates file directly and pull out a specifically named template without using the app config. Note that using this method may result in code which is less portable across studios, since it makes assumptions about how templates are named and defined in the master config. Generally speaking, it is often better to access templates using the app configuration and the get_template() method.

This is a convenience method. Shorthand for self.sgtk.templates[template_name].

:param template_name :returns: Template object

icon_256

Path to a 256x256 pixel png file which describes the item

import_module(module_name)

Special import command for Toolkit bundles. Imports the python folder inside an app and returns the specified module name that exists inside the python folder.

Each Toolkit App or Engine can have a python folder which contains additional code. In order to ensure that Toolkit can run multiple versions of the same app, as well as being able to reload app code if it changes, it is recommended that this method is used whenever you want to access code in the python location.

For example, imagine you had the following structure:

tk-multi-mybundle
   |- app.py or engine.py or framework.py
   |- info.yml
   \- python
       |- __init__.py   <--- Needs to contain 'from . import tk_multi_mybundle'
       \- tk_multi_mybundle

The above structure is a standard Toolkit app outline. app.py is a light weight wrapper and the python module tk_multi_myapp module contains the actual code payload. In order to import this in a Toolkit friendly way, you need to run the following when you want to load the payload module inside of app.py:

module_obj = self.import_module("tk_multi_myapp")
name

The short name for the item (e.g. tk-maya)

Returns:name as string
post_context_change(old_context, new_context)

Called after a context change.

Implemented by deriving classes.

Parameters:
  • old_context (Context) – The context being changed away from.
  • new_context (Context) – The context being changed to.
pre_context_change(old_context, new_context)

Called before a context change.

Implemented by deriving classes.

Parameters:
  • old_context (Context) – The context being changed away from.
  • new_context (Context) – The context being changed to.
sgtk

Returns the Toolkit API instance associated with this item

Returns:Tank
site_cache_location

A site location on disk where the app or engine can store random cache data. This location is guaranteed to exist on disk.

This location is configurable via the cache_location hook. It typically points at a path in the local filesystem, e.g on a mac:

~/Library/Caches/Shotgun/SITENAME/BUNDLE_NAME

This can be used to store cache data that the app wants to reuse across sessions and can be shared across a site:

stored_query_data_path = os.path.join(self.site_cache_location, "query.dat")
style_constants

Returns a dictionary of style constants. These can be used to build UIs using standard colors and other style components. All keys returned in this dictionary can also be used inside a style.qss that lives at the root level of the app, engine or framework. Use a {{DOUBLE_BACKET}} syntax in the stylesheet file, for example:

QWidget
{ 
    color: {{SG_FOREGROUND_COLOR}};
}

This property returns the values for all constants, for example:

{ 
  "SG_HIGHLIGHT_COLOR": "#18A7E3",
  "SG_ALERT_COLOR": "#FC6246",
  "SG_FOREGROUND_COLOR": "#C8C8C8"
}
Returns:Dictionary. See above for example
support_url

Return the relevant support url for this item.

Returns:url string, None if no documentation was found
tank

Returns the Toolkit API instance associated with this item

Returns:Tank
version

The version of the item (e.g. ‘v0.2.3’)

Returns:string representing the version

Frameworks

Frameworks are like libraries. They contain functionality that can be shared and reused across apps or engines.

Frameworks are automatically imported into the system whenever Toolkit finds a framework defined in the info.yml for an app or an engine. Once imported, it will be available in the frameworks dictionary on the host object. For example, an app or engine (or framework) may have the following definition in its info.yml:

frameworks:
    - {"name": "tk-framework-widget", "version": "v0.1.2"}
    - {"name": "tk-framework-tools", "version": "v0.x.x"}

When Toolkit loads the app, it will verify that the two frameworks are present in the environment and initialize them. Once initialized, the app that needs them can access them via the self.frameworks property:

foo_bar_module = self.frameworks["tk-framework-widget"].import_module("foo_bar")

In order to import a framework module into app or engine code, use the convenience method import_framework(). This method is typically executed right in the beginning of the file, before you create any methods or classes:

import os
import sys
import sgtk
widgets = sgtk.platform.import_framework("tk-framework-widget", "widgets")

class MyBrowser(widgets.BrowserWidget):
    ...

If you would like to load the framework instance itself rather than a module which was imported as part of the framework initalization, you can use the get_framework() method:

import sgtk
fw = sgtk.platform.get_framework("tk-framework-widget")

Note that this only works inside of code which has been imported via the import_module command - e.g. the way we recommend that Sgtk code is being imported into apps. For other scenarios, use the frameworks dictionary in conjunction with the import_module command, as shown above.

Frameworks are imported in an individual fashion, meaning that even though a framework is used in two apps, each app will import its own instance of the framework. This is to ensure stability and encapsulation.

A framework works just like an app or an engine - it has an info.yml manifest, a framework.py file which typically contains a class which derives from the Framework base class, etc.

Framework

class sgtk.platform.Framework(engine, descriptor, settings, env)[source]

Base class for a Toolkit Framework

Called by the bundle loading framework. The constructor is not meant to be overridden by deriving classes.

Parameters:
  • engine (Engine) – The engine instance to connect this fw to
  • app_name – The short name of this framework (e.g. tk-framework-widget)
  • settings – a settings dictionary for this fw
  • env – the environment that the framework belongs to
logger

Standard python logger for this engine, app or framework.

Use this whenever you want to emit or process log messages. If you are developing an app, engine or framework, call this method for generic logging.

Note

Inside the python area of your app, engine or framework, we recommend that you use sgtk.platform.get_logger() for your logging.

Logging will be dispatched to a logger parented under the main toolkit logging namespace:

# pattern
sgtk.env.environment_name.engine_instance_name

# for example
sgtk.env.asset.tk-maya

Note

If you want all log messages that you are emitting in your app, engine or framework to be written to a log file or to a logging console, you can attach a std log handler here.

shotgun

Returns a Shotgun API handle associated with the currently running environment. This method is a convenience method that calls out to shotgun().

Returns:Shotgun API handle
engine

The engine that this framework is connected to

is_shared

Boolean indicating whether this is a shared framework.

Frameworks are shared by default and this is a setting that can be controlled by the bundle manifest.

When a framework is shared, a single copy of the code is shared across all apps that use it. All apps will cut their framework instances from the same code. Any global state within the framework will be shared across all framework instances, and hence across all different apps.

If your framework manages complex global state that you want to control precisely, it may be useful to set the framework to be not shared in the info.yml manifest file. This will ensure that each bundle that uses the framework will maintain it’s own private version of the framework code.

get_metrics_properties()[source]

Returns a dictionary with properties to use when emitting a metric event for this framework in the current engine.

Frameworks don’t have any particular properties and just return the result of Engine.get_metrics_properties().

Returns:Dictionary as per above.
init_framework()[source]

Implemented by deriving classes in order to initialize the app. Called by the engine as it loads the framework.

destroy_framework()[source]

Implemented by deriving classes in order to tear down the framework. Called by the engine as it is being destroyed.

log_debug(msg)[source]

Logs a debug message.

Deprecated since version 0.18: Use Engine.logger() instead.

Parameters:msg – Message to log.
log_info(msg)[source]

Logs an info message.

Deprecated since version 0.18: Use Engine.logger() instead.

Parameters:msg – Message to log.
log_warning(msg)[source]

Logs an warning message.

Deprecated since version 0.18: Use Engine.logger() instead.

Parameters:msg – Message to log.
log_error(msg)[source]

Logs an error message.

Deprecated since version 0.18: Use Engine.logger() instead.

Parameters:msg – Message to log.
log_exception(msg)[source]

Logs an exception message.

Deprecated since version 0.18: Use Engine.logger() instead.

Parameters:msg – Message to log.
cache_location

An item-specific location on disk where the app or engine can store random cache data. This location is guaranteed to exist on disk.

This location is configurable via the cache_location hook. It typically points at a path in the local filesystem, e.g on a mac:

~/Library/Caches/Shotgun/SITENAME/PROJECT_ID/BUNDLE_NAME

This can be used to store cache data that the app wants to reuse across sessions:

stored_query_data_path = os.path.join(self.cache_location, "query.dat")
change_context(new_context)

Abstract method for context changing.

Implemented by deriving classes that wish to support context changes and require specific logic to do so safely.

Parameters:new_context – The context being changed to.
context

The context associated with this item.

Returns:Context
context_change_allowed

Whether a context change is allowed without the need for a restart. If a bundle supports on-the-fly context changing, this property should be overridden in the deriving class and forced to return True.

Returns:bool
create_hook_instance(hook_expression, base_class=None)

Returns the instance of a hook object given an expression.

This is useful for complex workflows where it is beneficial to maintain a handle to a hook instance. Normally, hooks are stateless and every time a hook is called, a new instance is returned. This method provides a standardized way to retrieve an instance of a hook:

self._plugin = app_object.create_hook_instance("{config}/path/to/my_hook.py")
self._plugin.execute_method_x()
self._plugin.execute_method_y()
self._plugin.execute_method_z()

The hook expression is the raw value that is specified in the configuration file. If you want to access a configuration setting instead (like how for example execute_hook_method() works), simply call get_setting() to retrieve the value and then pass the settings value to this method.

Note

For more information about hook syntax, see Hook

An optional base_class can be provided to override the default Hook base class. This is useful for bundles that create hook instances at execution time and wish to provide default implementation without the need to configure the base hook. The supplied class must inherit from Hook.

Parameters:
  • hook_expression – Path to hook to execute. See above for syntax details.
  • base_class – A python class to use as the base class for the created hook. This will override the default hook base class, Hook.
Returns:

Hook instance.

description

A short description of the item

Returns:string
disk_location

The folder on disk where this item is located. This can be useful if you want to write app code to retrieve a local resource:

app_font = os.path.join(self.disk_location, "resources", "font.fnt")
display_name

The display name for the item (e.g. Maya Engine)

Returns:display name as string
documentation_url

Return the relevant documentation url for this item.

Returns:url string, None if no documentation was found
ensure_folder_exists(path)

Make sure that the given folder exists on disk. Convenience method to make it easy for apps and engines to create folders in a standardized fashion. While the creation of high level folder structure such as Shot and Asset folders is typically handled by the folder creation system in Toolkit, Apps tend to need to create leaf-level folders such as publish folders and work areas. These are often created just in time of the operation.

Note

This method calls out to the ensure_folder_exists core hook, making the I/O operation user configurable. We recommend using this method over the methods provided in sgtk.util.filesystem.

Parameters:path – path to create
execute_hook(key, base_class=None, **kwargs)

Execute a hook that is part of the environment configuration for the current bundle.

Convenience method that calls execute_hook_method() with the method_name parameter set to “execute”.

Warning

This method is present for backwards compatibility. For all new hooks, we recommend using execute_hook_method() instead.

You simply pass the name of the hook setting that you want to execute and the accompanying arguments, and toolkit will find the correct hook file based on the currently configured setting and then execute the execute() method for that hook.

An optional base_class can be provided to override the default Hook base class. This is useful for bundles that want to define and document a strict interface for hooks. The classes defined in the hook have to derived from this classes.

Note

For more information about hooks, see Hook

Parameters:
  • key – The name of the hook setting you want to execute.
  • base_class – A python class to use as the base class for the created hook. This will override the default hook base class, Hook.
Returns:

The return value from the hook

execute_hook_by_name(hook_name, **kwargs)

Execute an arbitrary hook located in the hooks folder for this project. The hook_name is the name of the python file in which the hook resides, without the file extension.

In most use cases, the execute_hook method is the preferred way to access a hook from an app.

Warning

Now deprecated - Please use execute_hook_expression() instead.

This method is typically only used when you want to execute an arbitrary list of hooks, for example if you want to run a series of arbitrary user defined pre-publish validation hooks.

Note

For more information about hooks, see Hook

Parameters:hook_name – name of the legacy hook file to execute.
execute_hook_expression(hook_expression, method_name, base_class=None, **kwargs)

Execute an arbitrary hook via an expression. While the methods execute_hook and execute_hook_method allows you to execute a particular hook setting as specified in the app configuration manifest, this methods allows you to execute a hook directly by passing a hook expression, for example {config}/path/to/my_hook.py

This is useful if you are doing rapid app development and don’t necessarily want to expose a hook as a configuration setting just yet. It is also useful if you have app settings that are nested deep inside of lists or dictionaries. In that case, you cannot use execute_hook, but instead will have to retrieve the value specifically and then run it.

An optional base_class can be provided to override the default Hook base class. This is useful for bundles that want to define and document a strict interface for hooks. The classes defined in the hook have to derived from this classes.

Note

For more information about hooks, see Hook

Parameters:
  • hook_expression – Path to hook to execute. See above for syntax details.
  • method_name – Method inside the hook to execute.
  • base_class – A python class to use as the base class for the created hook. This will override the default hook base class, Hook.
Returns:

The return value from the hook

execute_hook_method(key, method_name, base_class=None, **kwargs)

Execute a specific method in a hook that is part of the environment configuration for the current bundle.

You simply pass the name of the hook setting that you want to execute, the name of the method you want to execute and the accompanying arguments. Toolkit will find the correct hook file based on the currently configured setting and then execute the specified method.

Hooks form a flexible way to extend and make toolkit apps or engines configurable. A hook acts like a setting in that it needs to be configured as part of the app’s configuration, but instead of being a simple value, it is a code snippet contained inside a class.

Apps typically provide default hooks to make installation and overriding easy. Each hook is represented by a setting, similar to the ones you access via the get_setting() method, however instead of retrieving a fixed value, you execute code which generates a value.

This method will execute a specific method for a given hook setting. Toolkit will find the actual python hook file and handle initialization and execution for you, by looking at the configuration settings and resolve a path based on this.

Arguments should always be passed in by name. This is to make it easy to add new parameters without breaking backwards compatibility, for example execute_hook_method("validator", "pre_check", name=curr_scene, version=curr_ver).

An optional base_class can be provided to override the default Hook base class. This is useful for bundles that want to define and document a strict interface for hooks. The classes defined in the hook have to derived from this classes.

Note

For more information about hooks, see Hook

Parameters:
  • key – The name of the hook setting you want to execute.
  • method_name – Name of the method to execute
  • base_class – A python class to use as the base class for the created hook. This will override the default hook base class, Hook.
Returns:

The return value from the hook

frameworks

List of all frameworks associated with this item

Returns:List of framework objects
get_project_cache_location(project_id)

Gets the bundle’s cache-location path for the given project id.

Parameters:project_id (int) – The project Entity id number.
Returns:Cache location directory path.
Rtype str:
get_setting(key, default=None)

Get a value from the item’s settings:

>>> app.get_setting('entity_types')
['Sequence', 'Shot', 'Asset', 'Task']
Parameters:
  • key – config name
  • default – default value to return
Returns:

Value from the environment configuration

get_template(key)

Returns a template object for a particular template setting in the Framework configuration. This method will look at the app configuration, determine which template is being referred to in the setting, go into the main platform Template API and fetch that particular template object.

This is a convenience method. Shorthand for self.sgtk.templates[ self.get_setting(key) ].

Parameters:key – Setting to retrieve template for
Returns:Template object
get_template_by_name(template_name)

Note: This is for advanced use cases - Most of the time you should probably use get_template(). Find a particular template, the way it is named in the master config file templates.yml. This method will access the master templates file directly and pull out a specifically named template without using the app config. Note that using this method may result in code which is less portable across studios, since it makes assumptions about how templates are named and defined in the master config. Generally speaking, it is often better to access templates using the app configuration and the get_template() method.

This is a convenience method. Shorthand for self.sgtk.templates[template_name].

:param template_name :returns: Template object

icon_256

Path to a 256x256 pixel png file which describes the item

import_module(module_name)

Special import command for Toolkit bundles. Imports the python folder inside an app and returns the specified module name that exists inside the python folder.

Each Toolkit App or Engine can have a python folder which contains additional code. In order to ensure that Toolkit can run multiple versions of the same app, as well as being able to reload app code if it changes, it is recommended that this method is used whenever you want to access code in the python location.

For example, imagine you had the following structure:

tk-multi-mybundle
   |- app.py or engine.py or framework.py
   |- info.yml
   \- python
       |- __init__.py   <--- Needs to contain 'from . import tk_multi_mybundle'
       \- tk_multi_mybundle

The above structure is a standard Toolkit app outline. app.py is a light weight wrapper and the python module tk_multi_myapp module contains the actual code payload. In order to import this in a Toolkit friendly way, you need to run the following when you want to load the payload module inside of app.py:

module_obj = self.import_module("tk_multi_myapp")
name

The short name for the item (e.g. tk-maya)

Returns:name as string
post_context_change(old_context, new_context)

Called after a context change.

Implemented by deriving classes.

Parameters:
  • old_context (Context) – The context being changed away from.
  • new_context (Context) – The context being changed to.
pre_context_change(old_context, new_context)

Called before a context change.

Implemented by deriving classes.

Parameters:
  • old_context (Context) – The context being changed away from.
  • new_context (Context) – The context being changed to.
sgtk

Returns the Toolkit API instance associated with this item

Returns:Tank
site_cache_location

A site location on disk where the app or engine can store random cache data. This location is guaranteed to exist on disk.

This location is configurable via the cache_location hook. It typically points at a path in the local filesystem, e.g on a mac:

~/Library/Caches/Shotgun/SITENAME/BUNDLE_NAME

This can be used to store cache data that the app wants to reuse across sessions and can be shared across a site:

stored_query_data_path = os.path.join(self.site_cache_location, "query.dat")
style_constants

Returns a dictionary of style constants. These can be used to build UIs using standard colors and other style components. All keys returned in this dictionary can also be used inside a style.qss that lives at the root level of the app, engine or framework. Use a {{DOUBLE_BACKET}} syntax in the stylesheet file, for example:

QWidget
{ 
    color: {{SG_FOREGROUND_COLOR}};
}

This property returns the values for all constants, for example:

{ 
  "SG_HIGHLIGHT_COLOR": "#18A7E3",
  "SG_ALERT_COLOR": "#FC6246",
  "SG_FOREGROUND_COLOR": "#C8C8C8"
}
Returns:Dictionary. See above for example
support_url

Return the relevant support url for this item.

Returns:url string, None if no documentation was found
tank

Returns the Toolkit API instance associated with this item

Returns:Tank
version

The version of the item (e.g. ‘v0.2.3’)

Returns:string representing the version

Exceptions

The following exception types are raised from within sgtk.platform:

class sgtk.platform.TankEngineInitError[source]

Bases: tank.errors.TankError

Exception that indicates that an engine could not start up.

class sgtk.platform.TankMissingEngineError[source]

Bases: tank.platform.errors.TankEngineInitError

Exception that indicates that an engine could not start up.

class sgtk.platform.TankContextChangeNotSupportedError[source]

Bases: tank.errors.TankError

Exception that indicates that a requested context change is not allowed based on a check of the current engine and all of its active apps.

App and Engine Development

Import and access methods

The following methods are useful when writing app, engine or framework code and you need to access and load other objects.

Note

For examples of how the below methods are used in practice, check out our starter app https://github.com/shotgunsoftware/tk-multi-starterapp.

sgtk.platform.current_bundle(*args, **kwargs)

Returns the bundle (app, engine or framework) instance for the app that the calling code is associated with. This is a special method, designed to be used inside python modules that belong to apps, engines or frameworks.

The calling code needs to have been imported using toolkit’s standard import mechanism, Application.import_module(), otherwise an exception will be raised.

This special helper method can be useful when code deep inside an app needs to reach out to for example grab a configuration value. Then you can simply do:

app = sgtk.platform.current_bundle()
app.get_setting("frame_range")
Returns:Application, Engine or Framework instance
sgtk.platform.get_framework(framework)[source]

Convenience method that returns a framework instance given a framework name.

This is a special method, designed to be used inside python modules that belong to apps, engines or frameworks.

The calling code needs to have been imported using toolkit’s standard import mechanism, import_module(), otherwise an exception will be raised.

For example, if your app code requires the tk-framework-helpers framework, and you need to retrieve a configuration setting from this framework, then you can simply do:

fw = sgtk.platform.get_framework("tk-framework-helpers")
fw.get_setting("frame_range")
Parameters:framework – name of the framework object to access, as defined in the app’s info.yml manifest.
Returns:framework instance
Type:Framework
sgtk.platform.import_framework(*args, **kwargs)

Convenience method for using frameworks code inside of apps, engines and other frameworks.

This method is intended to replace an import statement. Instead of typing:

from . import foo_bar

You use the following syntax to load a framework module:

foo_bar = tank.platform.import_framework("tk-framework-mystuff", "foo_bar")

This is a special method, designed to be used inside python modules that belong to apps, engines or frameworks.

The calling code needs to have been imported using toolkit’s standard import mechanism, Bundle.import_module(), otherwise an exception will be raised.

Parameters:
  • framework – name of the framework object to access, as defined in the app’s info.yml manifest.
  • module – module to load from framework
sgtk.platform.get_logger(x)

Manifest file

Apps, engines and frameworks each have a metadata file. It always resides in the root of the app or engine and is always named info.yml. This metadata file contains important information about the item:

  • Configuration settings available for an app or engine.
  • Display name, documentation and support links for the app and other user facing metadata.
  • All custom Shotgun fields that are required by the app or engine code.
  • Which frameworks that are required in order for this app to run. You can specify an exact framework version to use (e.g. v1.2.3) or you can track against a subset of versions (e.g. v1.x.x or v1.2.x).

For real-world examples, see for example the Shotgun Loader or the Shotgun Nuke Write Node.

Display name and Description

The optional display_name field defines the name that the user will see for the app. The optional description field is a brief one line description of what the app does:

# More verbose description of this item
display_name: "Write Node"
description: "Support for the Shotgun Write Node in Nuke."

Frameworks

If a framework is being used by the app, declare it in the info.yml and Toolkit will keep track and make sure that it is installed and available. Once inside the app, use the call module_name = sgtk.platform.import_framework("tk-framework-name", "module_name"). For more information, see import_framework().

The frameworks section is a list of dictionaries, for example:

# the frameworks required to run this app
frameworks:
    - {"name": "tk-framework-shotgunutils", "version": "v2.x.x"}
    - {"name": "tk-framework-qtwidgets", "version": "v1.x.x"}

Version numbers are typically supplied on the form v1.x.x, meaning that it will try to use the most recent approved major version one of the framework. Toolkit uses semantic versioning (http://semver.org/) for its versioning, meaning that major version numbers indicate breaking changes, minor version number increments indicates added features and patch version numbers indicates backwards compatible bug fixes. We therefore recommend to have framework dependencies track against a major version number.

Note

If there is a required minimum version for a framework, a minimum_version setting can be used in the info.yml manifest:

# the frameworks required to run this app
frameworks:
    - {"name": "tk-framework-shotgunutils", "version": "v2.x.x", "minimum_version": "v2.3.3"}
    - {"name": "tk-framework-qtwidgets", "version": "v1.x.x"}

Version constraints

If your app or engine requires specific versions of shotgun, the core or other things, you can specify this using the three parameters requires_shotgun_version, requires_core_version and (for apps only) requires_engine_version:

# Required minimum versions for this item to run
requires_shotgun_version:
requires_core_version: "v0.14.37"
requires_engine_version: "v0.2.3"

Supported Engines and operating systems

If your app is not a multi-app that has been designed to run in any engine, use this option to specify which engines are supported:

supported_engines: [tk-nuke]

If your app or engine only supports a particular operating system, you can define this using a supported_platforms parameter. Valid values are linux, windows and mac. This is an optional setting - omitting it or leaving it blank means that the app or engine will work on all platforms.

Documentation and Support

If you are developing an app for the Toolkit app store, no need to fill this in - the Sgtk Store manages documentation separately! But if you are building an in-house app for your studio, it can be useful to link it up to a wiki page or similar, so that it is easy for users to jump straight from the app to the documentation. In this case, just add a documentation_url setting:

documentation_url: "http://intranet/path/to/sgtk_app_docs.html"

This will be picked up and displayed in various locations in the Toolkit UI.

Similar to the documentation url above, it can be useful to connect an app to a url which lets users know how to get help when they have questions. If you have a separate system in your studio, (like an Request Tracker setup), and you want to make it easy for users to reach out from the app to this system, just define a support_url url:

support_url: "http://intranet/pipeline_team/support.html"

This setting is optional, and if left blank, the support url will automatically be the standard Toolkit support location.

Required Context Fields

Toolkit has a Context which it uses to determine what the current Shot, Project or Asset is. Apps may require a particular feature to be present in the context - for example, a Loader App may require an entity to be present in order to show a list of items for the current Asset or Shot. The required_context settings help defining what fields are needed. Possible values are project, entity, step, task and user.

Shotgun fields

If your app requires a particular custom field in Shotgun to operate correctly, you can add this to the info.yml manifest. Whenever the app is installed into a setup, toolkit will ensure that this custom field exists in shotgun.

Just create a requires_shotgun_fields in your manifest and add entries on the following form:

requires_shotgun_fields:
    # Shotgun fields that this app expects
    Version:
        - { "system_name": "sg_movie_type", "type": "text" }

Note how the fields are grouped by Shotgun entity type (in the example above Version). For a list of which field types are supported, see the Shotgun API documentation.

Note

For more complex field types (such as entity and multi entity links), you need to set up creation via the post-install hook instead. (The post install hook is a special hook which runs at installation time and allows you to execute arbitrary code as part of the app installation process.)

Warning

This functionality requires administrative privileges in Shotgun. Apps using this functionality therefore requires a workflow where an admin is required to update or install such apps. For general purpose apps, we therefore recommend not relying on this functionality.

The configuration section

If an app requires a setting in its code, it should be defined in the info.yml. Toolkit will validate all requested settings and make sure that they have all been defined (or have default values) and are valid before apps are launched. It will also use this metadata when performing upgrades and installations.

A single configuration entry typically looks like this:

setting_name:
    type: some_type
    description: "description of the setting"
    default_value: general_default
    default_value_tk-nuke: nuke_default
    default_value_tk-maya: maya_default
    option1: option_value1
    option2: option_value2

Data types typically have specific optional settings. All data types and their options are outlines in the following sections.

A full configuration section inside an info.yml manifest may look like this:

configuration:

    shotgun_fields_hook:
        type: hook
        default_value: "{self}/shotgun_fields.py"
        description: Hook which controls how values are presented

    action_mappings:
        type: dict
        description: Associates shotgun objects with actions. The actions are all defined
                     inside the actions hook, so a number of actions are available by default
                     and in addition to this you can add your own actions if you like.
        default_value:
            Task:
                - { actions: [assign_task, task_to_ip], filters: {} }
            Version:
                - { actions: [quicktime_clipboard, sequence_clipboard], filters: {} }
            PublishedFile:
                - { actions: [publish_clipboard], filters: {} }

        default_value_tk-nuke:
            Task:
                - { actions: [assign_task, task_to_ip], filters: {} }
            Version:
                - { actions: [quicktime_clipboard, sequence_clipboard], filters: {} }
            PublishedFile:
                - { actions: [publish_clipboard], filters: {} }
                - { actions: [read_node], filters: { published_file_type: Rendered Image} }
                - { actions: [script_import], filters: { published_file_type: Nuke Script} }

Sparse configurations

In the configuration you can define default value for the various app settings that you define. As of v0.18.x, these values will be read at run-time if the setting is not specified in the environment. Prior to v0.18.x, configuration files were required to be non-sparse, meaning that all parameters needed to be populated in the configuration.

Default values per engine

It is possible to define defaults per engine using the following syntax:

setting_name:
    type: some_type
    description: "description of the setting"
    default_value: general_default
    default_value_tk-nuke: nuke_default
    default_value_tk-maya: maya_default

When the app is being installed or updated, toolkit will first look for a default value for the engine which the app is being installed into. If that is not found, it will look for a general default_value setting. If that is not found, the user will be prompted to manually supply a value to populate in the environment. As of v0.18.x, settings with a default value will not be explicitly added to the installed/updated app’s settings.

Values that are procedurally populated by hooks

For advanced use cases, it is possible to specify a configuration value as a special hook evaluator rather than as a template setting. This means that when you configure your environment, rather than specifying an actual value for a setting to use with your app, you can specify a piece of code that returns the value to use. This makes it possible to create very complex settings logic. For more information, see the example_template_hook.py hook located in the core hooks area.

Simple Data Types

A number of simple data types are supported. These do not have any special options.

  • str - a string value
  • int - an integer
  • float - a floating point value
  • bool - a boolean, expecting values true or false

An example declaration for a simple data type may look like this:

debug_logging:
    type: bool
    default_value: false
    description: Controls whether debug messages should be emitted to the logger

The config_path data type

Use this when your app requires an external file that is part of the configuration. Typically, this settings type is used when you want to allow for a user to associate files with a configuration. These files can be icons or other resource files that should be part of the configuration. These paths should always be defined without an initial slash and using slashes as its path separator. Sgtk will translate it into a valid Windows path:

output_icon:
    type: config_path
    description: A config centric path that points to a square icon png file.

The publish_type data type

Use this when you want a setting which expects a Publish Type - these are typically used when publishing data to Shotgun. Value is a string matching PublishedFileType.code:

published_script_type:
    type: publish_type
    description: The Published file type for published Nuke scripts.

Note

The equivalent tank_type data type is also supported for backwards compatibility.

The shotgun_entity_type data type

Value is a string that represents a Shotgun entity type like Task, Sequence, Shot:

entity_type:
    type: shotgun_entity_type
    default_value: Shot
    description: "The entity type to attach to"

The shotgun_permission_group data type

Value is a string that represents the display name of a Shotgun permission group like Admin, Artist:

permissions_group:
    type: shotgun_permission_group
    default_value: Artist
    description: "Permissions group to use when performing the operation"

The shotgun_filter data type

Value is a filter that will be passed to the shotgun api when performing a query (e.g. ["sg_status_list", "is", "cmpt"]). As shotgun filters can take multiple forms, no additional validation will be done on values of this type:

publish_filters:
    type: list
    values:
        type: shotgun_filter

The template data type

Value is a string matching an entry in templates.yml. Using the fields option you specify how Toolkit should validate the template that the user specifies:

output_render:
    description: Render output location
    type: template
    fields: "context, name, channel, version, [width], [height], [eye]"

When you specify which fields your app requires, it must be strict. Toolkit will ensure that the template that the user has chosen to configure the app with exactly matches the values specified in the fields string. Typically, the app will also pull in fields via the context object - you can specify this by using the special context parameter. Optional parameters are represented with [brackets] and the special token * indicates that an arbitrary number of fields is okay. For example:

  • fields: name - only templates containing a single field name will be valid
  • fields: context, name - templates containing exactly the number of fields that the context is able to resolve, and name, will be valid.
  • fields: context, name, [width], [height] - same as previous but the two fields width and height can be present in the template at the user’s discression.
  • fields: name, * - name is required, the rest of the fields can be arbitrary.

A typical example illustrating the use of * is when you need to look for things in the scene which do not belong to the current context - for example if you are working on a shot and wants to scan for assets that have been imported into the scene. In this case, you cannot use the context since this is pointing at the current Shot:

input_templates_to_look_for:
    type: list
    description: List of templates to look for when scanning the scene for inputs.
                 A template listed here only needs to have a field called version. This field
                 will be used in the comparison to determine what is out of date.
    values:
        type: template
        fields: "version, *"

Empty settings

By default, all template settings require the user to specify a valid template when they are added to the environment configuration. If you want to define a template setting that can be set to None, specify the allows_empty option and set it to True:

output_render:
    description: Render output location, Leave blank for default output.
    type: template
    fields: "context, name, channel, version, [width], [height], [eye]"
    allows_empty: True

The hook data type

Hooks makes it possible to create flexible and powerful configurations for toolkit apps. A hook is a python file which contains a single class (deriving from a Hook base class or from other hook classes) and a number of pre-defined methods.

Hooks takes configuration beyond the retrival of a simple string or int value and allows apps to break out parts of the code that are likely to vary across facilities into code that can be customized, either by completely overriding it or by deriving from another hook class.

For hook documentation, see Hooks.

Typical Workflow for hooks

If you are using a Toolkit app and want to customize the behaviour that is defined in a hook, you can typically follow these steps:

  1. Identify the hook file and copy it into the hooks folder in your Toolkit project configuration. For example, if your hook is named validation.py, copy it to the configuration folder as CONFIG_ROOT/hooks/validation.py.

  2. In your environment configuration, find the app config and tell the app to use your new file instead of the default one:

    # change the default value in your env config:
    validation_hook: {self}/validation.py
    
    # to this new value:
    validation_hook: {config}/validation.py
    
  3. Now we have a bunch of duplicated code in our config folder which isn’t great. Because we are inheriting from the default hook, our custom hook only really needs to contain the modifications that we are making and not the entire logic. So go in and strip back our custom hook in the config folder:

    # customized validation hook in CONFIG_ROOT/hooks/validation.py
    import sgtk
    
    HookBaseClass = sgtk.get_hook_baseclass()
    
    class Validator(HookBaseClass):
    
        def validate_string(self, value):
            # call the built-in hook that comes with the app first
            HookBaseClass.validate_string(self, value)
    
            # now add our extra bit of validation
            if "LOLCAT" in value:
                raise Exception("No lol-cats in my pipeline!")
    

This makes it possible to customize parts of hooks, while leaving a lot of the hook code in tact. This keeps customizations lightweight, avoids code duplication and allows an app developer to push out bug fixes much more easily.

Multiple levels of inheritance in hooks

For even more complex scenarios, it is possible to declare an inheritance chain in the environment config:

validation_hook: {$STUDIO_ROOT}/studio_validation.py:{config}/project_validation.py.

This example will have three levels of inheritance: first the built in hook, after that a studio level implementation defined by an environment variable and lastly a project level implementation.

Accessing a framework inside a hook

For even more complex hook setups, you can also access frameworks from inside your hooks:

class SomeHook(HookBaseClass):

    def some_method(self):

        # first get a framework handle. This object is similar to an app or engine object
        fw = self.load_framework("my-framework-library_v123.x.x")

        # now just like with an app or an engine, if you want to access code in the python
        # folder, you can do import_plugin
        module = fw.import_module("some_module")

Note how we are accessing the framework instance my-framework-library_v123.x.x above. This needs to be defined in the currently running environment, as part of the frameworks section:

engines:
  # all engine and app defs here...

frameworks:
 # define the framework that we are using in the hook
 my-framework-library_v123.x.x:
    location: {type: dev, path: /some/path}

The list data type

Value is a list, all values in the list must be of the same data type. You must supply values dict that describes the data type of the list items:

entity_types:
    type: list
    values: {type: shotgun_entity_type}
    default_value: [Sequence, Shot, Asset, Task]
    description: List of Shotgun entity types where this
                 Sgtk action should be visible on the Actions menu.

Optionally you can also specify an allows_empty option if an empty list is a valid value:

publish_types:
    type: list
    allows_empty: True
    values: {type: pubish_type}

You would then be able to specify an empty list in your environment configuration:

apps:
    tk-multi-loader:
        tank_types: []

The dict data type

Value is a dictionary, keys are always strings, values can be of mixed types.

In info.yml, optionally provide an items dict. Used to mark what keys must be in the config, default values, and type info for the values which will be used for validation:

write_nodes:
    type: list
    description: "A list of dictionaries in which you define the Sgtk write nodes that
                 are supported in this configuration."
    allows_empty: True
    values:
        type: dict
        items:
            name: { type: str }
            file_type: { type: str }
            publish_type: { type: tank_type }
            render_template:
                type: template
                fields: "context, name, channel, version, SEQ, [width], [height], [eye]"

A valid setting could look like this:

movies:
- {name: Exr Render, file_type: exr, publish_type: Quicktime, render_template: exr_shot_render}
- {name: Dpx Render, file_type: dpx, publish_type: Quicktime, render_template: dpx_shot_render}

Using QT inside your Toolkit App

You can use QT classes inside your app code. Sgtk will handle the import and gracefully manage different platform considerations in the background. Typically, PySide is being used for QT integration, but Sgtk may use PyQT in certain engines. Normally, the code is pretty portable between the two systems and it should be no problem writing code that works with both libraries.

In order to use QT, import it from Sgtk:

from sgtk.platform.qt import QtCore, QtGui

Toolkit will make sure Qt is sourced in the correct way. Keep in mind that many applications (for example Nuke) may not have a functional Qt that can be imported when they run in batch mode.

Using QT 5 inside your Toolkit App

When running in an environment with PySide 2 , Toolkit will provide under sgtk.platform.qt an emulation layer that mimics the PySide 1 API on top of PySide 2 so that your Toolkit applications don’t need to be updated to work in those environments. If you need straight access to the PySide 2 API, you can access it through the sgtk.platform.qt5 module. Detecting the availability of Qt 5 can be done through Engine.has_qt5().

Warning

The PySide 1 emulation layer for PySide 2 may be missing some features. It provides enough coverage to run the officially supported Toolkit applications. If you find that something in the PySide 1 emulation layer is not working or missing, please contact support@shotgunsoftware.com so that we may update it.

To learn more about API discrepancies between Qt 4 and Qt 5, you can visit https://wiki.qt.io/Transition_from_Qt_4.x_to_Qt5.

Creating Dialogs

When creating a dialog, it is important to parent it properly to the host environment. There is nothing stopping you from managing this by yourself, but for maximum compatibility and portabilty, we strongly suggest that you l et Toolkit handle it. When using Sgtk to set up your UI, just let your UI class derive from QtGui.QWidget and pass it to one of the UI factory methods that the engine has. For example:

from sgtk.platform.qt import QtCore, QtGui

# derive from QtGui.QWidget for your UI components.

class AppDialog(QtGui.QWidget):

    def __init__(self, param1, param2):
        QtGui.QWidget.__init__(self)

# the engine is then used to correctly launch this dialog. In your app code
# you can now do create a window using the engine's factory methods.

# display widget in a modeless window:
widget_obj = self.engine.show_dialog("Dialog Title", self, AppDialog, param1, param2)

# display widget in a modal dialog - blocking call
(return_code, widget_obj) = self.engine.show_modal("Dialog Title", self, AppDialog, param1, param2)

What happens in the above calls is that your app widget is parented inside of a Dialog window Sgtk is creating. Sgtk will add additional potential window constructs, menus etc. Whenever the app widget is closed (for example using the close() method), the parent window that is used to wrap the widget will automatically close too.

Hiding the default Toolkit title bar

By default, the standard Toolkit UI dialog includes a title bar at the top. However, sometimes this is not desirable, especially when the contained widget is quite small. To hide the title bar, just add a property called hide_tk_title_bar to your widget class and set it to a value of True, for example:

class MyWidget(QtGui.QWidget):

    @property
    def hide_tk_title_bar(self):
        return True

    def __init__(self):
        ...

Styling your Toolkit App

If a standard Qt style sheet style.qss file resides in the root of your app, Toolkit will automatically load it and apply it to your app.

When developping your app, you can enable interactive styling by setting the SHOTGUN_QSS_FILE_WATCHER environment variable to 1. Toolkit will automatically reload and re-apply the styling when the file is changed.

Note

The style sheet file watching can be helpful when developping apps, but shouldn’t be used in production.