Open23

sgtk

h_kishimotoh_kishimoto
  1. tk-toolchainにパスを通す
  2. tk-coreにもパスを通す
  3. 環境変数SGTK_PYSIDE6_PATCH_METHODをNONEにする
  4. TK_TOOLCHAIN_HOST、TK_TOOLCHAIN_SCRIPT_NAME、TK_TOOLCHAIN_SCRIPT_KEYを指定
  5. デバッグしたい場合は TK_DEBUG を1に
  6. tk-run-appをオプションつけて実行
    7. --location にtk-multi-publish2の場所を指定
    8. --context-entity-type、--context-entity-idを指定
h_kishimotoh_kishimoto

Descriptor type :baked の活用

https://developers.shotgridsoftware.com/tk-core/descriptor.html#descriptor-types

Descriptor typesとしては、最も一般的なapp_storeやpath/devなどの他にもいくつかのタイプがあるが、
公式ドキュメントではtypeに含まれない形でうっすら言及されている「baked」pipeline configuration がある。
tk-core/python/tank/bootstrap/resolver.py の resolve_configuration メソッドのコメントによると、

# special case -- this is a full configuration scaffold that
# has been pre-baked and can be used directly at runtime
# without having to do lots of copying into temp space.
(特殊なケース - これは、事前に準備された完全な構成スキャフォールドであり、一時領域に大量のコピーを行うことなく実行時に直接使用できます。)

Toolkit(tk-core)が動作するために必要な全てのフォルダ構造とファイルが事前に用意された状態を指している模様

h_kishimotoh_kishimoto

tk-docs/tk-core/python/tank/bootstrap/baked_configuration.py で処理されていて、この中の bake_config_scaffold メソッドを使うとベイクされたコンフィグを作ることもできる。
さらにその実用として tk-docs/tk-core/developer/build_plugin.py の build_plugin 関数を利用することもできる。

h_kishimotoh_kishimoto

bundle_cacheフォルダ直下はapp_storeなどDescriptorタイプのフォルダが置かれる階層。
ここにbakedフォルダを設置し、さらに「コンフィグ名」「コンフィグのバージョン」といった階層構造を組み、
その下に「config」フォルダを含む設定ファイル群を設置する。

bundle_cache/
  └── baked/
      └── {name]/
          └── {version}/
              ├── config/
              │   ├── core/
              │   │   ├── hooks/
              │   │   ├── install_location.yml
              │   │   ├── pipeline_configuration.yml
              │   │   └── shotgun.yml
              │   ├── env/
              │   ├── hooks/
              │   └── ...
              ├── install/
              │   └── core/
              └── tank

フォルダ名は「BAKED_DESCRIPTOR_FOLDER_NAME」環境変数で指定可能
core以下のymlファイル名は「PIPELINECONFIG_FILE」「CONFIG_SHOTGUN_FILE」「CONFIG_CORE_DESCRIPTOR_FILE」で指定可能

baked descriptorは次のように指定する

baked_example = {
    "type": "baked",
    "name": "config",
    "version": "v0.0.0"
}
h_kishimotoh_kishimoto

/tank/descriptor/constants.py の確認。
app_store で使われているカスタムエンティティ:

TANK_CORE_VERSION = CustomNonProjectEntity01
TANK_CODE_PAYLOAD_FIELD = "sg_payload"

TANK_CONFIG = CustomNonProjectEntity07
TANK_CONFIG_VERSION = CustomNonProjectEntity08

TANK_APP = CustomNonProjectEntity02
TANK_APP_VERSION = CustomNonProjectEntity05

TANK_ENGINE = CustomNonProjectEntity03
TANK_ENGINE_VERSION = CustomNonProjectEntity04

TANK_FRAMEWORK = CustomNonProjectEntity13
TANK_FRAMEWORK_VERSION = CustomNonProjectEntity09

app_store にアクセスするのを止める環境変数もある
SHOTGUN_DISABLE_APPSTORE_ACCESS
h_kishimotoh_kishimoto

/tank/constants.py

# パイプラインコンフィグのパス代替
PIPELINE_CONFIG_DESCRIPTOR_TOKEN = "{PIPELINE_CONFIG}"

# パイプラインコンフィグの「configフォルダへの」パス代替
CONFIG_FOLDER_DESCRIPTOR_TOKEN = "{CONFIG_FOLDER}"

