Skip to content

Plugin

Looking for?

  • The design principles behind plugins, check guide.
  • A complete reference for plugins classes, App, Tracker, Host and Submiter, check the SDK.
  • How to set up your environment for plugin development, check the development.
  • How to manage plugins in your instance, check the TD documentation.

Introduction

A Bip plugin must follow some rules in order to be validated at registration. This page describes these rules extensively.

Bip plugins also have many optional features, from integration to remote execution. The page also list and details how to use these features.

Tip

Check the Chocolatine plugin, a demo Bip application which illustrates practically the main information given in this page.

Guidelines

Bip relies on Git features to inspect and update a plugin. Therefore, a plugin must be a valid and public (or at least reachable from your production Bip instance) repository.

Danger

If the guidelines regarding repository structure, tag naming and changelog formatting are not strictly followed, some Bip inspection procedures might not succeed and the plugin might not work properly.

Repository

For a repository to be read as a valid Bip plugin at registration, it must at least contain the following elements:

  • my_plugin/: Repository root
  • my_plugin/: Package root (named the same as the repository root)
  • bip.yml: Plugin descriptor
  • CHANGELOG.md: Changelog file
  • pyproject.toml: Python descriptor

In addition to that mandatory structure, it is recommended to respect the following convention:

  • my_plugin/: Repository root
  • my_plugin/: Package root (named the same as the repository root)
  • assets/: Stylesheets, icons, graphic elements...
    • stylesheet.ink: Main stylesheet
  • dev/: Development scripts
  • integrations/: Bip batches for integration
  • resources/: Deployment scripts, integration utils...
  • bip.yml: Plugin descriptor
  • CHANGELOG.md: Changelog file
  • pyproject.toml: Python descriptor
  • README.md: Readme file

Git tags

The repository tags are used for upgrading or downgrading a plugin version. Any non SemVer version is ignored. The tags must therefore respect the Semantic Versioning convention. Version number prefix "v" is allowed.

Changelogs

For the changelog to be parsed by the API (mink.changelog), it must follow the following rules:

  • Be written in Markdown.
  • Be named CHANGELOG.md.
  • Follow the Keep a changelog structure.
  • Respect the Semantic Versioning convention.
  • Reference the related tickets as much as possible.
  • Level-two (h2) headings must exactly follow this structure: [x.x.x] - YYYY-MM-DD except for changes made before the release of a new tag. In that case, the title can be X.X.X - [unreleased]
  • Level-three (h3) headings can only be:
    • Added
    • Changed
    • Fixed
    • Removed
    • Deprecated
    • Security
  • Version number prefix "v" is allowed.

Here is a minimalist example:

# Changelog

All notable changes to this project will be documented in this file.

## 1.0.2 - [unreleased]

### Removed

