sgtk
パブリッシャーとかのappを簡易的に使いたい:
tk-toolchainを利用する
- tk-toolchainにパスを通す
- tk-coreにもパスを通す
- 環境変数
SGTK_PYSIDE6_PATCH_METHOD
をNONEにする - TK_TOOLCHAIN_HOST、TK_TOOLCHAIN_SCRIPT_NAME、TK_TOOLCHAIN_SCRIPT_KEYを指定
- デバッグしたい場合は
TK_DEBUG
を1に - tk-run-appをオプションつけて実行
7.--location
にtk-multi-publish2の場所を指定
8. --context-entity-type、--context-entity-idを指定
toolchainの中には独自のengineとconfigが含まれてる
engine:
config:このコンフィグでは core として
$SHOTGUN_REPOS_ROOT/tk-core
を指定しつつ、pick envでは
return "test"
かならずテスト環境を返している
で、envのtestは下記
tk-multi-run-this-app
によって、実体はなんであれ渡されたappを実行
Descriptor type :baked の活用
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)が動作するために必要な全てのフォルダ構造とファイルが事前に用意された状態を指している模様
tk-docs/tk-core/python/tank/bootstrap/baked_configuration.py で処理されていて、この中の bake_config_scaffold メソッドを使うとベイクされたコンフィグを作ることもできる。
さらにその実用として tk-docs/tk-core/developer/build_plugin.py の build_plugin 関数を利用することもできる。
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"
}
/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
/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"
shotgun api にはduplicateメソッドがないというスレッド
ここで挙げられている対応として
- フィールドを取得
- フィールドの編集可能・不可能を判断
- 複製元(ソース)に対して、編集可能フィールドのみの情報を得る
- 編集可能情報を付与して
create
フィールド情報の取得には .schema_field_read()
を使う
# 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
一括入力時にはbatch
batch_data = [
{"request_type": "create", "entity_type": "Shot", "data": {...}},
...
...
]
sg.batch(batch_data)
サムネイルに関するフィールドはエラーになるので、 share_thumbnail
を使う
これだとバッチを使った後にforでまわすことになりそうなので、時間かかりそう
バージョンと関連づけられている場合はそのサムネがくる
関連づけられたバージョンやタスクは元エンティティと同じようにリンクされるけど
そのせいで、batchでcreateされたエンティティを消すとそれらもまとめて消える。
タスクのentityフィールドはシングルなので、この操作をした時点で書き変わってしまう
タスクも対象にするならタスクも複製する処理を用意する。または、タスクは除外する。
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': []}
あるエンティティの内容をプロジェクト間で複製
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フィールドへの補償を特にしなければこんな感じ
もしかして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')なのが相場なので、それ以外が入っていたらあるいは、という感じだけど。。。
['data_type']['value']がcalculated、summary、pivot_columnは除外、みたいにするのがいいのかな
ちなみに値取れないフィールドでも、Noneが帰ってくるだけで、エラーを発生させてくれるとかではないみたい
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'が入っていないということでエラー
'custom_metadata' に辞書っぽく記入しておくと schema_field_read で取得はできる。
でも文字列として返ってくる
>>> metadata = field_info[some_field]['custom_metadata']['value']
>>> type(metadata)
# Results: <class 'str'>
- フィールドには任意にフィールドを足せない
- その代わり、custom_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}
import ast
meta = data[field_name]['custom_metadata']['value']
meta = ast.literal_eval(meta)
meta['a']
# Results:
# 123
まずまず面倒なような