これらは「path」「dev」ディスクリプターの時に有効。
/tank/pipelineconfig.py の_preprocess_descriptor関数で処理される。
{PIPELINE_CONFIG} はget_path関数で処理されるが、これはPipelineConfigurationオブジェクトを取得する際の引数 pipeline_configuration_path をそのまま返す
当該オブジェクトについての注意書き:

"""
このオブジェクトを構築するには、pipelineconfig_factory のファクトリ メソッドを使用します。
コンストラクター経由で直接作成しないでください。
"""
# ※ /tank/pipelineconfig_factory.py

"""
OS レベルでシンボリックリンクの設定がどのように処理されるかに関係なく、
pipeline_configuration_path には常に FlowPT に登録されたパスが設定されます。
"""

"""
descriptor 引数: このパイプラインコンフィグの作成に使用されたdescriptorです。
1つの引数のみを渡すBootstrapperとの後方互換性を保つため、デフォルトでは「None」に設定されています。
また、この引数はv0.18.72から0.18.94までのコアによっても渡されていました。
このdescriptorは、pipeline_configuration.yml内のディスクから読み込まれるようになりました。
"""

"""
「PIPELINE_CONFIG」はパイプライン設定のルートを指します。
キャッシュまたはベイクされたパイプライン設定の場合、すべての環境ファイルとフックファイルを含む「config」フォルダは含まれません。
「config」フォルダ内の要素を参照し、インストール済み、ベイク済み、キャッシュ済みのいずれの設定でも設定を使用したい場合は、
「CONFIG_FOLDER」トークンを使用することをお勧めします。
"""
# https://developers.shotgridsoftware.com/tk-core/descriptor.html#pointing-to-a-path-on-disk

基本的には {CONFIG_FOLDER} が推奨とみられる

テンプレート関連

# キーに使える文字とその説明
TEMPLATE_KEY_NAME_REGEX = r"[a-zA-Z_ 0-9\.]+"
VALID_TEMPLATE_KEY_NAME_DESC = "letters, numbers, underscore, space and period"

# テンプレート内のセクション
TEMPLATE_SECTIONS = ["keys", "paths", "strings"]

# どのセクションが「テンプレートパス」か
TEMPLATE_PATH_SECTION = "paths"

# どのセクションが「ストリングス」か
TEMPLATE_STRING_SECTION = "strings"
h_kishimotoh_kishimoto

shotgun api にはduplicateメソッドがないというスレッド
https://community.shotgridsoftware.com/t/duplicate-an-entity-via-python-api/10583

ここで挙げられている対応として

  • フィールドを取得
  • フィールドの編集可能・不可能を判断
  • 複製元(ソース)に対して、編集可能フィールドのみの情報を得る
  • 編集可能情報を付与して create

フィールド情報の取得には .schema_field_read() を使う
https://developers.shotgridsoftware.com/python-api/reference.html#shotgun_api3.shotgun.Shotgun.schema_field_read

h_kishimotoh_kishimoto
# Asset フィールドを調べる例
field_info = shotgun.schema_field_read('Asset')
target_field = [ k for k,v in field_info.items()]
len(target_field)
# Results:  51

target_field = [ k for k,v in field_info.items() if v['editable']['value'] == True ]
len(target_field)
# Results:  31
h_kishimotoh_kishimoto

サムネイルに関するフィールドはエラーになるので、 share_thumbnail を使う
https://developers.shotgridsoftware.com/python-api/reference.html#shotgun_api3.shotgun.Shotgun.share_thumbnail
これだとバッチを使った後にforでまわすことになりそうなので、時間かかりそう

バージョンと関連づけられている場合はそのサムネがくる

h_kishimotoh_kishimoto

関連づけられたバージョンやタスクは元エンティティと同じようにリンクされるけど
そのせいで、batchでcreateされたエンティティを消すとそれらもまとめて消える。

h_kishimotoh_kishimoto

タスクのentityフィールドはシングルなので、この操作をした時点で書き変わってしまう
タスクも対象にするならタスクも複製する処理を用意する。または、タスクは除外する。

h_kishimotoh_kishimoto

assetの全フィールドの値を取る

field_info = shotgun.schema_field_read('Asset')
asset_info = shotgun.find_one('Asset',[],list(field_info.keys()))

# Results:
#  {'type': 'Asset', 'id': 1226, 'mocap_takes': [], 'task_template': None, 'step_0': None, 'addressings_cc': [], 'cached_display_name': 'Alice', 'filmstrip_image': None, 'image_blur_hash': None,
...
'notes': [], 'open_notes': [], 'open_notes_count': 0, 'scenes': [], 'blendshapes': [], 'shoot_days': [], 'elements': []}
h_kishimotoh_kishimoto