- Something removed (#548)

## [1.0.1] - 2023-03-05

### Added

- Something added (#842)

### Fixed

- Something fixed (#744)

## [1.0.0] - 2022-10-04

### Added

- Something added (#842)

[unreleased]: https://codebase.ext/my-repo/releases/compare/v1.0.1...HEAD
[1.0.1]: https://codebase.ext/my-repo/releases/compare/v1.0.0...v1.0.1
[1.0.0]: https://codebase.ext/my-repo/releases/tag/v1.0.0

Applications

Structure

For applications, there is no mandatory structure, since the entry point is defined by the developer themselves in the integration batches. Although, we suggest the following structure, or base structure:

  • my_plugin/my_plugin/:
  • __init__.py
  • api.py or api/
  • ui.py or ui/
  • app.py (conventional entry point)
__init__.py

We suggest using this snippet:

from pathlib import Path
import toml


here = Path(__file__).parent
package_root = here.parent
assets = package_root / "assets"
stylesheet = assets / "stylesheet.ink"  # For apps
pyproject_path = package_root / "pyproject.toml"
pyproject = toml.load(str(pyproject_path))
__version__ = pyproject["project"]["version"]
app.py

If there is no reason not to, we suggest running the application (if standalone) from app.py:

from bip.sdk import App, run
from my_app.ui import Window
from my_app import api, stylesheet, __version__


class MyApp(App):
    slug = "my_app"
    version = __version__

    def __init__(self, *args, **kwargs):
        super().__init__(*args, stylesheet=stylesheet, **kwargs)
        self.widget = Window(self)
        self.set_widget(self.widget)

if __name__ == "__main__":
    app = run(MyApp)

Styling

The following keywords can be used in your stylesheet:

  • @app: Path to the root directory of your application plugin.
  • @main-color: Bip main color (#edc03b).
  • @quiet-color: Bip secondary color (#b29c08).
  • @ui: Path to the client assets/ui directory.
  • @icons: Path to the client assets/logo directory.

Handlers

Structure

Handlers are expected to provide a handler.py entry point.

  • my_plugin/my_plugin/:
  • __init__.py
  • handler.py (mandatory entry point)
handler.py

The entry point is where the plugin class is created (but not initialized, since it is done in due time by the API getters (mink.plugins))

from bip.sdk import Host


class MyHost(Host):
    # Override all the methods that are expected to be overriden
    pass

Descriptor

The descriptor bip.yml is expected to be found at the repository root.

General

Mandatory

  • name (str): Plugin name.
  • slug (str): Plugin slug (no special characters allowed).
  • type (str): Plugin type, handler or application.
  • api_version (str): Minimal Bip client version compatible.
  • handler_type (str): Handlers only - Handler type, host, submitter or tracker.
  • product (str): Handlers only - Wrapped product, maya, shotgrid, deadline...
  • scope (str): Applications only - Application scope, global or project.

Optional

  • descriptive_name (str): Functional name.
  • description (str): One or two sentences description of what the plugin does.
  • author (str): Name of the maintainer(s).
  • supported_models (list): Forbidden for global applications - If specified, the Plugin would not launch if the current user's active project model is not listed.
  • integrations (list): Forbidden for handlers - List of available integrations (see the Integrations section).
  • dependencies (dict): Forbidden for global applications - Required Bip plugins (see the Dependencies section).
  • mapping (dict): Forbidden for global applications - Mapped entities (see the Mapping section).
  • dynamic_mapping (dict): Forbidden for global applications - Mapped entities (see the Mapping section).
  • config (dict): Global plugin settings (see the Config section).
  • settings (dict): User plugin settings (see the Settings section).

Integrations

Info

Read the general Integrations section to learn more about integrations. This section here only describes how to define them in the descriptor.

You must provide a list of available integrations that the administrator who manages your plugin will choose to enable.

It is not expected that all the integrations listed here have their matching batch(es) in the integrations/ directory. You might have an integration that does not require any batch, since the application's root will anyway be added to the PYTHONPATH when a DCC matching a name in that list is started (if the administrator did enable the integration).

  • If the application accepts the standalone context, add bip to the list.
  • If the application accepts the hosted or remote context, add the product name of the host to the list.

Settings, config and mappings

  • The settings section of the descriptor allows to define the user settings. Those settings will be generated with their default value for all existing users when the Plugin is enabled and each time a new user is created.
  • The config section of the descriptor allows to define the global configuration. It is usually set by the administrator, and is unique to the scope (if the scope is project, the config values are only for the project for which the application is enabled).
  • The mapping section of the descriptor allows to map a Bip entity with an application concept. Since Bip is data-agnostic, each project can have different data models. But some applications might need to ask the administrator/TD "in this project's data structure, what ComponentModel corresponds to what I internally call a "scene"?", or "what ItemModel corresponds to what I internally call an "asset"?"
  • The dynamic mapping section of the descriptor allows to map multiple Bip data entities with application concepts. Since Bip is data-agnostic, each project can have different data models. But some applications might need to ask the administrator "in this project's data structure, can you associated each ComponentTag with a value". This is useful for example for matching entities between Bip and a production tracker (like Shotgrid: "can you associated each ItemTag with its Shotgrid id").

Each entry must be named by its slug name. Here are the accepted fields:

  • name (str): Parameter name.
  • type (str): Parameter type.
    • Settings accepted values are str, bool, int, list.
    • Config accepted values are str, bool, int, list.
    • Mapping and Dynamic Mapping accepted values are DocumentModel, ItemModel, GroupModel, TaskModel.
  • default (depends on "type"): Default value. (If choices are defined, the default must be one of the choice values).
  • sub_type (mandatory if type is list): List item type. Accepted values are str, bool, int.
  • choices (dict) - optional: If you want to restrict choices, provide a dictionary of pairs of slugs and display names.
  • description (str) - optional: Detailed description of the parameter. (Forbidden for dynamic_mapping)
  • category (str) - optional: If you want the UI to group parameters, give them the same category value. (Forbidden for dynamic_mapping)
  • optional (str) - optional: If true, the user is not forced to specify this value, and it is set to None. Default is False. (Forbidden for dynamic_mapping)

Example

name: Chocolatine
slug: chocolatine
type: application
scope: project
descriptive_name: Demo
description: Bip application demo.
author: Blink
api_version: 4.0.1
integrations:
    - maya
    - blender
    - after-effects
    - photoshop
    - bip
settings:
    string_setting:
        name: String user setting
        type: str
        default: "Hello world"
    bool_setting:
        name: Bool user setting
        description: Example of a boolean user setting.
        type: bool
        default: true
config:
    list_config:
        name: List config
        description: Example of a list of string config.
        type: str
        choices:
            choice1: First choice
            choice2: Second choice
        default: choice1
mapping:
    document:
        name: Document model mapping
        description: Example of an entity mapping.
        type: DocumentModel
        default: scene
dynamic_mapping:
    items:
        name: Item model dynamic mapping
        description: Example of an entity dynamic mapping.
        type: ItemModel

Integrations

Warning

Integrations are for Applications only.

Integrations are how an application is started by the launcher entry point (Brioche by default). They must be enabled in the plugin settings.

The way Bip has chosen to describe how to start a program in the most customizable fashion is to use JeanPaulStart, which allows to write Yaml batches with instruction sequences.

For describing what needs to be done when the user starts your application, you must write a batch file.

Tip

There are two different launching scenarii: - Standalone: The application is started from the launcher application. - Hosted: The application is started from a DCC (host) which have been started from the launcher.

Standalone

If you add a bip.yml batch in the integrations/ directory at the root of your application repository, the batch API (mink.batches) will find it, and it will be listed in the launcher batch list.

If your application has several standalone batches, for example in the case when an application can be started in different modes or views, you can create a integrations/bip/ directory in which you can add as many batches as you want.

Examples

---
uid: chocolatine
name: Chocolatine
description: 'Bip application demo'
icon_path: null
os:
  - Windows
tags:
  - Bip
tasks:
  - name: Running application
    raw:
      command: python "$BIP_APPS/chocolatine/chocolatine/app.py"
...
You can also check the Clafoutis integrations directory for multi-standalone batches examples.

Hosted/Remote

By default, the root of the plugin is added to the PYTHONPATH by the batch API when the user launches a DCC batch which host name matches the integration listed in the bip.yml. In most cases, that is enough. But in some cases, you might want to copy some files to the DCC's special folders or preload some scripts.

If your application must be loaded or preloaded when the DCC is started, you can add in the integrations/ a batch file named after the DCC product name. Then this batch will be executed at the beginning of any user batch which has the host parameter set to the same value. For example, if your content has a maya-2023.yml batch with host set as maya, add a maya.yml in your integrations/ directory.

Info

Not all cases require an integration for the host, even if the application is meant to be executed from a host. In the following examples, these are applications that need to be silently preloaded when the DCC starts, because they are slow applications. If your application doesn't need that, you can simply provide a snippet in your README explaining how to call your application, and then it is up to the administrator to integrate your application in their various custom menus or toolbars.

Examples

Example from Kouglof, which has a hosted integration for Maya.

---
name: Maya
icon_path: $BIP_CONTENT/assets/icons/maya.png
tags:
  - Handler
tasks:
  - name: Add Kouglof to Python environment
    environment:
      name: PYTHONPATH
      value: $BIP_APPS/kouglof/resources/maya
      append: true
...

Example from Kouglof, which has a remote integration for Photoshop.

---
name: Photoshop
icon_path: $BIP_CONTENT/assets/icons/photoshop.png
tags:
  - Handler
tasks:
  - name: Preload Kouglof
    raw:
      command: python "$BIP_APPS/kouglof/kouglof/loader.py" --context remote
...

Mixed

An application can have all kind of integration batches at the same time depending on the contexts it supports (see the supported_contexts class attribute)

Updates

What happens when a plugin is updated (config, api version....)

Running

Production

  • Application: Ran using sdk.runner (managed by the developer)
  • Handler: Ran using mink.plugin (managed internally by the API)
  • Tracker (WIP): Automatically initialized and attached to the Application when the project has a tracker enabled.
  • Submitter (WIP): Automatically initialized and attached to the Application when the project has a submitter enabled.
  • Host: Automatically initialized and attached to the Application when the context is HOSTED or REMOTE.

Application

Since there are often many different ways to execute a single application, it is left to the discretion of the developer to chose how to initialize the application.

A very typical case could be to have the main foo/foo/app.py:

class Foo(App):
    slug = "foo"


if __name__ == "__main__":
    app = run(Foo)

And a corresponding standalone integration batch would simply be:

---
uid: foo
name: Foo
icon_path: null
tasks:
  - name: Running application
    raw:
      command: python "$BIP_APPS/foo/foo/app.py"
...

Development

See the related documentation to know how to run a plugin in a development context.