あるエンティティの内容をプロジェクト間で複製

target_entity = 'CustomEntity000'
src_id = 999
dst_id = 777

field_info = shotgun.schema_field_read(target_entity)
target_field = [ k for k,v in field_info.items() if v['editable']['value'] == True ]

src = shotgun.find(target_entity,[['project','is',{'type':'Project','id':src_id}]],target_field)
batch_data = []
for entity in src:
    data = { k:v for k,v in entity.items() if k in target_field if v!=[] and v!=''}
    data['project'] = {'type':'Project','id':dst_id}
    batch_data.append( {"request_type": "create", "entity_type": target_entity, "data":data } )

shotgun.batch(batch_data)

サムネやentityフィールドへの補償を特にしなければこんな感じ

h_kishimotoh_kishimoto

もしかしてapiから値取れないフィールドって判定する方法が無い?

field_info = shotgun.schema_field_read('Asset')
for field,val in field_info.items():
    print(field,val['data_type']['value'],val['editable']['value'],val['properties'].keys())

mocap_takes multi_entity True dict_keys(['default_value', 'summary_default', 'valid_types'])
task_template entity True dict_keys(['default_value', 'summary_default', 'valid_types'])
step_0 pivot_column False dict_keys(['default_value', 'summary_default'])
...
scenes multi_entity True dict_keys(['default_value', 'summary_default', 'valid_types'])
blendshapes multi_entity True dict_keys(['default_value', 'summary_default', 'valid_types'])
shoot_days multi_entity True dict_keys(['default_value', 'summary_default', 'valid_types'])
elements multi_entity True dict_keys(['default_value', 'summary_default', 'valid_types'])

一応、ほとんどのフィールドはpropertiesが'default_value', 'summary_default'のみ(あとは'valid_types')なのが相場なので、それ以外が入っていたらあるいは、という感じだけど。。。

h_kishimotoh_kishimoto

ちなみに値取れないフィールドでも、Noneが帰ってくるだけで、エラーを発生させてくれるとかではないみたい

h_kishimotoh_kishimoto

Fieldエンティティは内部的には 'DisplayColumn' だけど、findできない。

>>> item = shotgun.find_one('DisplayColumn',[])
Traceback (most recent call last):
  File ".../shotgun_api3/shotgun.py", line 961, in find_one
    results = self.find(
              ^^^^^^^^^^
  File ".../shotgun_api3/shotgun.py", line 1142, in find
    records = self._call_rpc("read", params).get("entities", [])
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
  File ".../shotgun_api3/shotgun.py", line 3758, in _call_rpc
    self._response_errors(response)
  File ".../shotgun_api3/shotgun.py", line 4103, in _response_errors
    raise Fault(sg_response.get("message", "Unknown Error"))
tank_vendor.shotgun_api3.shotgun.Fault: API read() invalid/missing string entity 'type':
{"type" => "DisplayColumn",
 "return_fields" => ["id"],
 "filters" => {"logical_operator" => "and", "conditions" => []},
 "return_only" => "active",
 "paging" => {"entities_per_page" => 1, "current_page" => 1},
 "api_return_image_urls" => true,
 "return_paging_info_without_counts" => false}
Valid entity types:
["ActionMenuItem",
 "ApiUser",
...

Valid entity types: の中に'DisplayColumn'が入っていないということでエラー

h_kishimotoh_kishimoto

'custom_metadata' に辞書っぽく記入しておくと schema_field_read で取得はできる。
でも文字列として返ってくる

>>> metadata = field_info[some_field]['custom_metadata']['value']
>>> type(metadata)
# Results:  <class 'str'>
h_kishimotoh_kishimoto
  • フィールドには任意にフィールドを足せない
  • その代わり、custom_metadataフィールドがある。

ということで、おそらく正しいお作法はこう

辞書をmetadataとして記入
data = str({'a':123,'b':456})
properties = {'custom_metadata':data}
shotgun.schema_field_update('Asset','description',properties)
# Results:
#  True
取り出す(この時点では文字列)
field_name = 'description'
data = shotgun.schema_field_read('Asset',field_name)
data[field_name]['custom_metadata']['value']
# Results:
#  {'a': 123, 'b': 456}
astモジュールで文字列から辞書化して使う
import ast
meta = data[field_name]['custom_metadata']['value']
meta = ast.literal_eval(meta)
meta['a']
# Results:
#  123

まずまず面倒なような