Merge branch 'develop' into bugfix/OP-3520_Nuke-double-slate
8
.gitmodules
vendored
|
|
@ -1,7 +1,7 @@
|
|||
[submodule "vendor/powershell/BurntToast"]
|
||||
path = vendor/powershell/BurntToast
|
||||
[submodule "tools/modules/powershell/BurntToast"]
|
||||
path = tools/modules/powershell/BurntToast
|
||||
url = https://github.com/Windos/BurntToast.git
|
||||
|
||||
[submodule "vendor/powershell/PSWriteColor"]
|
||||
path = vendor/powershell/PSWriteColor
|
||||
[submodule "tools/modules/powershell/PSWriteColor"]
|
||||
path = tools/modules/powershell/PSWriteColor
|
||||
url = https://github.com/EvotecIT/PSWriteColor.git
|
||||
|
|
|
|||
67
CHANGELOG.md
|
|
@ -1,8 +1,42 @@
|
|||
# Changelog
|
||||
|
||||
## [3.12.2-nightly.2](https://github.com/pypeclub/OpenPype/tree/HEAD)
|
||||
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.12.1...HEAD)
|
||||
|
||||
**🚀 Enhancements**
|
||||
|
||||
- General: Interactive console in cli [\#3526](https://github.com/pypeclub/OpenPype/pull/3526)
|
||||
- Ftrack: Automatic daily review session creation can define trigger hour [\#3516](https://github.com/pypeclub/OpenPype/pull/3516)
|
||||
- Ftrack: add source into Note [\#3509](https://github.com/pypeclub/OpenPype/pull/3509)
|
||||
- Ftrack: Trigger custom ftrack topic of project structure creation [\#3506](https://github.com/pypeclub/OpenPype/pull/3506)
|
||||
- Settings UI: Add extract to file action on project view [\#3505](https://github.com/pypeclub/OpenPype/pull/3505)
|
||||
- Add pack and unpack convenience scripts [\#3502](https://github.com/pypeclub/OpenPype/pull/3502)
|
||||
- General: Event system [\#3499](https://github.com/pypeclub/OpenPype/pull/3499)
|
||||
- NewPublisher: Keep plugins with mismatch target in report [\#3498](https://github.com/pypeclub/OpenPype/pull/3498)
|
||||
- Nuke: load clip with options from settings [\#3497](https://github.com/pypeclub/OpenPype/pull/3497)
|
||||
- TrayPublisher: implemented render\_mov\_batch [\#3486](https://github.com/pypeclub/OpenPype/pull/3486)
|
||||
- Migrate basic families to the new Tray Publisher [\#3469](https://github.com/pypeclub/OpenPype/pull/3469)
|
||||
|
||||
**🐛 Bug fixes**
|
||||
|
||||
- Additional fixes for powershell scripts [\#3525](https://github.com/pypeclub/OpenPype/pull/3525)
|
||||
- Maya: Added wrapper around cmds.setAttr [\#3523](https://github.com/pypeclub/OpenPype/pull/3523)
|
||||
- General: Fix hash of centos oiio archive [\#3519](https://github.com/pypeclub/OpenPype/pull/3519)
|
||||
- Maya: Renderman display output fix [\#3514](https://github.com/pypeclub/OpenPype/pull/3514)
|
||||
- TrayPublisher: Simple creation enhancements and fixes [\#3513](https://github.com/pypeclub/OpenPype/pull/3513)
|
||||
- NewPublisher: Publish attributes are properly collected [\#3510](https://github.com/pypeclub/OpenPype/pull/3510)
|
||||
- TrayPublisher: Make sure host name is filled [\#3504](https://github.com/pypeclub/OpenPype/pull/3504)
|
||||
- NewPublisher: Groups work and enum multivalue [\#3501](https://github.com/pypeclub/OpenPype/pull/3501)
|
||||
|
||||
**🔀 Refactored code**
|
||||
|
||||
- General: Client docstrings cleanup [\#3529](https://github.com/pypeclub/OpenPype/pull/3529)
|
||||
- TimersManager: Use query functions [\#3495](https://github.com/pypeclub/OpenPype/pull/3495)
|
||||
|
||||
## [3.12.1](https://github.com/pypeclub/OpenPype/tree/3.12.1) (2022-07-13)
|
||||
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.12.0...3.12.1)
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.12.1-nightly.6...3.12.1)
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
|
|
@ -24,7 +58,6 @@
|
|||
- Blender: Bugfix - Set fps properly on open [\#3426](https://github.com/pypeclub/OpenPype/pull/3426)
|
||||
- Hiero: Add custom scripts menu [\#3425](https://github.com/pypeclub/OpenPype/pull/3425)
|
||||
- Blender: pre pyside install for all platforms [\#3400](https://github.com/pypeclub/OpenPype/pull/3400)
|
||||
- Maya: Add additional playblast options to review Extractor. [\#3384](https://github.com/pypeclub/OpenPype/pull/3384)
|
||||
|
||||
**🐛 Bug fixes**
|
||||
|
||||
|
|
@ -44,9 +77,6 @@
|
|||
- Maya: fix hashing in Python 3 for tile rendering [\#3447](https://github.com/pypeclub/OpenPype/pull/3447)
|
||||
- LogViewer: Escape html characters in log message [\#3443](https://github.com/pypeclub/OpenPype/pull/3443)
|
||||
- Nuke: Slate frame is integrated [\#3427](https://github.com/pypeclub/OpenPype/pull/3427)
|
||||
- Maya: Camera extra data - additional fix for \#3304 [\#3386](https://github.com/pypeclub/OpenPype/pull/3386)
|
||||
- Maya: Handle excluding `model` family from frame range validator. [\#3370](https://github.com/pypeclub/OpenPype/pull/3370)
|
||||
- Harmony: audio validator has wrong logic [\#3364](https://github.com/pypeclub/OpenPype/pull/3364)
|
||||
|
||||
**🔀 Refactored code**
|
||||
|
||||
|
|
@ -60,8 +90,6 @@
|
|||
- General: Move publish plugin and publish render abstractions [\#3442](https://github.com/pypeclub/OpenPype/pull/3442)
|
||||
- General: Use Anatomy after move to pipeline [\#3436](https://github.com/pypeclub/OpenPype/pull/3436)
|
||||
- General: Anatomy moved to pipeline [\#3435](https://github.com/pypeclub/OpenPype/pull/3435)
|
||||
- Fusion: Use client query functions [\#3380](https://github.com/pypeclub/OpenPype/pull/3380)
|
||||
- Resolve: Use client query functions [\#3379](https://github.com/pypeclub/OpenPype/pull/3379)
|
||||
|
||||
## [3.12.0](https://github.com/pypeclub/OpenPype/tree/3.12.0) (2022-06-28)
|
||||
|
||||
|
|
@ -76,7 +104,6 @@
|
|||
|
||||
- Webserver: Added CORS middleware [\#3422](https://github.com/pypeclub/OpenPype/pull/3422)
|
||||
- Attribute Defs UI: Files widget show what is allowed to drop in [\#3411](https://github.com/pypeclub/OpenPype/pull/3411)
|
||||
- General: Add ability to change user value for templates [\#3366](https://github.com/pypeclub/OpenPype/pull/3366)
|
||||
|
||||
**🐛 Bug fixes**
|
||||
|
||||
|
|
@ -87,10 +114,6 @@
|
|||
- Nuke: Collect representation files based on Write [\#3407](https://github.com/pypeclub/OpenPype/pull/3407)
|
||||
- General: Filter representations before integration start [\#3398](https://github.com/pypeclub/OpenPype/pull/3398)
|
||||
- Maya: look collector typo [\#3392](https://github.com/pypeclub/OpenPype/pull/3392)
|
||||
- TVPaint: Make sure exit code is set to not None [\#3382](https://github.com/pypeclub/OpenPype/pull/3382)
|
||||
- Maya: vray device aspect ratio fix [\#3381](https://github.com/pypeclub/OpenPype/pull/3381)
|
||||
- Flame: bunch of publishing issues [\#3377](https://github.com/pypeclub/OpenPype/pull/3377)
|
||||
- Harmony: added unc path to zifile command in Harmony [\#3372](https://github.com/pypeclub/OpenPype/pull/3372)
|
||||
|
||||
**🔀 Refactored code**
|
||||
|
||||
|
|
@ -100,31 +123,11 @@
|
|||
- Houdini: Use client query functions [\#3395](https://github.com/pypeclub/OpenPype/pull/3395)
|
||||
- Hiero: Use client query functions [\#3393](https://github.com/pypeclub/OpenPype/pull/3393)
|
||||
- Nuke: Use client query functions [\#3391](https://github.com/pypeclub/OpenPype/pull/3391)
|
||||
- Maya: Use client query functions [\#3385](https://github.com/pypeclub/OpenPype/pull/3385)
|
||||
- Harmony: Use client query functions [\#3378](https://github.com/pypeclub/OpenPype/pull/3378)
|
||||
- Celaction: Use client query functions [\#3376](https://github.com/pypeclub/OpenPype/pull/3376)
|
||||
- Photoshop: Use client query functions [\#3375](https://github.com/pypeclub/OpenPype/pull/3375)
|
||||
- AfterEffects: Use client query functions [\#3374](https://github.com/pypeclub/OpenPype/pull/3374)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Sync Queue: Added far future value for null values for dates [\#3371](https://github.com/pypeclub/OpenPype/pull/3371)
|
||||
- Maya - added support for single frame playblast review [\#3369](https://github.com/pypeclub/OpenPype/pull/3369)
|
||||
|
||||
## [3.11.1](https://github.com/pypeclub/OpenPype/tree/3.11.1) (2022-06-20)
|
||||
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.11.1-nightly.1...3.11.1)
|
||||
|
||||
**🚀 Enhancements**
|
||||
|
||||
- Pyblish Pype: Hiding/Close issues [\#3367](https://github.com/pypeclub/OpenPype/pull/3367)
|
||||
|
||||
**🐛 Bug fixes**
|
||||
|
||||
- Nuke: bake streams with slate on farm [\#3368](https://github.com/pypeclub/OpenPype/pull/3368)
|
||||
- Nuke: Fix missing variable in extract thumbnail [\#3363](https://github.com/pypeclub/OpenPype/pull/3363)
|
||||
- Nuke: Fix precollect writes [\#3361](https://github.com/pypeclub/OpenPype/pull/3361)
|
||||
|
||||
## [3.11.0](https://github.com/pypeclub/OpenPype/tree/3.11.0) (2022-06-17)
|
||||
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.11.0-nightly.4...3.11.0)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"""Package for handling pype command line arguments."""
|
||||
import os
|
||||
import sys
|
||||
|
||||
import code
|
||||
import click
|
||||
|
||||
# import sys
|
||||
|
|
@ -424,3 +424,22 @@ def pack_project(project, dirpath):
|
|||
def unpack_project(zipfile, root):
|
||||
"""Create a package of project with all files and database dump."""
|
||||
PypeCommands().unpack_project(zipfile, root)
|
||||
|
||||
|
||||
@main.command()
|
||||
def interactive():
|
||||
"""Interative (Python like) console.
|
||||
|
||||
Helpfull command not only for development to directly work with python
|
||||
interpreter.
|
||||
|
||||
Warning:
|
||||
Executable 'openpype_gui' on windows won't work.
|
||||
"""
|
||||
|
||||
from openpype.version import __version__
|
||||
|
||||
banner = "OpenPype {}\nPython {} on {}".format(
|
||||
__version__, sys.version, sys.platform
|
||||
)
|
||||
code.interact(banner)
|
||||
|
|
|
|||
|
|
@ -117,8 +117,8 @@ def get_asset_by_id(project_name, asset_id, fields=None):
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
asset_id (str|ObjectId): Asset's id.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
asset_id (Union[str, ObjectId]): Asset's id.
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -141,7 +141,7 @@ def get_asset_by_name(project_name, asset_name, fields=None):
|
|||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
asset_name (str): Asset's name.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -178,12 +178,13 @@ def _get_assets(
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
asset_ids (list[str|ObjectId]): Asset ids that should be found.
|
||||
asset_names (list[str]): Name assets that should be found.
|
||||
parent_ids (list[str|ObjectId]): Parent asset ids.
|
||||
asset_ids (Iterable[Union[str, ObjectId]]): Asset ids that should
|
||||
be found.
|
||||
asset_names (Iterable[str]): Name assets that should be found.
|
||||
parent_ids (Iterable[Union[str, ObjectId]]): Parent asset ids.
|
||||
standard (bool): Query standart assets (type 'asset').
|
||||
archived (bool): Query archived assets (type 'archived_asset').
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -244,11 +245,12 @@ def get_assets(
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
asset_ids (list[str|ObjectId]): Asset ids that should be found.
|
||||
asset_names (list[str]): Name assets that should be found.
|
||||
parent_ids (list[str|ObjectId]): Parent asset ids.
|
||||
asset_ids (Iterable[Union[str, ObjectId]]): Asset ids that should
|
||||
be found.
|
||||
asset_names (Iterable[str]): Name assets that should be found.
|
||||
parent_ids (Iterable[Union[str, ObjectId]]): Parent asset ids.
|
||||
archived (bool): Add also archived assets.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -283,10 +285,11 @@ def get_archived_assets(
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
asset_ids (list[str|ObjectId]): Asset ids that should be found.
|
||||
asset_names (list[str]): Name assets that should be found.
|
||||
parent_ids (list[str|ObjectId]): Parent asset ids.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
asset_ids (Iterable[Union[str, ObjectId]]): Asset ids that should
|
||||
be found.
|
||||
asset_names (Iterable[str]): Name assets that should be found.
|
||||
parent_ids (Iterable[Union[str, ObjectId]]): Parent asset ids.
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -304,10 +307,11 @@ def get_asset_ids_with_subsets(project_name, asset_ids=None):
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
asset_ids (list[str|ObjectId]): Look only for entered asset ids.
|
||||
asset_ids (Iterable[Union[str, ObjectId]]): Look only for entered
|
||||
asset ids.
|
||||
|
||||
Returns:
|
||||
List[ObjectId]: Asset ids that have existing subsets.
|
||||
Iterable[ObjectId]: Asset ids that have existing subsets.
|
||||
"""
|
||||
|
||||
subset_query = {
|
||||
|
|
@ -345,8 +349,8 @@ def get_subset_by_id(project_name, subset_id, fields=None):
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
subset_id (str|ObjectId): Id of subset which should be found.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
subset_id (Union[str, ObjectId]): Id of subset which should be found.
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -369,8 +373,8 @@ def get_subset_by_name(project_name, subset_name, asset_id, fields=None):
|
|||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
subset_name (str): Name of subset.
|
||||
asset_id (str|ObjectId): Id of parent asset.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
asset_id (Union[str, ObjectId]): Id of parent asset.
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -409,16 +413,16 @@ def get_subsets(
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
subset_ids (list[str|ObjectId]): Subset ids that should be queried.
|
||||
subset_ids (Iterable[Union[str, ObjectId]]): Subset ids that should be
|
||||
queried. Filter ignored if 'None' is passed.
|
||||
subset_names (Iterable[str]): Subset names that should be queried.
|
||||
Filter ignored if 'None' is passed.
|
||||
subset_names (list[str]): Subset names that should be queried.
|
||||
Filter ignored if 'None' is passed.
|
||||
asset_ids (list[str|ObjectId]): Asset ids under which should look for
|
||||
the subsets. Filter ignored if 'None' is passed.
|
||||
names_by_asset_ids (dict[ObjectId, list[str]]): Complex filtering
|
||||
asset_ids (Iterable[Union[str, ObjectId]]): Asset ids under which
|
||||
should look for the subsets. Filter ignored if 'None' is passed.
|
||||
names_by_asset_ids (dict[ObjectId, List[str]]): Complex filtering
|
||||
using asset ids and list of subset names under the asset.
|
||||
archived (bool): Look for archived subsets too.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -472,8 +476,8 @@ def get_subset_families(project_name, subset_ids=None):
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
subset_ids (list[str|ObjectId]): Subset ids that should be queried.
|
||||
All subsets from project are used if 'None' is passed.
|
||||
subset_ids (Iterable[Union[str, ObjectId]]): Subset ids that should
|
||||
be queried. All subsets from project are used if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
set[str]: Main families of matching subsets.
|
||||
|
|
@ -508,8 +512,8 @@ def get_version_by_id(project_name, version_id, fields=None):
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
version_id (str|ObjectId): Id of version which should be found.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
version_id (Union[str, ObjectId]): Id of version which should be found.
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -535,8 +539,8 @@ def get_version_by_name(project_name, version, subset_id, fields=None):
|
|||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
version (int): name of version entity (it's version).
|
||||
subset_id (str|ObjectId): Id of version which should be found.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
subset_id (Union[str, ObjectId]): Id of version which should be found.
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -621,14 +625,14 @@ def get_versions(
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
version_ids (list[str|ObjectId]): Version ids that will be queried.
|
||||
version_ids (Iterable[Union[str, ObjectId]]): Version ids that will
|
||||
be queried. Filter ignored if 'None' is passed.
|
||||
subset_ids (Iterable[str]): Subset ids that will be queried.
|
||||
Filter ignored if 'None' is passed.
|
||||
subset_ids (list[str]): Subset ids that will be queried.
|
||||
Filter ignored if 'None' is passed.
|
||||
versions (list[int]): Version names (as integers).
|
||||
versions (Iterable[int]): Version names (as integers).
|
||||
Filter ignored if 'None' is passed.
|
||||
hero (bool): Look also for hero versions.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -651,8 +655,9 @@ def get_hero_version_by_subset_id(project_name, subset_id, fields=None):
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
subset_id (str|ObjectId): Subset id under which is hero version.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
subset_id (Union[str, ObjectId]): Subset id under which
|
||||
is hero version.
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -681,8 +686,8 @@ def get_hero_version_by_id(project_name, version_id, fields=None):
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
version_id (str|ObjectId): Hero version id.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
version_id (Union[str, ObjectId]): Hero version id.
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -716,11 +721,11 @@ def get_hero_versions(
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
subset_ids (list[str|ObjectId]): Subset ids for which should look for
|
||||
hero versions. Filter ignored if 'None' is passed.
|
||||
version_ids (list[str|ObjectId]): Hero version ids. Filter ignored if
|
||||
'None' is passed.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
subset_ids (Iterable[Union[str, ObjectId]]): Subset ids for which
|
||||
should look for hero versions. Filter ignored if 'None' is passed.
|
||||
version_ids (Iterable[Union[str, ObjectId]]): Hero version ids. Filter
|
||||
ignored if 'None' is passed.
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -746,13 +751,13 @@ def get_output_link_versions(project_name, version_id, fields=None):
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
version_id (str|ObjectId): Version id which can be used as input link
|
||||
for other versions.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
version_id (Union[str, ObjectId]): Version id which can be used
|
||||
as input link for other versions.
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
Cursor|list: Iterable cursor yielding versions that are used as input
|
||||
Iterable: Iterable cursor yielding versions that are used as input
|
||||
links for passed version.
|
||||
"""
|
||||
|
||||
|
|
@ -774,8 +779,8 @@ def get_last_versions(project_name, subset_ids, fields=None):
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
subset_ids (list): List of subset ids.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
subset_ids (Iterable[Union[str, ObjectId]]): List of subset ids.
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -859,8 +864,8 @@ def get_last_version_by_subset_id(project_name, subset_id, fields=None):
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
subset_id (str|ObjectId): Id of version which should be found.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
subset_id (Union[str, ObjectId]): Id of version which should be found.
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -889,10 +894,10 @@ def get_last_version_by_subset_name(
|
|||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
subset_name (str): Name of subset.
|
||||
asset_id (str|ObjectId): Asset id which is parent of passed
|
||||
asset_id (Union[str, ObjectId]): Asset id which is parent of passed
|
||||
subset name.
|
||||
asset_name (str): Asset name which is parent of passed subset name.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -923,8 +928,8 @@ def get_representation_by_id(project_name, representation_id, fields=None):
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
representation_id (str|ObjectId): Representation id.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
representation_id (Union[str, ObjectId]): Representation id.
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -956,8 +961,8 @@ def get_representation_by_name(
|
|||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
representation_name (str): Representation name.
|
||||
version_id (str|ObjectId): Id of parent version entity.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
version_id (Union[str, ObjectId]): Id of parent version entity.
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -1061,18 +1066,18 @@ def get_representations(
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
representation_ids (list[str|ObjectId]): Representation ids used as
|
||||
filter. Filter ignored if 'None' is passed.
|
||||
representation_names (list[str]): Representations names used as filter.
|
||||
Filter ignored if 'None' is passed.
|
||||
version_ids (list[str]): Subset ids used as parent filter. Filter
|
||||
representation_ids (Iterable[Union[str, ObjectId]]): Representation ids
|
||||
used as filter. Filter ignored if 'None' is passed.
|
||||
representation_names (Iterable[str]): Representations names used
|
||||
as filter. Filter ignored if 'None' is passed.
|
||||
version_ids (Iterable[str]): Subset ids used as parent filter. Filter
|
||||
ignored if 'None' is passed.
|
||||
extensions (list[str]): Filter by extension of main representation
|
||||
extensions (Iterable[str]): Filter by extension of main representation
|
||||
file (without dot).
|
||||
names_by_version_ids (dict[ObjectId, list[str]]): Complex filtering
|
||||
using version ids and list of names under the version.
|
||||
archived (bool): Output will also contain archived representations.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -1107,17 +1112,17 @@ def get_archived_representations(
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
representation_ids (list[str|ObjectId]): Representation ids used as
|
||||
filter. Filter ignored if 'None' is passed.
|
||||
representation_names (list[str]): Representations names used as filter.
|
||||
Filter ignored if 'None' is passed.
|
||||
version_ids (list[str]): Subset ids used as parent filter. Filter
|
||||
representation_ids (Iterable[Union[str, ObjectId]]): Representation ids
|
||||
used as filter. Filter ignored if 'None' is passed.
|
||||
representation_names (Iterable[str]): Representations names used
|
||||
as filter. Filter ignored if 'None' is passed.
|
||||
version_ids (Iterable[str]): Subset ids used as parent filter. Filter
|
||||
ignored if 'None' is passed.
|
||||
extensions (list[str]): Filter by extension of main representation
|
||||
extensions (Iterable[str]): Filter by extension of main representation
|
||||
file (without dot).
|
||||
names_by_version_ids (dict[ObjectId, list[str]]): Complex filtering
|
||||
names_by_version_ids (dict[ObjectId, List[str]]): Complex filtering
|
||||
using version ids and list of names under the version.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -1145,7 +1150,7 @@ def get_representations_parents(project_name, representations):
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
representations (list[dict]): Representation entities with at least
|
||||
representations (List[dict]): Representation entities with at least
|
||||
'_id' and 'parent' keys.
|
||||
|
||||
Returns:
|
||||
|
|
@ -1238,7 +1243,7 @@ def get_thumbnail_id_from_source(project_name, src_type, src_id):
|
|||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
src_type (str): Type of source entity ('asset', 'version').
|
||||
src_id (str|objectId): Id of source entity.
|
||||
src_id (Union[str, ObjectId]): Id of source entity.
|
||||
|
||||
Returns:
|
||||
ObjectId: Thumbnail id assigned to entity.
|
||||
|
|
@ -1265,8 +1270,9 @@ def get_thumbnails(project_name, thumbnail_ids, fields=None):
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
thumbnail_ids (list[str|ObjectId]): Ids of thumbnail entities.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
thumbnail_ids (Iterable[Union[str, ObjectId]]): Ids of thumbnail
|
||||
entities.
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -1291,8 +1297,8 @@ def get_thumbnail(project_name, thumbnail_id, fields=None):
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
thumbnail_id (str|ObjectId): Id of thumbnail entity.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
thumbnail_id (Union[str, ObjectId]): Id of thumbnail entity.
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
|
|
@ -1319,9 +1325,9 @@ def get_workfile_info(
|
|||
|
||||
Args:
|
||||
project_name (str): Name of project where to look for queried entities.
|
||||
asset_id (str|ObjectId): Id of asset entity.
|
||||
asset_id (Union[str, ObjectId]): Id of asset entity.
|
||||
task_name (str): Task name on asset.
|
||||
fields (list[str]): Fields that should be returned. All fields are
|
||||
fields (Iterable[str]): Fields that should be returned. All fields are
|
||||
returned if 'None' is passed.
|
||||
"""
|
||||
|
||||
|
|
@ -1348,622 +1354,18 @@ def get_workfile_info(
|
|||
- openpype/hosts/maya/api/shader_definition_editor.py
|
||||
- openpype/hosts/maya/plugins/publish/validate_model_name.py
|
||||
|
||||
## Global launch hooks
|
||||
- openpype/hooks/pre_global_host_data.py
|
||||
Query:
|
||||
- project
|
||||
- asset
|
||||
|
||||
## Global load plugins
|
||||
- openpype/plugins/load/delete_old_versions.py
|
||||
Query:
|
||||
- versions
|
||||
- representations
|
||||
- openpype/plugins/load/delivery.py
|
||||
Query:
|
||||
- representations
|
||||
|
||||
## Global publish plugins
|
||||
- openpype/plugins/publish/collect_avalon_entities.py
|
||||
Query:
|
||||
- asset
|
||||
- project
|
||||
- openpype/plugins/publish/collect_anatomy_instance_data.py
|
||||
Query:
|
||||
- assets
|
||||
- subsets
|
||||
- last version
|
||||
- openpype/plugins/publish/collect_scene_loaded_versions.py
|
||||
Query:
|
||||
- representations
|
||||
- openpype/plugins/publish/extract_hierarchy_avalon.py
|
||||
Query:
|
||||
- asset
|
||||
- assets
|
||||
- project
|
||||
Create:
|
||||
- asset
|
||||
Update:
|
||||
- asset
|
||||
- openpype/plugins/publish/integrate_hero_version.py
|
||||
Query:
|
||||
- version
|
||||
- hero version
|
||||
- representations
|
||||
- openpype/plugins/publish/integrate_new.py
|
||||
Query:
|
||||
- asset
|
||||
- subset
|
||||
- version
|
||||
- representations
|
||||
- openpype/plugins/publish/integrate_thumbnail.py
|
||||
Query:
|
||||
- version
|
||||
- openpype/plugins/publish/validate_editorial_asset_name.py
|
||||
Query:
|
||||
- assets
|
||||
|
||||
## Lib
|
||||
- openpype/lib/applications.py
|
||||
Query:
|
||||
- project
|
||||
- asset
|
||||
- openpype/lib/avalon_context.py
|
||||
Query:
|
||||
- project
|
||||
- asset
|
||||
- linked assets (new function get_linked_assets?)
|
||||
- subset
|
||||
- subsets
|
||||
- version
|
||||
- versions
|
||||
- last version
|
||||
- representations
|
||||
- linked representations (new function get_linked_ids_for_representations)
|
||||
Update:
|
||||
- workfile data
|
||||
- openpype/lib/plugin_tools.py
|
||||
Query:
|
||||
- asset
|
||||
- openpype/lib/project_backpack.py
|
||||
Query:
|
||||
- project
|
||||
- everything from mongo
|
||||
Update:
|
||||
- project
|
||||
- openpype/lib/usdlib.py
|
||||
Query:
|
||||
- project
|
||||
- asset
|
||||
|
||||
## Pipeline
|
||||
- openpype/pipeline/load/utils.py
|
||||
Query:
|
||||
- project
|
||||
- assets
|
||||
- subsets
|
||||
- version
|
||||
- versions
|
||||
- representation
|
||||
- representations
|
||||
- openpype/pipeline/mongodb.py
|
||||
Query:
|
||||
- project
|
||||
- openpype/pipeline/thumbnail.py
|
||||
Query:
|
||||
- project
|
||||
|
||||
## Hosts
|
||||
### Aftereffects
|
||||
- openpype/hosts/aftereffects/plugins/create/workfile_creator.py
|
||||
Query:
|
||||
- asset
|
||||
|
||||
### Blender
|
||||
- openpype/hosts/blender/api/pipeline.py
|
||||
Query:
|
||||
- asset
|
||||
- openpype/hosts/blender/plugins/publish/extract_layout.py
|
||||
Query:
|
||||
- representation
|
||||
|
||||
### Celaction
|
||||
- openpype/hosts/celaction/plugins/publish/collect_audio.py
|
||||
Query:
|
||||
- subsets
|
||||
- last versions
|
||||
- representations
|
||||
|
||||
### Fusion
|
||||
- openpype/hosts/fusion/api/lib.py
|
||||
Query:
|
||||
- asset
|
||||
- subset
|
||||
- version
|
||||
- representation
|
||||
- openpype/hosts/fusion/plugins/load/load_sequence.py
|
||||
Query:
|
||||
- version
|
||||
- openpype/hosts/fusion/scripts/fusion_switch_shot.py
|
||||
Query:
|
||||
- project
|
||||
- asset
|
||||
- versions
|
||||
- openpype/hosts/fusion/utility_scripts/switch_ui.py
|
||||
Query:
|
||||
- assets
|
||||
|
||||
### Harmony
|
||||
- openpype/hosts/harmony/api/pipeline.py
|
||||
Query:
|
||||
- representation
|
||||
|
||||
### Hiero
|
||||
- openpype/hosts/hiero/api/lib.py
|
||||
Query:
|
||||
- project
|
||||
- version
|
||||
- versions
|
||||
- representation
|
||||
- openpype/hosts/hiero/api/tags.py
|
||||
Query:
|
||||
- task types
|
||||
- assets
|
||||
- openpype/hosts/hiero/plugins/load/load_clip.py
|
||||
Query:
|
||||
- version
|
||||
- versions
|
||||
- openpype/hosts/hiero/plugins/publish_old_workflow/collect_assetbuilds.py
|
||||
Query:
|
||||
- assets
|
||||
|
||||
### Houdini
|
||||
- openpype/hosts/houdini/api/lib.py
|
||||
Query:
|
||||
- asset
|
||||
- openpype/hosts/houdini/api/usd.py
|
||||
Query:
|
||||
- asset
|
||||
- openpype/hosts/houdini/plugins/create/create_hda.py
|
||||
Query:
|
||||
- asset
|
||||
- subsets
|
||||
- openpype/hosts/houdini/plugins/publish/collect_usd_bootstrap.py
|
||||
Query:
|
||||
- asset
|
||||
- subset
|
||||
- openpype/hosts/houdini/plugins/publish/extract_usd_layered.py
|
||||
Query:
|
||||
- asset
|
||||
- subset
|
||||
- version
|
||||
- representation
|
||||
- openpype/hosts/houdini/plugins/publish/validate_usd_shade_model_exists.py
|
||||
Query:
|
||||
- asset
|
||||
- subset
|
||||
- openpype/hosts/houdini/vendor/husdoutputprocessors/avalon_uri_processor.py
|
||||
Query:
|
||||
- project
|
||||
- asset
|
||||
|
||||
### Maya
|
||||
- openpype/hosts/maya/api/action.py
|
||||
Query:
|
||||
- asset
|
||||
- openpype/hosts/maya/api/commands.py
|
||||
Query:
|
||||
- asset
|
||||
- project
|
||||
- openpype/hosts/maya/api/lib.py
|
||||
Query:
|
||||
- project
|
||||
- asset
|
||||
- subset
|
||||
- subsets
|
||||
- version
|
||||
- representation
|
||||
- openpype/hosts/maya/api/setdress.py
|
||||
Query:
|
||||
- version
|
||||
- representation
|
||||
- openpype/hosts/maya/plugins/inventory/import_modelrender.py
|
||||
Query:
|
||||
- representation
|
||||
- openpype/hosts/maya/plugins/load/load_audio.py
|
||||
Query:
|
||||
- asset
|
||||
- subset
|
||||
- version
|
||||
- openpype/hosts/maya/plugins/load/load_image_plane.py
|
||||
Query:
|
||||
- asset
|
||||
- subset
|
||||
- version
|
||||
- openpype/hosts/maya/plugins/load/load_look.py
|
||||
Query:
|
||||
- representation
|
||||
- openpype/hosts/maya/plugins/load/load_vrayproxy.py
|
||||
Query:
|
||||
- representation
|
||||
- openpype/hosts/maya/plugins/load/load_yeti_cache.py
|
||||
Query:
|
||||
- representation
|
||||
- openpype/hosts/maya/plugins/publish/collect_review.py
|
||||
Query:
|
||||
- subsets
|
||||
- openpype/hosts/maya/plugins/publish/validate_node_ids_in_database.py
|
||||
Query:
|
||||
- assets
|
||||
- openpype/hosts/maya/plugins/publish/validate_node_ids_related.py
|
||||
Query:
|
||||
- asset
|
||||
- openpype/hosts/maya/plugins/publish/validate_renderlayer_aovs.py
|
||||
Query:
|
||||
- asset
|
||||
- subset
|
||||
|
||||
### Nuke
|
||||
- openpype/hosts/nuke/api/command.py
|
||||
Query:
|
||||
- project
|
||||
- asset
|
||||
- openpype/hosts/nuke/api/lib.py
|
||||
Query:
|
||||
- project
|
||||
- asset
|
||||
- version
|
||||
- versions
|
||||
- representation
|
||||
- openpype/hosts/nuke/plugins/load/load_backdrop.py
|
||||
Query:
|
||||
- version
|
||||
- versions
|
||||
- openpype/hosts/nuke/plugins/load/load_camera_abc.py
|
||||
Query:
|
||||
- version
|
||||
- versions
|
||||
- openpype/hosts/nuke/plugins/load/load_clip.py
|
||||
Query:
|
||||
- version
|
||||
- versions
|
||||
- openpype/hosts/nuke/plugins/load/load_effects_ip.py
|
||||
Query:
|
||||
- version
|
||||
- versions
|
||||
- openpype/hosts/nuke/plugins/load/load_effects.py
|
||||
Query:
|
||||
- version
|
||||
- versions
|
||||
- openpype/hosts/nuke/plugins/load/load_gizmo_ip.py
|
||||
Query:
|
||||
- version
|
||||
- versions
|
||||
- openpype/hosts/nuke/plugins/load/load_gizmo.py
|
||||
Query:
|
||||
- version
|
||||
- versions
|
||||
- openpype/hosts/nuke/plugins/load/load_image.py
|
||||
Query:
|
||||
- version
|
||||
- versions
|
||||
- openpype/hosts/nuke/plugins/load/load_model.py
|
||||
Query:
|
||||
- version
|
||||
- versions
|
||||
- openpype/hosts/nuke/plugins/load/load_script_precomp.py
|
||||
Query:
|
||||
- version
|
||||
- versions
|
||||
- openpype/hosts/nuke/plugins/publish/collect_reads.py
|
||||
Query:
|
||||
- asset
|
||||
- openpype/hosts/nuke/plugins/publish/precollect_instances.py
|
||||
Query:
|
||||
- asset
|
||||
- openpype/hosts/nuke/plugins/publish/precollect_writes.py
|
||||
Query:
|
||||
- representation
|
||||
- openpype/hosts/nuke/plugins/publish/validate_script.py
|
||||
Query:
|
||||
- asset
|
||||
- project
|
||||
|
||||
### Photoshop
|
||||
- openpype/hosts/photoshop/plugins/create/workfile_creator.py
|
||||
Query:
|
||||
- asset
|
||||
|
||||
### Resolve
|
||||
- openpype/hosts/resolve/plugins/load/load_clip.py
|
||||
Query:
|
||||
- version
|
||||
- versions
|
||||
|
||||
### Standalone publisher
|
||||
- openpype/hosts/standalonepublisher/plugins/publish/collect_bulk_mov_instances.py
|
||||
Query:
|
||||
- asset
|
||||
- openpype/hosts/standalonepublisher/plugins/publish/collect_matching_asset.py
|
||||
Query:
|
||||
- assets
|
||||
- openpype/hosts/standalonepublisher/plugins/publish/collect_hierarchy.py
|
||||
Query:
|
||||
- project
|
||||
- asset
|
||||
- openpype/hosts/standalonepublisher/plugins/publish/validate_task_existence.py
|
||||
Query:
|
||||
- assets
|
||||
|
||||
### TVPaint
|
||||
- openpype/hosts/tvpaint/api/pipeline.py
|
||||
Query:
|
||||
- project
|
||||
- asset
|
||||
- openpype/hosts/tvpaint/plugins/load/load_workfile.py
|
||||
Query:
|
||||
- project
|
||||
- asset
|
||||
- openpype/hosts/tvpaint/plugins/publish/collect_instances.py
|
||||
Query:
|
||||
- asset
|
||||
- openpype/hosts/tvpaint/plugins/publish/collect_scene_render.py
|
||||
Query:
|
||||
- asset
|
||||
- openpype/hosts/tvpaint/plugins/publish/collect_workfile.py
|
||||
Query:
|
||||
- asset
|
||||
|
||||
### Unreal
|
||||
- openpype/hosts/unreal/plugins/load/load_camera.py
|
||||
Query:
|
||||
- asset
|
||||
- assets
|
||||
- openpype/hosts/unreal/plugins/load/load_layout.py
|
||||
Query:
|
||||
- asset
|
||||
- assets
|
||||
- openpype/hosts/unreal/plugins/publish/extract_layout.py
|
||||
Query:
|
||||
- representation
|
||||
|
||||
### Webpublisher
|
||||
- openpype/hosts/webpublisher/webserver_service/webpublish_routes.py
|
||||
Query:
|
||||
- assets
|
||||
- openpype/hosts/webpublisher/plugins/publish/collect_published_files.py
|
||||
Query:
|
||||
- last versions
|
||||
|
||||
## Tools
|
||||
openpype/tools/assetlinks/widgets.py
|
||||
- SimpleLinkView
|
||||
Query:
|
||||
- get_versions
|
||||
- get_subsets
|
||||
- get_assets
|
||||
- get_output_link_versions
|
||||
|
||||
openpype/tools/creator/window.py
|
||||
- CreatorWindow
|
||||
Query:
|
||||
- get_asset_by_name
|
||||
- get_subsets
|
||||
|
||||
openpype/tools/launcher/models.py
|
||||
- LauncherModel
|
||||
Query:
|
||||
- get_project
|
||||
- get_assets
|
||||
|
||||
openpype/tools/libraryloader/app.py
|
||||
- LibraryLoaderWindow
|
||||
Query:
|
||||
- get_project
|
||||
|
||||
openpype/tools/loader/app.py
|
||||
- LoaderWindow
|
||||
Query:
|
||||
- get_project
|
||||
- show
|
||||
Query:
|
||||
- get_projects
|
||||
|
||||
openpype/tools/loader/model.py
|
||||
- SubsetsModel
|
||||
Query:
|
||||
- get_assets
|
||||
- get_subsets
|
||||
- get_last_versions
|
||||
- get_versions
|
||||
- get_hero_versions
|
||||
- get_version_by_name
|
||||
- RepresentationModel
|
||||
Query:
|
||||
- get_representations
|
||||
- sync server specific queries (separated into multiple functions?)
|
||||
- NOT REPLACED
|
||||
|
||||
openpype/tools/loader/widgets.py
|
||||
- FamilyModel
|
||||
Query:
|
||||
- get_subset_families
|
||||
- VersionTextEdit
|
||||
Query:
|
||||
- get_subset_by_id
|
||||
- get_version_by_id
|
||||
- SubsetWidget
|
||||
Query:
|
||||
- get_subsets
|
||||
- get_representations
|
||||
Update:
|
||||
- Subset groups (combination of asset id and subset names)
|
||||
- RepresentationWidget
|
||||
Query:
|
||||
- get_subsets
|
||||
- get_versions
|
||||
- get_representations
|
||||
- ThumbnailWidget
|
||||
Query:
|
||||
- get_thumbnail_id_from_source
|
||||
- get_thumbnail
|
||||
|
||||
openpype/tools/mayalookassigner/app.py
|
||||
- MayaLookAssignerWindow
|
||||
Query:
|
||||
- get_last_version_by_subset_id
|
||||
|
||||
openpype/tools/mayalookassigner/commands.py
|
||||
- create_items_from_nodes
|
||||
Query:
|
||||
- get_asset_by_id
|
||||
|
||||
openpype/tools/mayalookassigner/vray_proxies.py
|
||||
- get_look_relationships
|
||||
Query:
|
||||
- get_representation_by_name
|
||||
- load_look
|
||||
Query:
|
||||
- get_representation_by_name
|
||||
- vrayproxy_assign_look
|
||||
Query:
|
||||
- get_last_version_by_subset_name
|
||||
|
||||
openpype/tools/project_manager/project_manager/model.py
|
||||
- HierarchyModel
|
||||
Query:
|
||||
- get_asset_ids_with_subsets
|
||||
- get_project
|
||||
- get_assets
|
||||
|
||||
openpype/tools/project_manager/project_manager/view.py
|
||||
- ProjectDocCache
|
||||
Query:
|
||||
- get_project
|
||||
|
||||
openpype/tools/project_manager/project_manager/widgets.py
|
||||
- CreateProjectDialog
|
||||
Query:
|
||||
- get_projects
|
||||
|
||||
openpype/tools/publisher/widgets/create_dialog.py
|
||||
- CreateDialog
|
||||
Query:
|
||||
- get_asset_by_name
|
||||
- get_subsets
|
||||
|
||||
openpype/tools/publisher/control.py
|
||||
- AssetDocsCache
|
||||
Query:
|
||||
- get_assets
|
||||
|
||||
openpype/tools/sceneinventory/model.py
|
||||
- InventoryModel
|
||||
Query:
|
||||
- get_asset_by_id
|
||||
- get_subset_by_id
|
||||
- get_version_by_id
|
||||
- get_last_version_by_subset_id
|
||||
- get_representation
|
||||
|
||||
openpype/tools/sceneinventory/switch_dialog.py
|
||||
- SwitchAssetDialog
|
||||
Query:
|
||||
- get_asset_by_name
|
||||
- get_assets
|
||||
- get_subset_by_name
|
||||
- get_subsets
|
||||
- get_versions
|
||||
- get_hero_versions
|
||||
- get_last_versions
|
||||
- get_representations
|
||||
|
||||
openpype/tools/sceneinventory/view.py
|
||||
- SceneInventoryView
|
||||
Query:
|
||||
- get_version_by_id
|
||||
- get_versions
|
||||
- get_hero_versions
|
||||
- get_representation_by_id
|
||||
- get_representations
|
||||
|
||||
openpype/tools/standalonepublish/widgets/model_asset.py
|
||||
- AssetModel
|
||||
Query:
|
||||
- get_assets
|
||||
|
||||
openpype/tools/standalonepublish/widgets/widget_asset.py
|
||||
- AssetWidget
|
||||
Query:
|
||||
- get_project
|
||||
- get_asset_by_id
|
||||
|
||||
openpype/tools/standalonepublish/widgets/widget_family.py
|
||||
- FamilyWidget
|
||||
Query:
|
||||
- get_asset_by_name
|
||||
- get_subset_by_name
|
||||
- get_subsets
|
||||
- get_last_version_by_subset_id
|
||||
|
||||
openpype/tools/standalonepublish/app.py
|
||||
- Window
|
||||
Query:
|
||||
- get_asset_by_id
|
||||
|
||||
openpype/tools/texture_copy/app.py
|
||||
- TextureCopy
|
||||
Query:
|
||||
- get_project
|
||||
- get_asset_by_name
|
||||
|
||||
openpype/tools/workfiles/files_widget.py
|
||||
- FilesWidget
|
||||
Query:
|
||||
- get_asset_by_id
|
||||
|
||||
openpype/tools/workfiles/model.py
|
||||
- PublishFilesModel
|
||||
Query:
|
||||
- get_subsets
|
||||
- get_versions
|
||||
- get_representations
|
||||
|
||||
openpype/tools/workfiles/save_as_dialog.py
|
||||
- build_workfile_data
|
||||
Query:
|
||||
- get_project
|
||||
- get_asset_by_name
|
||||
|
||||
openpype/tools/workfiles/window.py
|
||||
- Window
|
||||
Query:
|
||||
- get_asset_by_id
|
||||
- get_asset_by_name
|
||||
|
||||
openpype/tools/utils/assets_widget.py
|
||||
- AssetModel
|
||||
Query:
|
||||
- get_project
|
||||
- get_assets
|
||||
|
||||
openpype/tools/utils/delegates.py
|
||||
- VersionDelegate
|
||||
Query:
|
||||
- get_versions
|
||||
- get_hero_versions
|
||||
|
||||
openpype/tools/utils/lib.py
|
||||
- GroupsConfig
|
||||
Query:
|
||||
- get_project
|
||||
- FamilyConfigCache
|
||||
Query:
|
||||
- get_asset_by_name
|
||||
|
||||
openpype/tools/utils/tasks_widget.py
|
||||
- TasksModel
|
||||
Query:
|
||||
- get_project
|
||||
- get_asset_by_id
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -323,6 +323,8 @@ class IntegrateBatchGroup(pyblish.api.InstancePlugin):
|
|||
def _get_shot_task_dir_path(self, instance, task_data):
|
||||
project_doc = instance.data["projectEntity"]
|
||||
asset_entity = instance.data["assetEntity"]
|
||||
anatomy = instance.context.data["anatomy"]
|
||||
|
||||
return get_workdir(
|
||||
project_doc, asset_entity, task_data["name"], "flame")
|
||||
project_doc, asset_entity, task_data["name"], "flame", anatomy
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1087,7 +1087,7 @@ class RenderProductsRenderman(ARenderProducts):
|
|||
"d_tiff": "tif"
|
||||
}
|
||||
|
||||
displays = get_displays()["displays"]
|
||||
displays = get_displays(override_dst="render")["displays"]
|
||||
for name, display in displays.items():
|
||||
enabled = display["params"]["enable"]["value"]
|
||||
if not enabled:
|
||||
|
|
@ -1106,9 +1106,33 @@ class RenderProductsRenderman(ARenderProducts):
|
|||
display["driverNode"]["type"], "exr")
|
||||
|
||||
for camera in cameras:
|
||||
product = RenderProduct(productName=aov_name,
|
||||
ext=extensions,
|
||||
camera=camera)
|
||||
# Create render product and set it as multipart only on
|
||||
# display types supporting it. In all other cases, Renderman
|
||||
# will create separate output per channel.
|
||||
if display["driverNode"]["type"] in ["d_openexr", "d_deepexr", "d_tiff"]: # noqa
|
||||
product = RenderProduct(
|
||||
productName=aov_name,
|
||||
ext=extensions,
|
||||
camera=camera,
|
||||
multipart=True
|
||||
)
|
||||
else:
|
||||
# this code should handle the case where no multipart
|
||||
# capable format is selected. But since it involves
|
||||
# shady logic to determine what channel become what
|
||||
# lets not do that as all productions will use exr anyway.
|
||||
"""
|
||||
for channel in display['params']['displayChannels']['value']: # noqa
|
||||
product = RenderProduct(
|
||||
productName="{}_{}".format(aov_name, channel),
|
||||
ext=extensions,
|
||||
camera=camera,
|
||||
multipart=False
|
||||
)
|
||||
"""
|
||||
raise UnsupportedImageFormatException(
|
||||
"Only exr, deep exr and tiff formats are supported.")
|
||||
|
||||
products.append(product)
|
||||
|
||||
return products
|
||||
|
|
@ -1201,3 +1225,7 @@ class UnsupportedRendererException(Exception):
|
|||
|
||||
Raised when requesting data from unsupported renderer.
|
||||
"""
|
||||
|
||||
|
||||
class UnsupportedImageFormatException(Exception):
|
||||
"""Custom exception to report unsupported output image format."""
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from openpype.pipeline import PublishXmlValidationError
|
|||
|
||||
|
||||
class ValidateReviewSubsetUniqueness(pyblish.api.ContextPlugin):
|
||||
"""Validates that nodes has common root."""
|
||||
"""Validates that review subset has unique name."""
|
||||
|
||||
order = openpype.api.ValidateContentsOrder
|
||||
hosts = ["maya"]
|
||||
|
|
@ -17,7 +17,7 @@ class ValidateReviewSubsetUniqueness(pyblish.api.ContextPlugin):
|
|||
subset_names = []
|
||||
|
||||
for instance in context:
|
||||
self.log.info("instance:: {}".format(instance.data))
|
||||
self.log.debug("Instance: {}".format(instance.data))
|
||||
if instance.data.get('publish'):
|
||||
subset_names.append(instance.data.get('subset'))
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@ import openpype.api
|
|||
|
||||
|
||||
class ValidateSetdressRoot(pyblish.api.InstancePlugin):
|
||||
"""
|
||||
"""
|
||||
"""Validate if set dress top root node is published."""
|
||||
|
||||
order = openpype.api.ValidateContentsOrder
|
||||
label = "SetDress Root"
|
||||
|
|
|
|||
|
|
@ -2440,10 +2440,12 @@ def _launch_workfile_app():
|
|||
if starting_up or closing_down:
|
||||
return
|
||||
|
||||
from .pipeline import get_main_window
|
||||
|
||||
main_window = get_main_window()
|
||||
host_tools.show_workfiles(parent=main_window)
|
||||
# Make sure on top is enabled on first show so the window is not hidden
|
||||
# under main nuke window
|
||||
# - this happened on Centos 7 and it is because the focus of nuke
|
||||
# changes to the main window after showing because of initialization
|
||||
# which moves workfiles tool under it
|
||||
host_tools.show_workfiles(parent=None, on_top=True)
|
||||
|
||||
|
||||
def process_workfile_builder():
|
||||
|
|
|
|||
|
|
@ -142,6 +142,14 @@ def uninstall():
|
|||
_uninstall_menu()
|
||||
|
||||
|
||||
def _show_workfiles():
|
||||
# Make sure parent is not set
|
||||
# - this makes Workfiles tool as separated window which
|
||||
# avoid issues with reopening
|
||||
# - it is possible to explicitly change on top flag of the tool
|
||||
host_tools.show_workfiles(parent=None, on_top=False)
|
||||
|
||||
|
||||
def _install_menu():
|
||||
# uninstall original avalon menu
|
||||
main_window = get_main_window()
|
||||
|
|
@ -158,7 +166,7 @@ def _install_menu():
|
|||
menu.addSeparator()
|
||||
menu.addCommand(
|
||||
"Work Files...",
|
||||
lambda: host_tools.show_workfiles(parent=main_window)
|
||||
_show_workfiles
|
||||
)
|
||||
|
||||
menu.addSeparator()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,216 @@
|
|||
import copy
|
||||
import os
|
||||
import re
|
||||
|
||||
from openpype.client import get_assets, get_asset_by_name
|
||||
from openpype.lib import (
|
||||
FileDef,
|
||||
BoolDef,
|
||||
get_subset_name_with_asset_doc,
|
||||
TaskNotSetError,
|
||||
)
|
||||
from openpype.pipeline import (
|
||||
CreatedInstance,
|
||||
CreatorError
|
||||
)
|
||||
|
||||
from openpype.hosts.traypublisher.api.plugin import TrayPublishCreator
|
||||
|
||||
|
||||
class BatchMovieCreator(TrayPublishCreator):
|
||||
"""Creates instances from movie file(s).
|
||||
|
||||
Intended for .mov files, but should work for any video file.
|
||||
Doesn't handle image sequences though.
|
||||
"""
|
||||
identifier = "render_movie_batch"
|
||||
label = "Batch Movies"
|
||||
family = "render"
|
||||
description = "Publish batch of video files"
|
||||
|
||||
create_allow_context_change = False
|
||||
version_regex = re.compile(r"^(.+)_v([0-9]+)$")
|
||||
|
||||
def __init__(self, project_settings, *args, **kwargs):
|
||||
super(BatchMovieCreator, self).__init__(project_settings,
|
||||
*args, **kwargs)
|
||||
creator_settings = (
|
||||
project_settings["traypublisher"]["BatchMovieCreator"]
|
||||
)
|
||||
self.default_variants = creator_settings["default_variants"]
|
||||
self.default_tasks = creator_settings["default_tasks"]
|
||||
self.extensions = creator_settings["extensions"]
|
||||
|
||||
def get_icon(self):
|
||||
return "fa.file"
|
||||
|
||||
def create(self, subset_name, data, pre_create_data):
|
||||
file_paths = pre_create_data.get("filepath")
|
||||
if not file_paths:
|
||||
return
|
||||
|
||||
for file_info in file_paths:
|
||||
instance_data = copy.deepcopy(data)
|
||||
file_name = file_info["filenames"][0]
|
||||
filepath = os.path.join(file_info["directory"], file_name)
|
||||
instance_data["creator_attributes"] = {"filepath": filepath}
|
||||
|
||||
asset_doc, version = self.get_asset_doc_from_file_name(
|
||||
file_name, self.project_name)
|
||||
|
||||
subset_name, task_name = self._get_subset_and_task(
|
||||
asset_doc, data["variant"], self.project_name)
|
||||
|
||||
instance_data["task"] = task_name
|
||||
instance_data["asset"] = asset_doc["name"]
|
||||
|
||||
# Create new instance
|
||||
new_instance = CreatedInstance(self.family, subset_name,
|
||||
instance_data, self)
|
||||
self._store_new_instance(new_instance)
|
||||
|
||||
def get_asset_doc_from_file_name(self, source_filename, project_name):
|
||||
"""Try to parse out asset name from file name provided.
|
||||
|
||||
Artists might provide various file name formats.
|
||||
Currently handled:
|
||||
- chair.mov
|
||||
- chair_v001.mov
|
||||
- my_chair_to_upload.mov
|
||||
"""
|
||||
version = None
|
||||
asset_name = os.path.splitext(source_filename)[0]
|
||||
# Always first check if source filename is in assets
|
||||
matching_asset_doc = self._get_asset_by_name_case_not_sensitive(
|
||||
project_name, asset_name)
|
||||
|
||||
if matching_asset_doc is None:
|
||||
matching_asset_doc, version = (
|
||||
self._parse_with_version(project_name, asset_name))
|
||||
|
||||
if matching_asset_doc is None:
|
||||
matching_asset_doc = self._parse_containing(project_name,
|
||||
asset_name)
|
||||
|
||||
if matching_asset_doc is None:
|
||||
raise CreatorError(
|
||||
"Cannot guess asset name from {}".format(source_filename))
|
||||
|
||||
return matching_asset_doc, version
|
||||
|
||||
def _parse_with_version(self, project_name, asset_name):
|
||||
"""Try to parse asset name from a file name containing version too
|
||||
|
||||
Eg. 'chair_v001.mov' >> 'chair', 1
|
||||
"""
|
||||
self.log.debug((
|
||||
"Asset doc by \"{}\" was not found, trying version regex."
|
||||
).format(asset_name))
|
||||
|
||||
matching_asset_doc = version_number = None
|
||||
|
||||
regex_result = self.version_regex.findall(asset_name)
|
||||
if regex_result:
|
||||
_asset_name, _version_number = regex_result[0]
|
||||
matching_asset_doc = self._get_asset_by_name_case_not_sensitive(
|
||||
project_name, _asset_name)
|
||||
if matching_asset_doc:
|
||||
version_number = int(_version_number)
|
||||
|
||||
return matching_asset_doc, version_number
|
||||
|
||||
def _parse_containing(self, project_name, asset_name):
|
||||
"""Look if file name contains any existing asset name"""
|
||||
for asset_doc in get_assets(project_name, fields=["name"]):
|
||||
if asset_doc["name"].lower() in asset_name.lower():
|
||||
return get_asset_by_name(project_name, asset_doc["name"])
|
||||
|
||||
def _get_subset_and_task(self, asset_doc, variant, project_name):
|
||||
"""Create subset name according to standard template process"""
|
||||
task_name = self._get_task_name(asset_doc)
|
||||
|
||||
try:
|
||||
subset_name = get_subset_name_with_asset_doc(
|
||||
self.family,
|
||||
variant,
|
||||
task_name,
|
||||
asset_doc,
|
||||
project_name
|
||||
)
|
||||
except TaskNotSetError:
|
||||
# Create instance with fake task
|
||||
# - instance will be marked as invalid so it can't be published
|
||||
# but user have ability to change it
|
||||
# NOTE: This expect that there is not task 'Undefined' on asset
|
||||
task_name = "Undefined"
|
||||
subset_name = get_subset_name_with_asset_doc(
|
||||
self.family,
|
||||
variant,
|
||||
task_name,
|
||||
asset_doc,
|
||||
project_name
|
||||
)
|
||||
|
||||
return subset_name, task_name
|
||||
|
||||
def _get_task_name(self, asset_doc):
|
||||
"""Get applicable task from 'asset_doc' """
|
||||
available_task_names = {}
|
||||
asset_tasks = asset_doc.get("data", {}).get("tasks") or {}
|
||||
for task_name in asset_tasks.keys():
|
||||
available_task_names[task_name.lower()] = task_name
|
||||
|
||||
task_name = None
|
||||
for _task_name in self.default_tasks:
|
||||
_task_name_low = _task_name.lower()
|
||||
if _task_name_low in available_task_names:
|
||||
task_name = available_task_names[_task_name_low]
|
||||
break
|
||||
|
||||
return task_name
|
||||
|
||||
def get_instance_attr_defs(self):
|
||||
return [
|
||||
BoolDef(
|
||||
"add_review_family",
|
||||
default=True,
|
||||
label="Review"
|
||||
)
|
||||
]
|
||||
|
||||
def get_pre_create_attr_defs(self):
|
||||
# Use same attributes as for instance attributes
|
||||
return [
|
||||
FileDef(
|
||||
"filepath",
|
||||
folders=False,
|
||||
single_item=False,
|
||||
extensions=self.extensions,
|
||||
label="Filepath"
|
||||
),
|
||||
BoolDef(
|
||||
"add_review_family",
|
||||
default=True,
|
||||
label="Review"
|
||||
)
|
||||
]
|
||||
|
||||
def get_detail_description(self):
|
||||
return """# Publish batch of .mov to multiple assets.
|
||||
|
||||
File names must then contain only asset name, or asset name + version.
|
||||
(eg. 'chair.mov', 'chair_v001.mov', not really safe `my_chair_v001.mov`
|
||||
"""
|
||||
|
||||
def _get_asset_by_name_case_not_sensitive(self, project_name, asset_name):
|
||||
"""Handle more cases in file names"""
|
||||
asset_name = re.compile(asset_name, re.IGNORECASE)
|
||||
|
||||
assets = list(get_assets(project_name, asset_names=[asset_name]))
|
||||
if assets:
|
||||
if len(assets) > 1:
|
||||
self.log.warning("Too many records found for {}".format(
|
||||
asset_name))
|
||||
return
|
||||
|
||||
return assets.pop()
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import os
|
||||
|
||||
import pyblish.api
|
||||
from openpype.pipeline import OpenPypePyblishPluginMixin
|
||||
|
||||
|
||||
class CollectMovieBatch(
|
||||
pyblish.api.InstancePlugin, OpenPypePyblishPluginMixin
|
||||
):
|
||||
"""Collect file url for batch movies and create representation.
|
||||
|
||||
Adds review on instance and to repre.tags based on value of toggle button
|
||||
on creator.
|
||||
"""
|
||||
|
||||
label = "Collect Movie Batch Files"
|
||||
order = pyblish.api.CollectorOrder
|
||||
|
||||
hosts = ["traypublisher"]
|
||||
|
||||
def process(self, instance):
|
||||
if instance.data.get("creator_identifier") != "render_movie_batch":
|
||||
return
|
||||
|
||||
creator_attributes = instance.data["creator_attributes"]
|
||||
|
||||
file_url = creator_attributes["filepath"]
|
||||
file_name = os.path.basename(file_url)
|
||||
_, ext = os.path.splitext(file_name)
|
||||
|
||||
repre = {
|
||||
"name": ext[1:],
|
||||
"ext": ext[1:],
|
||||
"files": file_name,
|
||||
"stagingDir": os.path.dirname(file_url),
|
||||
"tags": []
|
||||
}
|
||||
|
||||
if creator_attributes["add_review_family"]:
|
||||
repre["tags"].append("review")
|
||||
instance.data["families"].append("review")
|
||||
|
||||
instance.data["representations"].append(repre)
|
||||
|
||||
instance.data["source"] = file_url
|
||||
|
||||
self.log.debug("instance.data {}".format(instance.data))
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root>
|
||||
<error id="main">
|
||||
<title>Invalid frame range</title>
|
||||
<description>
|
||||
## Invalid frame range
|
||||
|
||||
Expected duration or '{duration}' frames set in database, workfile contains only '{found}' frames.
|
||||
|
||||
### How to repair?
|
||||
|
||||
Modify configuration in the database or tweak frame range in the workfile.
|
||||
</description>
|
||||
</error>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
import re
|
||||
|
||||
import pyblish.api
|
||||
|
||||
import openpype.api
|
||||
from openpype.pipeline import (
|
||||
PublishXmlValidationError,
|
||||
OptionalPyblishPluginMixin
|
||||
)
|
||||
|
||||
|
||||
class ValidateFrameRange(OptionalPyblishPluginMixin,
|
||||
pyblish.api.InstancePlugin):
|
||||
"""Validating frame range of rendered files against state in DB."""
|
||||
|
||||
label = "Validate Frame Range"
|
||||
hosts = ["traypublisher"]
|
||||
families = ["render"]
|
||||
order = openpype.api.ValidateContentsOrder
|
||||
|
||||
optional = True
|
||||
# published data might be sequence (.mov, .mp4) in that counting files
|
||||
# doesnt make sense
|
||||
check_extensions = ["exr", "dpx", "jpg", "jpeg", "png", "tiff", "tga",
|
||||
"gif", "svg"]
|
||||
skip_timelines_check = [] # skip for specific task names (regex)
|
||||
|
||||
def process(self, instance):
|
||||
# Skip the instance if is not active by data on the instance
|
||||
if not self.is_active(instance.data):
|
||||
return
|
||||
|
||||
if (self.skip_timelines_check and
|
||||
any(re.search(pattern, instance.data["task"])
|
||||
for pattern in self.skip_timelines_check)):
|
||||
self.log.info("Skipping for {} task".format(instance.data["task"]))
|
||||
|
||||
asset_doc = instance.data["assetEntity"]
|
||||
asset_data = asset_doc["data"]
|
||||
frame_start = asset_data["frameStart"]
|
||||
frame_end = asset_data["frameEnd"]
|
||||
handle_start = asset_data["handleStart"]
|
||||
handle_end = asset_data["handleEnd"]
|
||||
duration = (frame_end - frame_start + 1) + handle_start + handle_end
|
||||
|
||||
repres = instance.data.get("representations")
|
||||
if not repres:
|
||||
self.log.info("No representations, skipping.")
|
||||
return
|
||||
|
||||
first_repre = repres[0]
|
||||
ext = first_repre['ext'].replace(".", '')
|
||||
|
||||
if not ext or ext.lower() not in self.check_extensions:
|
||||
self.log.warning("Cannot check for extension {}".format(ext))
|
||||
return
|
||||
|
||||
files = first_repre["files"]
|
||||
if isinstance(files, str):
|
||||
files = [files]
|
||||
frames = len(files)
|
||||
|
||||
msg = (
|
||||
"Frame duration from DB:'{}' doesn't match number of files:'{}'"
|
||||
" Please change frame range for Asset or limit no. of files"
|
||||
). format(int(duration), frames)
|
||||
|
||||
formatting_data = {"duration": duration,
|
||||
"found": frames}
|
||||
if frames != duration:
|
||||
raise PublishXmlValidationError(self, msg,
|
||||
formatting_data=formatting_data)
|
||||
|
||||
self.log.debug("Valid ranges expected '{}' - found '{}'".
|
||||
format(int(duration), frames))
|
||||
|
|
@ -582,10 +582,10 @@ def get_workdir_with_workdir_data(
|
|||
|
||||
anatomy_filled = anatomy.format(workdir_data)
|
||||
# Output is TemplateResult object which contain useful data
|
||||
path = anatomy_filled[template_key]["folder"]
|
||||
if path:
|
||||
path = os.path.normpath(path)
|
||||
return path
|
||||
output = anatomy_filled[template_key]["folder"]
|
||||
if output:
|
||||
return output.normalized()
|
||||
return output
|
||||
|
||||
|
||||
def get_workdir(
|
||||
|
|
|
|||
|
|
@ -409,6 +409,19 @@ class TemplateResult(str):
|
|||
self.invalid_types
|
||||
)
|
||||
|
||||
def normalized(self):
|
||||
"""Convert to normalized path."""
|
||||
|
||||
cls = self.__class__
|
||||
return cls(
|
||||
os.path.normpath(self),
|
||||
self.template,
|
||||
self.solved,
|
||||
self.used_values,
|
||||
self.missing_keys,
|
||||
self.invalid_types
|
||||
)
|
||||
|
||||
|
||||
class TemplatesResultDict(dict):
|
||||
"""Holds and wrap TemplateResults for easy bug report."""
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ def pack_project(project_name, destination_dir=None):
|
|||
|
||||
Args:
|
||||
project_name(str): Project that should be packaged.
|
||||
destination_dir(str): Optinal path where zip will be stored. Project's
|
||||
destination_dir(str): Optional path where zip will be stored. Project's
|
||||
root is used if not passed.
|
||||
"""
|
||||
print("Creating package of project \"{}\"".format(project_name))
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ class _ModuleClass(object):
|
|||
Object of this class can be stored to `sys.modules` and used for storing
|
||||
dynamically imported modules.
|
||||
"""
|
||||
|
||||
def __init__(self, name):
|
||||
# Call setattr on super class
|
||||
super(_ModuleClass, self).__setattr__("name", name)
|
||||
|
|
@ -116,12 +117,13 @@ class _InterfacesClass(_ModuleClass):
|
|||
- this is because interfaces must be available even if are missing
|
||||
implementation
|
||||
"""
|
||||
|
||||
def __getattr__(self, attr_name):
|
||||
if attr_name not in self.__attributes__:
|
||||
if attr_name in ("__path__", "__file__"):
|
||||
return None
|
||||
|
||||
raise ImportError((
|
||||
raise AttributeError((
|
||||
"cannot import name '{}' from 'openpype_interfaces'"
|
||||
).format(attr_name))
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class HoudiniSubmitPublishDeadline(pyblish.api.ContextPlugin):
|
|||
scenename = os.path.basename(scene)
|
||||
|
||||
# Get project code
|
||||
project = legacy_io.find_one({"type": "project"})
|
||||
project = context.data["projectEntity"]
|
||||
code = project["data"].get("code", project["name"])
|
||||
|
||||
job_name = "{scene} [PUBLISH]".format(scene=scenename)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import clique
|
|||
import pyblish.api
|
||||
|
||||
import openpype.api
|
||||
from openpype.client import get_representations
|
||||
from openpype.pipeline import (
|
||||
get_representation_path,
|
||||
legacy_io,
|
||||
|
|
@ -18,15 +19,23 @@ from openpype.pipeline import (
|
|||
from openpype.pipeline.farm.patterning import match_aov_pattern
|
||||
|
||||
|
||||
def get_resources(version, extension=None):
|
||||
def get_resources(project_name, version, extension=None):
|
||||
"""Get the files from the specific version."""
|
||||
query = {"type": "representation", "parent": version["_id"]}
|
||||
|
||||
# TODO this functions seems to be weird
|
||||
# - it's looking for representation with one extension or first (any)
|
||||
# representation from a version?
|
||||
# - not sure how this should work, maybe it does for specific use cases
|
||||
# but probably can't be used for all resources from 2D workflows
|
||||
extensions = None
|
||||
if extension:
|
||||
query["name"] = extension
|
||||
|
||||
representation = legacy_io.find_one(query)
|
||||
assert representation, "This is a bug"
|
||||
extensions = [extension]
|
||||
repre_docs = list(get_representations(
|
||||
project_name, version_ids=[version["_id"]], extensions=extensions
|
||||
))
|
||||
assert repre_docs, "This is a bug"
|
||||
|
||||
representation = repre_docs[0]
|
||||
directory = get_representation_path(representation)
|
||||
print("Source: ", directory)
|
||||
resources = sorted(
|
||||
|
|
@ -330,13 +339,16 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
|
|||
self.log.info("Preparing to copy ...")
|
||||
start = instance.data.get("frameStart")
|
||||
end = instance.data.get("frameEnd")
|
||||
project_name = legacy_io.active_project()
|
||||
|
||||
# get latest version of subset
|
||||
# this will stop if subset wasn't published yet
|
||||
version = openpype.api.get_latest_version(instance.data.get("asset"),
|
||||
instance.data.get("subset"))
|
||||
# get its files based on extension
|
||||
subset_resources = get_resources(version, representation.get("ext"))
|
||||
subset_resources = get_resources(
|
||||
project_name, version, representation.get("ext")
|
||||
)
|
||||
r_col, _ = clique.assemble(subset_resources)
|
||||
|
||||
# if override remove all frames we are expecting to be rendered
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ import collections
|
|||
import ftrack_api
|
||||
|
||||
from openpype.lib import get_datetime_data
|
||||
from openpype.api import get_project_settings
|
||||
from openpype.settings.lib import (
|
||||
get_project_settings,
|
||||
get_default_project_settings
|
||||
)
|
||||
from openpype_modules.ftrack.lib import ServerAction
|
||||
|
||||
|
||||
|
|
@ -79,6 +82,35 @@ class CreateDailyReviewSessionServerAction(ServerAction):
|
|||
)
|
||||
return True
|
||||
|
||||
def _calculate_next_cycle_delta(self):
|
||||
studio_default_settings = get_default_project_settings()
|
||||
action_settings = (
|
||||
studio_default_settings
|
||||
["ftrack"]
|
||||
[self.settings_frack_subkey]
|
||||
[self.settings_key]
|
||||
)
|
||||
cycle_hour_start = action_settings.get("cycle_hour_start")
|
||||
if not cycle_hour_start:
|
||||
h = m = s = 0
|
||||
else:
|
||||
h, m, s = cycle_hour_start
|
||||
|
||||
# Create threading timer which will trigger creation of report
|
||||
# at the 00:00:01 of next day
|
||||
# - callback will trigger another timer which will have 1 day offset
|
||||
now = datetime.datetime.now()
|
||||
# Create object of today morning
|
||||
expected_next_trigger = datetime.datetime(
|
||||
now.year, now.month, now.day, h, m, s
|
||||
)
|
||||
if expected_next_trigger > now:
|
||||
seconds = (expected_next_trigger - now).total_seconds()
|
||||
else:
|
||||
expected_next_trigger += self._day_delta
|
||||
seconds = (expected_next_trigger - now).total_seconds()
|
||||
return seconds, expected_next_trigger
|
||||
|
||||
def register(self, *args, **kwargs):
|
||||
"""Override register to be able trigger """
|
||||
# Register server action as would be normally
|
||||
|
|
@ -86,22 +118,14 @@ class CreateDailyReviewSessionServerAction(ServerAction):
|
|||
*args, **kwargs
|
||||
)
|
||||
|
||||
# Create threading timer which will trigger creation of report
|
||||
# at the 00:00:01 of next day
|
||||
# - callback will trigger another timer which will have 1 day offset
|
||||
now = datetime.datetime.now()
|
||||
# Create object of today morning
|
||||
today_morning = datetime.datetime(
|
||||
now.year, now.month, now.day, 0, 0, 1
|
||||
)
|
||||
# Add a day delta (to calculate next day date)
|
||||
next_day_morning = today_morning + self._day_delta
|
||||
# Calculate first delta in seconds for first threading timer
|
||||
first_delta = (next_day_morning - now).total_seconds()
|
||||
seconds_delta, cycle_time = self._calculate_next_cycle_delta()
|
||||
|
||||
# Store cycle time which will be used to create next timer
|
||||
self._last_cyle_time = next_day_morning
|
||||
self._last_cyle_time = cycle_time
|
||||
# Create timer thread
|
||||
self._cycle_timer = threading.Timer(first_delta, self._timer_callback)
|
||||
self._cycle_timer = threading.Timer(
|
||||
seconds_delta, self._timer_callback
|
||||
)
|
||||
self._cycle_timer.start()
|
||||
|
||||
self._check_review_session()
|
||||
|
|
@ -111,13 +135,12 @@ class CreateDailyReviewSessionServerAction(ServerAction):
|
|||
self._cycle_timer is not None
|
||||
and self._last_cyle_time is not None
|
||||
):
|
||||
now = datetime.datetime.now()
|
||||
while self._last_cyle_time < now:
|
||||
self._last_cyle_time = self._last_cyle_time + self._day_delta
|
||||
seconds_delta, cycle_time = self._calculate_next_cycle_delta()
|
||||
self._last_cyle_time = cycle_time
|
||||
|
||||
delay = (self._last_cyle_time - now).total_seconds()
|
||||
|
||||
self._cycle_timer = threading.Timer(delay, self._timer_callback)
|
||||
self._cycle_timer = threading.Timer(
|
||||
seconds_delta, self._timer_callback
|
||||
)
|
||||
self._cycle_timer.start()
|
||||
self._check_review_session()
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,17 @@ import os
|
|||
|
||||
import gazu
|
||||
|
||||
from openpype.client import (
|
||||
get_project,
|
||||
get_assets,
|
||||
get_asset_by_name
|
||||
)
|
||||
from openpype.pipeline import AvalonMongoDB
|
||||
from .credentials import validate_credentials
|
||||
from .update_op_with_zou import (
|
||||
create_op_asset,
|
||||
set_op_project,
|
||||
get_kitsu_project_name,
|
||||
write_project_to_op,
|
||||
update_op_assets,
|
||||
)
|
||||
|
|
@ -119,17 +125,16 @@ class Listener:
|
|||
|
||||
# Write into DB
|
||||
if update_project:
|
||||
self.dbcon = self.dbcon.database[project_name]
|
||||
self.dbcon.Session["AVALON_PROJECT"] = project_name
|
||||
self.dbcon.bulk_write([update_project])
|
||||
|
||||
def _delete_project(self, data):
|
||||
"""Delete project."""
|
||||
project_doc = self.dbcon.find_one(
|
||||
{"type": "project", "data.zou_id": data["project_id"]}
|
||||
)
|
||||
|
||||
project_name = get_kitsu_project_name(data["project_id"])
|
||||
|
||||
# Delete project collection
|
||||
self.dbcon.database[project_doc["name"]].drop()
|
||||
self.dbcon.database[project_name].drop()
|
||||
|
||||
# == Asset ==
|
||||
|
||||
|
|
@ -150,7 +155,8 @@ class Listener:
|
|||
def _update_asset(self, data):
|
||||
"""Update asset into OP DB."""
|
||||
set_op_project(self.dbcon, data["project_id"])
|
||||
project_doc = self.dbcon.find_one({"type": "project"})
|
||||
project_name = self.dbcon.active_project()
|
||||
project_doc = get_project(project_name)
|
||||
|
||||
# Get gazu entity
|
||||
asset = gazu.asset.get_asset(data["asset_id"])
|
||||
|
|
@ -159,7 +165,7 @@ class Listener:
|
|||
# Query all assets of the local project
|
||||
zou_ids_and_asset_docs = {
|
||||
asset_doc["data"]["zou"]["id"]: asset_doc
|
||||
for asset_doc in self.dbcon.find({"type": "asset"})
|
||||
for asset_doc in get_assets(project_name)
|
||||
if asset_doc["data"].get("zou", {}).get("id")
|
||||
}
|
||||
zou_ids_and_asset_docs[asset["project_id"]] = project_doc
|
||||
|
|
@ -199,7 +205,8 @@ class Listener:
|
|||
def _update_episode(self, data):
|
||||
"""Update episode into OP DB."""
|
||||
set_op_project(self.dbcon, data["project_id"])
|
||||
project_doc = self.dbcon.find_one({"type": "project"})
|
||||
project_name = self.dbcon.active_project()
|
||||
project_doc = get_project(project_name)
|
||||
|
||||
# Get gazu entity
|
||||
episode = gazu.shot.get_episode(data["episode_id"])
|
||||
|
|
@ -208,7 +215,7 @@ class Listener:
|
|||
# Query all assets of the local project
|
||||
zou_ids_and_asset_docs = {
|
||||
asset_doc["data"]["zou"]["id"]: asset_doc
|
||||
for asset_doc in self.dbcon.find({"type": "asset"})
|
||||
for asset_doc in get_assets(project_name)
|
||||
if asset_doc["data"].get("zou", {}).get("id")
|
||||
}
|
||||
zou_ids_and_asset_docs[episode["project_id"]] = project_doc
|
||||
|
|
@ -249,7 +256,8 @@ class Listener:
|
|||
def _update_sequence(self, data):
|
||||
"""Update sequence into OP DB."""
|
||||
set_op_project(self.dbcon, data["project_id"])
|
||||
project_doc = self.dbcon.find_one({"type": "project"})
|
||||
project_name = self.dbcon.active_project()
|
||||
project_doc = get_project(project_name)
|
||||
|
||||
# Get gazu entity
|
||||
sequence = gazu.shot.get_sequence(data["sequence_id"])
|
||||
|
|
@ -258,7 +266,7 @@ class Listener:
|
|||
# Query all assets of the local project
|
||||
zou_ids_and_asset_docs = {
|
||||
asset_doc["data"]["zou"]["id"]: asset_doc
|
||||
for asset_doc in self.dbcon.find({"type": "asset"})
|
||||
for asset_doc in get_assets(project_name)
|
||||
if asset_doc["data"].get("zou", {}).get("id")
|
||||
}
|
||||
zou_ids_and_asset_docs[sequence["project_id"]] = project_doc
|
||||
|
|
@ -299,7 +307,8 @@ class Listener:
|
|||
def _update_shot(self, data):
|
||||
"""Update shot into OP DB."""
|
||||
set_op_project(self.dbcon, data["project_id"])
|
||||
project_doc = self.dbcon.find_one({"type": "project"})
|
||||
project_name = self.dbcon.active_project()
|
||||
project_doc = get_project(project_name)
|
||||
|
||||
# Get gazu entity
|
||||
shot = gazu.shot.get_shot(data["shot_id"])
|
||||
|
|
@ -308,7 +317,7 @@ class Listener:
|
|||
# Query all assets of the local project
|
||||
zou_ids_and_asset_docs = {
|
||||
asset_doc["data"]["zou"]["id"]: asset_doc
|
||||
for asset_doc in self.dbcon.find({"type": "asset"})
|
||||
for asset_doc in get_assets(project_name)
|
||||
if asset_doc["data"].get("zou", {}).get("id")
|
||||
}
|
||||
zou_ids_and_asset_docs[shot["project_id"]] = project_doc
|
||||
|
|
@ -335,14 +344,15 @@ class Listener:
|
|||
"""Create new task into OP DB."""
|
||||
# Get project entity
|
||||
set_op_project(self.dbcon, data["project_id"])
|
||||
project_name = self.dbcon.active_project()
|
||||
|
||||
# Get gazu entity
|
||||
task = gazu.task.get_task(data["task_id"])
|
||||
|
||||
# Find asset doc
|
||||
asset_doc = self.dbcon.find_one(
|
||||
{"type": "asset", "data.zou.id": task["entity"]["id"]}
|
||||
)
|
||||
parent_name = task["entity"]["name"]
|
||||
|
||||
asset_doc = get_asset_by_name(project_name, parent_name)
|
||||
|
||||
# Update asset tasks with new one
|
||||
asset_tasks = asset_doc["data"].get("tasks")
|
||||
|
|
@ -359,10 +369,11 @@ class Listener:
|
|||
|
||||
def _delete_task(self, data):
|
||||
"""Delete task of OP DB."""
|
||||
set_op_project(self.dbcon, data["project_id"])
|
||||
|
||||
set_op_project(self.dbcon, data["project_id"])
|
||||
project_name = self.dbcon.active_project()
|
||||
# Find asset doc
|
||||
asset_docs = [doc for doc in self.dbcon.find({"type": "asset"})]
|
||||
asset_docs = list(get_assets(project_name))
|
||||
for doc in asset_docs:
|
||||
# Match task
|
||||
for name, task in doc["data"]["tasks"].items():
|
||||
|
|
|
|||
|
|
@ -10,6 +10,12 @@ from gazu.task import (
|
|||
all_tasks_for_shot,
|
||||
)
|
||||
|
||||
from openpype.client import (
|
||||
get_project,
|
||||
get_assets,
|
||||
get_asset_by_id,
|
||||
get_asset_by_name,
|
||||
)
|
||||
from openpype.pipeline import AvalonMongoDB
|
||||
from openpype.api import get_project_settings
|
||||
from openpype.lib import create_project
|
||||
|
|
@ -33,6 +39,20 @@ def create_op_asset(gazu_entity: dict) -> dict:
|
|||
}
|
||||
|
||||
|
||||
def get_kitsu_project_name(project_id: str) -> str:
|
||||
"""Get project name based on project id in kitsu.
|
||||
|
||||
Args:
|
||||
project_id (str): UUID of project in Kitsu.
|
||||
|
||||
Returns:
|
||||
str: Name of Kitsu project.
|
||||
"""
|
||||
|
||||
project = gazu.project.get_project(project_id)
|
||||
return project["name"]
|
||||
|
||||
|
||||
def set_op_project(dbcon: AvalonMongoDB, project_id: str):
|
||||
"""Set project context.
|
||||
|
||||
|
|
@ -40,9 +60,8 @@ def set_op_project(dbcon: AvalonMongoDB, project_id: str):
|
|||
dbcon (AvalonMongoDB): Connection to DB
|
||||
project_id (str): Project zou ID
|
||||
"""
|
||||
project = gazu.project.get_project(project_id)
|
||||
project_name = project["name"]
|
||||
dbcon.Session["AVALON_PROJECT"] = project_name
|
||||
|
||||
dbcon.Session["AVALON_PROJECT"] = get_kitsu_project_name(project_id)
|
||||
|
||||
|
||||
def update_op_assets(
|
||||
|
|
@ -72,9 +91,7 @@ def update_op_assets(
|
|||
if not item_doc: # Create asset
|
||||
op_asset = create_op_asset(item)
|
||||
insert_result = dbcon.insert_one(op_asset)
|
||||
item_doc = dbcon.find_one(
|
||||
{"type": "asset", "_id": insert_result.inserted_id}
|
||||
)
|
||||
item_doc = get_asset_by_id(project_name, insert_result.inserted_id)
|
||||
|
||||
# Update asset
|
||||
item_data = deepcopy(item_doc["data"])
|
||||
|
|
@ -137,17 +154,23 @@ def update_op_assets(
|
|||
parent_zou_id = substitute_parent_item["parent_id"]
|
||||
else:
|
||||
parent_zou_id = (
|
||||
item.get("parent_id")
|
||||
# For Asset, put under asset type directory
|
||||
item.get("entity_type_id")
|
||||
if item_type == "Asset"
|
||||
else None
|
||||
# Else, fallback on usual hierarchy
|
||||
or item.get("parent_id")
|
||||
or item.get("episode_id")
|
||||
or item.get("source_id")
|
||||
) # TODO check consistency
|
||||
)
|
||||
|
||||
# Substitute Episode and Sequence by Shot
|
||||
substitute_item_type = (
|
||||
"shots"
|
||||
if item_type in ["Episode", "Sequence"]
|
||||
else f"{item_type.lower()}s"
|
||||
)
|
||||
# Substitute item type for general classification (assets or shots)
|
||||
if item_type in ["Asset", "AssetType"]:
|
||||
substitute_item_type = "assets"
|
||||
elif item_type in ["Episode", "Sequence"]:
|
||||
substitute_item_type = "shots"
|
||||
else:
|
||||
substitute_item_type = f"{item_type.lower()}s"
|
||||
entity_parent_folders = [
|
||||
f
|
||||
for f in project_module_settings["entities_root"]
|
||||
|
|
@ -161,15 +184,33 @@ def update_op_assets(
|
|||
asset_doc_ids[parent_zou_id]["_id"] if parent_zou_id else None
|
||||
)
|
||||
if visual_parent_doc_id is None:
|
||||
# Find root folder doc
|
||||
root_folder_doc = dbcon.find_one(
|
||||
{
|
||||
"type": "asset",
|
||||
"name": entity_parent_folders[-1],
|
||||
"data.root_of": substitute_item_type,
|
||||
},
|
||||
["_id"],
|
||||
# Find root folder docs
|
||||
root_folder_docs = get_assets(
|
||||
project_name,
|
||||
asset_names=[entity_parent_folders[-1]],
|
||||
fields=["_id", "data.root_of"],
|
||||
)
|
||||
# NOTE: Not sure why it's checking for entity type?
|
||||
# OP3 does not support multiple assets with same names so type
|
||||
# filtering is irelevant.
|
||||
# This way mimics previous implementation:
|
||||
# ```
|
||||
# root_folder_doc = dbcon.find_one(
|
||||
# {
|
||||
# "type": "asset",
|
||||
# "name": entity_parent_folders[-1],
|
||||
# "data.root_of": substitute_item_type,
|
||||
# },
|
||||
# ["_id"],
|
||||
# )
|
||||
# ```
|
||||
root_folder_doc = None
|
||||
for folder_doc in root_folder_docs:
|
||||
root_of = folder_doc.get("data", {}).get("root_of")
|
||||
if root_of == substitute_item_type:
|
||||
root_folder_doc = folder_doc
|
||||
break
|
||||
|
||||
if root_folder_doc:
|
||||
visual_parent_doc_id = root_folder_doc["_id"]
|
||||
|
||||
|
|
@ -184,7 +225,14 @@ def update_op_assets(
|
|||
|
||||
# Get parent entity
|
||||
parent_entity = parent_doc["data"]["zou"]
|
||||
parent_zou_id = parent_entity["parent_id"]
|
||||
parent_zou_id = parent_entity.get("parent_id")
|
||||
|
||||
if item_type in ["Shot", "Sequence"]:
|
||||
# Name with parents hierarchy "({episode}_){sequence}_{shot}"
|
||||
# to avoid duplicate name issue
|
||||
item_name = "_".join(item_data["parents"] + [item_doc["name"]])
|
||||
else:
|
||||
item_name = item_doc["name"]
|
||||
|
||||
# Set root folders parents
|
||||
item_data["parents"] = entity_parent_folders + item_data["parents"]
|
||||
|
|
@ -199,9 +247,9 @@ def update_op_assets(
|
|||
item_doc["_id"],
|
||||
{
|
||||
"$set": {
|
||||
"name": item["name"],
|
||||
"name": item_name,
|
||||
"data": item_data,
|
||||
"parent": asset_doc_ids[item["project_id"]]["_id"],
|
||||
"parent": project_doc["_id"],
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
@ -222,7 +270,7 @@ def write_project_to_op(project: dict, dbcon: AvalonMongoDB) -> UpdateOne:
|
|||
UpdateOne: Update instance for the project
|
||||
"""
|
||||
project_name = project["name"]
|
||||
project_doc = dbcon.database[project_name].find_one({"type": "project"})
|
||||
project_doc = get_project(project_name)
|
||||
if not project_doc:
|
||||
print(f"Creating project '{project_name}'")
|
||||
project_doc = create_project(project_name, project_name, dbcon=dbcon)
|
||||
|
|
@ -292,6 +340,11 @@ def sync_all_projects(login: str, password: str):
|
|||
def sync_project_from_kitsu(dbcon: AvalonMongoDB, project: dict):
|
||||
"""Update OP project in DB with Zou data.
|
||||
|
||||
`root_of` is meant to sort entities by type for a better readability in
|
||||
the data tree. It puts all shot like (Shot and Episode and Sequence) and
|
||||
asset entities under two different root folders or hierarchy, defined in
|
||||
settings.
|
||||
|
||||
Args:
|
||||
dbcon (AvalonMongoDB): MongoDB connection
|
||||
project (dict): Project dict got using gazu.
|
||||
|
|
@ -306,12 +359,17 @@ def sync_project_from_kitsu(dbcon: AvalonMongoDB, project: dict):
|
|||
|
||||
# Get all assets from zou
|
||||
all_assets = gazu.asset.all_assets_for_project(project)
|
||||
all_asset_types = gazu.asset.all_asset_types_for_project(project)
|
||||
all_episodes = gazu.shot.all_episodes_for_project(project)
|
||||
all_seqs = gazu.shot.all_sequences_for_project(project)
|
||||
all_shots = gazu.shot.all_shots_for_project(project)
|
||||
all_entities = [
|
||||
item
|
||||
for item in all_assets + all_episodes + all_seqs + all_shots
|
||||
for item in all_assets
|
||||
+ all_asset_types
|
||||
+ all_episodes
|
||||
+ all_seqs
|
||||
+ all_shots
|
||||
if naming_pattern.match(item["name"])
|
||||
]
|
||||
|
||||
|
|
@ -319,26 +377,44 @@ def sync_project_from_kitsu(dbcon: AvalonMongoDB, project: dict):
|
|||
bulk_writes.append(write_project_to_op(project, dbcon))
|
||||
|
||||
# Try to find project document
|
||||
dbcon.Session["AVALON_PROJECT"] = project["name"]
|
||||
project_doc = dbcon.find_one({"type": "project"})
|
||||
project_name = project["name"]
|
||||
dbcon.Session["AVALON_PROJECT"] = project_name
|
||||
project_doc = get_project(project_name)
|
||||
|
||||
# Query all assets of the local project
|
||||
zou_ids_and_asset_docs = {
|
||||
asset_doc["data"]["zou"]["id"]: asset_doc
|
||||
for asset_doc in dbcon.find({"type": "asset"})
|
||||
for asset_doc in get_assets(project_name)
|
||||
if asset_doc["data"].get("zou", {}).get("id")
|
||||
}
|
||||
zou_ids_and_asset_docs[project["id"]] = project_doc
|
||||
|
||||
# Create entities root folders
|
||||
project_module_settings = get_project_settings(project["name"])["kitsu"]
|
||||
project_module_settings = get_project_settings(project_name)["kitsu"]
|
||||
for entity_type, root in project_module_settings["entities_root"].items():
|
||||
parent_folders = root.split("/")
|
||||
direct_parent_doc = None
|
||||
for i, folder in enumerate(parent_folders, 1):
|
||||
parent_doc = dbcon.find_one(
|
||||
{"type": "asset", "name": folder, "data.root_of": entity_type}
|
||||
parent_doc = get_asset_by_name(
|
||||
project_name, folder, fields=["_id", "data.root_of"]
|
||||
)
|
||||
# NOTE: Not sure why it's checking for entity type?
|
||||
# OP3 does not support multiple assets with same names so type
|
||||
# filtering is irelevant.
|
||||
# Also all of the entities could find be queried at once using
|
||||
# 'get_assets'.
|
||||
# This way mimics previous implementation:
|
||||
# ```
|
||||
# parent_doc = dbcon.find_one(
|
||||
# {"type": "asset", "name": folder, "data.root_of": entity_type}
|
||||
# )
|
||||
# ```
|
||||
if (
|
||||
parent_doc
|
||||
and parent_doc.get("data", {}).get("root_of") != entity_type
|
||||
):
|
||||
parent_doc = None
|
||||
|
||||
if not parent_doc:
|
||||
direct_parent_doc = dbcon.insert_one(
|
||||
{
|
||||
|
|
@ -348,21 +424,20 @@ def sync_project_from_kitsu(dbcon: AvalonMongoDB, project: dict):
|
|||
"data": {
|
||||
"root_of": entity_type,
|
||||
"parents": parent_folders[:i],
|
||||
"visualParent": direct_parent_doc,
|
||||
"visualParent": direct_parent_doc.inserted_id
|
||||
if direct_parent_doc
|
||||
else None,
|
||||
"tasks": {},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
# Create
|
||||
to_insert = []
|
||||
to_insert.extend(
|
||||
[
|
||||
create_op_asset(item)
|
||||
for item in all_entities
|
||||
if item["id"] not in zou_ids_and_asset_docs.keys()
|
||||
]
|
||||
)
|
||||
to_insert = [
|
||||
create_op_asset(item)
|
||||
for item in all_entities
|
||||
if item["id"] not in zou_ids_and_asset_docs.keys()
|
||||
]
|
||||
if to_insert:
|
||||
# Insert doc in DB
|
||||
dbcon.insert_many(to_insert)
|
||||
|
|
@ -371,7 +446,7 @@ def sync_project_from_kitsu(dbcon: AvalonMongoDB, project: dict):
|
|||
zou_ids_and_asset_docs.update(
|
||||
{
|
||||
asset_doc["data"]["zou"]["id"]: asset_doc
|
||||
for asset_doc in dbcon.find({"type": "asset"})
|
||||
for asset_doc in get_assets(project_name)
|
||||
if asset_doc["data"].get("zou")
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ from typing import List
|
|||
import gazu
|
||||
from pymongo import UpdateOne
|
||||
|
||||
from openpype.client import get_project, get_assets
|
||||
from openpype.pipeline import AvalonMongoDB
|
||||
from openpype.api import get_project_settings
|
||||
from openpype.modules.kitsu.utils.credentials import validate_credentials
|
||||
|
|
@ -53,9 +54,7 @@ def sync_zou_from_op_project(
|
|||
"""
|
||||
# Get project doc if not provided
|
||||
if not project_doc:
|
||||
project_doc = dbcon.database[project_name].find_one(
|
||||
{"type": "project"}
|
||||
)
|
||||
project_doc = get_project(project_name)
|
||||
|
||||
# Get all entities from zou
|
||||
print(f"Synchronizing {project_name}...")
|
||||
|
|
@ -96,7 +95,7 @@ def sync_zou_from_op_project(
|
|||
dbcon.Session["AVALON_PROJECT"] = project_name
|
||||
asset_docs = {
|
||||
asset_doc["_id"]: asset_doc
|
||||
for asset_doc in dbcon.find({"type": "asset"})
|
||||
for asset_doc in get_assets(project_name)
|
||||
}
|
||||
|
||||
# Create new assets
|
||||
|
|
|
|||
|
|
@ -380,6 +380,19 @@ class AnatomyTemplateResult(TemplateResult):
|
|||
)
|
||||
return self.__class__(tmp, self.rootless)
|
||||
|
||||
def normalized(self):
|
||||
"""Convert to normalized path."""
|
||||
|
||||
tmp = TemplateResult(
|
||||
os.path.normpath(self),
|
||||
self.template,
|
||||
self.solved,
|
||||
self.used_values,
|
||||
self.missing_keys,
|
||||
self.invalid_types
|
||||
)
|
||||
return self.__class__(tmp, self.rootless)
|
||||
|
||||
|
||||
class AnatomyTemplates(TemplatesDict):
|
||||
inner_key_pattern = re.compile(r"(\{@.*?[^{}0]*\})")
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class ExtractThumbnail(pyblish.api.InstancePlugin):
|
|||
"imagesequence", "render", "render2d", "prerender",
|
||||
"source", "plate", "take"
|
||||
]
|
||||
hosts = ["shell", "fusion", "resolve"]
|
||||
hosts = ["shell", "fusion", "resolve", "traypublisher"]
|
||||
enabled = False
|
||||
|
||||
# presetable attribute
|
||||
|
|
@ -46,6 +46,10 @@ class ExtractThumbnail(pyblish.api.InstancePlugin):
|
|||
self.log.info("Skipping - no review set on instance.")
|
||||
return
|
||||
|
||||
if self._already_has_thumbnail(instance):
|
||||
self.log.info("Thumbnail representation already present.")
|
||||
return
|
||||
|
||||
filtered_repres = self._get_filtered_repres(instance)
|
||||
for repre in filtered_repres:
|
||||
repre_files = repre["files"]
|
||||
|
|
@ -102,6 +106,14 @@ class ExtractThumbnail(pyblish.api.InstancePlugin):
|
|||
# There is no need to create more then one thumbnail
|
||||
break
|
||||
|
||||
def _already_has_thumbnail(self, instance):
|
||||
for repre in instance.data.get("representations", []):
|
||||
self.log.info("repre {}".format(repre))
|
||||
if repre["name"] == "thumbnail":
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _get_filtered_repres(self, instance):
|
||||
filtered_repres = []
|
||||
src_repres = instance.data.get("representations") or []
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import time
|
|||
|
||||
from openpype.lib import PypeLogger
|
||||
from openpype.api import get_app_environments_for_context
|
||||
from openpype.lib.plugin_tools import parse_json, get_batch_asset_task_info
|
||||
from openpype.lib.plugin_tools import get_batch_asset_task_info
|
||||
from openpype.lib.remote_publish import (
|
||||
get_webpublish_conn,
|
||||
start_webpublish_log,
|
||||
|
|
|
|||
|
|
@ -124,6 +124,11 @@
|
|||
"Project Manager"
|
||||
],
|
||||
"cycle_enabled": false,
|
||||
"cycle_hour_start": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"review_session_template": "{yy}{mm}{dd}"
|
||||
}
|
||||
},
|
||||
|
|
@ -268,6 +273,49 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hosts": [
|
||||
"traypublisher"
|
||||
],
|
||||
"families": [],
|
||||
"task_types": [],
|
||||
"tasks": [],
|
||||
"add_ftrack_family": true,
|
||||
"advanced_filtering": []
|
||||
},
|
||||
{
|
||||
"hosts": [
|
||||
"traypublisher"
|
||||
],
|
||||
"families": [
|
||||
"matchmove",
|
||||
"shot"
|
||||
],
|
||||
"task_types": [],
|
||||
"tasks": [],
|
||||
"add_ftrack_family": false,
|
||||
"advanced_filtering": []
|
||||
},
|
||||
{
|
||||
"hosts": [
|
||||
"traypublisher"
|
||||
],
|
||||
"families": [
|
||||
"plate"
|
||||
],
|
||||
"task_types": [],
|
||||
"tasks": [],
|
||||
"add_ftrack_family": false,
|
||||
"advanced_filtering": [
|
||||
{
|
||||
"families": [
|
||||
"clip",
|
||||
"review"
|
||||
],
|
||||
"add_ftrack_family": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hosts": [
|
||||
"maya"
|
||||
|
|
|
|||
|
|
@ -205,10 +205,15 @@
|
|||
"enabled": true,
|
||||
"optional": true,
|
||||
"active": true,
|
||||
"exclude_families": ["model", "rig", "staticMesh"]
|
||||
"exclude_families": [
|
||||
"model",
|
||||
"rig",
|
||||
"staticMesh"
|
||||
]
|
||||
},
|
||||
"ValidateShaderName": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
"regex": "(?P<asset>.*)_(.*)_SHD"
|
||||
},
|
||||
"ValidateShadingEngine": {
|
||||
|
|
@ -222,6 +227,7 @@
|
|||
},
|
||||
"ValidateLoadedPlugin": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
"whitelist_native_plugins": false,
|
||||
"authorized_plugins": []
|
||||
},
|
||||
|
|
@ -236,6 +242,7 @@
|
|||
},
|
||||
"ValidateUnrealStaticMeshName": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"validate_mesh": false,
|
||||
"validate_collision": true
|
||||
},
|
||||
|
|
@ -252,6 +259,81 @@
|
|||
"redshift_render_attributes": [],
|
||||
"renderman_render_attributes": []
|
||||
},
|
||||
"ValidateCurrentRenderLayerIsRenderable": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateRenderImageRule": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateRenderNoDefaultCameras": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateRenderSingleCamera": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateRenderLayerAOVs": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateStepSize": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateVRayDistributedRendering": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateVrayReferencedAOVs": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateVRayTranslatorEnabled": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateVrayProxy": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateVrayProxyMembers": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateYetiRenderScriptCallbacks": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateYetiRigCacheState": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateYetiRigInputShapesInInstance": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateYetiRigSettings": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateModelName": {
|
||||
"enabled": false,
|
||||
"database": true,
|
||||
|
|
@ -270,6 +352,7 @@
|
|||
},
|
||||
"ValidateTransformNamingSuffix": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"SUFFIX_NAMING_TABLE": {
|
||||
"mesh": [
|
||||
"_GEO",
|
||||
|
|
@ -293,7 +376,7 @@
|
|||
"ALLOW_IF_NOT_IN_SUFFIX_TABLE": true
|
||||
},
|
||||
"ValidateColorSets": {
|
||||
"enabled": false,
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
|
|
@ -337,6 +420,16 @@
|
|||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateMeshNoNegativeScale": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateMeshNonZeroEdgeLength": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateMeshNormalsUnlocked": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
|
|
@ -359,22 +452,22 @@
|
|||
},
|
||||
"ValidateNoNamespace": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateNoNullTransforms": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateNoUnknownNodes": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateNodeNoGhosting": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateShapeDefaultNames": {
|
||||
|
|
@ -402,6 +495,21 @@
|
|||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateNoVRayMesh": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateUnrealMeshTriangulated": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateAlembicVisibleOnly": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ExtractAlembic": {
|
||||
"enabled": true,
|
||||
"families": [
|
||||
|
|
@ -425,8 +533,34 @@
|
|||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateAnimationContent": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateOutRelatedNodeIds": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateRigControllersArnoldAttributes": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateSkeletalMeshHierarchy": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateSkinclusterDeformerSet": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateRigOutSetNodeIds": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"allow_history_only": false
|
||||
},
|
||||
"ValidateCameraAttributes": {
|
||||
|
|
@ -439,14 +573,44 @@
|
|||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateAssemblyNamespaces": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateAssemblyModelTransforms": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateAssRelativePaths": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateInstancerContent": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateInstancerFrameRanges": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateNoDefaultCameras": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true
|
||||
},
|
||||
"ValidateUnrealUpAxis": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateCameraContents": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"optional": false,
|
||||
"validate_shapes": true
|
||||
},
|
||||
"ExtractPlayblast": {
|
||||
|
|
|
|||
|
|
@ -235,5 +235,12 @@
|
|||
"allow_multiple_items": true,
|
||||
"extensions": []
|
||||
}
|
||||
]
|
||||
],
|
||||
"BatchMovieCreator": {
|
||||
"default_variants": ["Main"],
|
||||
"default_tasks": ["Compositing"],
|
||||
"extensions": [
|
||||
".mov"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -2,11 +2,7 @@
|
|||
"studio_name": "Studio name",
|
||||
"studio_code": "stu",
|
||||
"admin_password": "",
|
||||
"environment": {
|
||||
"__environment_keys__": {
|
||||
"global": []
|
||||
}
|
||||
},
|
||||
"environment": {},
|
||||
"log_to_server": true,
|
||||
"disk_mapping": {
|
||||
"windows": [],
|
||||
|
|
|
|||
|
|
@ -169,6 +169,7 @@ class HostsEnumEntity(BaseEnumEntity):
|
|||
"tvpaint",
|
||||
"unreal",
|
||||
"standalonepublisher",
|
||||
"traypublisher",
|
||||
"webpublisher"
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -410,7 +410,41 @@
|
|||
{
|
||||
"type": "boolean",
|
||||
"key": "cycle_enabled",
|
||||
"label": "Create daily review session"
|
||||
"label": "Run automatically every day"
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"type": "list-strict",
|
||||
"key": "cycle_hour_start",
|
||||
"label": "Create daily review session at",
|
||||
"tooltip": "This may take affect on next day",
|
||||
"object_types": [
|
||||
{
|
||||
"label": "H:",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 23,
|
||||
"decimal": 0
|
||||
}, {
|
||||
"label": "M:",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 59,
|
||||
"decimal": 0
|
||||
}, {
|
||||
"label": "S:",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 59,
|
||||
"decimal": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "This can't be overriden per project and any change will take effect on the next day or on restart of event server."
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
|
|
|
|||
|
|
@ -83,6 +83,44 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "BatchMovieCreator",
|
||||
"label": "Batch Movie Creator",
|
||||
"collapsible_key": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Allows to publish multiple video files in one go. <br />Name of matching asset is parsed from file names ('asset.mov', 'asset_v001.mov', 'my_asset_to_publish.mov')"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "default_variants",
|
||||
"label": "Default variants",
|
||||
"object_type": {
|
||||
"type": "text"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "default_tasks",
|
||||
"label": "Default tasks",
|
||||
"object_type": {
|
||||
"type": "text"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "extensions",
|
||||
"label": "Extensions",
|
||||
"use_label_wrap": true,
|
||||
"collapsible_key": true,
|
||||
"collapsed": false,
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,6 +107,11 @@
|
|||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "optional",
|
||||
"label": "Optional"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Shader name regex can use named capture group <b>asset</b> to validate against current asset name.<p><b>Example:</b><br/><code>^.*(?P=<asset>.+)_SHD</code></p>"
|
||||
|
|
@ -159,6 +164,11 @@
|
|||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "optional",
|
||||
"label": "Optional"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "whitelist_native_plugins",
|
||||
|
|
@ -246,6 +256,11 @@
|
|||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "optional",
|
||||
"label": "Optional"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "validate_mesh",
|
||||
|
|
@ -332,6 +347,72 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_publish_plugin",
|
||||
"template_data": [
|
||||
{
|
||||
"key": "ValidateCurrentRenderLayerIsRenderable",
|
||||
"label": "Validate Current Render Layer Has Renderable Camera"
|
||||
},
|
||||
{
|
||||
"key": "ValidateRenderImageRule",
|
||||
"label": "Validate Images File Rule (Workspace)"
|
||||
},
|
||||
{
|
||||
"key": "ValidateRenderNoDefaultCameras",
|
||||
"label": "Validate No Default Cameras Renderable"
|
||||
},
|
||||
{
|
||||
"key": "ValidateRenderSingleCamera",
|
||||
"label": "Validate Render Single Camera"
|
||||
},
|
||||
{
|
||||
"key": "ValidateRenderLayerAOVs",
|
||||
"label": "Validate Render Passes / AOVs Are Registered"
|
||||
},
|
||||
{
|
||||
"key": "ValidateStepSize",
|
||||
"label": "Validate Step Size"
|
||||
},
|
||||
{
|
||||
"key": "ValidateVRayDistributedRendering",
|
||||
"label": "VRay Distributed Rendering"
|
||||
},
|
||||
{
|
||||
"key": "ValidateVrayReferencedAOVs",
|
||||
"label": "VRay Referenced AOVs"
|
||||
},
|
||||
{
|
||||
"key": "ValidateVRayTranslatorEnabled",
|
||||
"label": "VRay Translator Settings"
|
||||
},
|
||||
{
|
||||
"key": "ValidateVrayProxy",
|
||||
"label": "VRay Proxy Settings"
|
||||
},
|
||||
{
|
||||
"key": "ValidateVrayProxyMembers",
|
||||
"label": "VRay Proxy Members"
|
||||
},
|
||||
{
|
||||
"key": "ValidateYetiRenderScriptCallbacks",
|
||||
"label": "Yeti Render Script Callbacks"
|
||||
},
|
||||
{
|
||||
"key": "ValidateYetiRigCacheState",
|
||||
"label": "Yeti Rig Cache State"
|
||||
},
|
||||
{
|
||||
"key": "ValidateYetiRigInputShapesInInstance",
|
||||
"label": "Yeti Rig Input Shapes In Instance"
|
||||
},
|
||||
{
|
||||
"key": "ValidateYetiRigSettings",
|
||||
"label": "Yeti Rig Settings"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "collapsible-wrap",
|
||||
"label": "Model",
|
||||
|
|
@ -416,6 +497,11 @@
|
|||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "optional",
|
||||
"label": "Optional"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Validates transform suffix based on the type of its children shapes."
|
||||
|
|
@ -472,6 +558,14 @@
|
|||
"key": "ValidateMeshNonManifold",
|
||||
"label": "ValidateMeshNonManifold"
|
||||
},
|
||||
{
|
||||
"key": "ValidateMeshNoNegativeScale",
|
||||
"label": "Validate Mesh No Negative Scale"
|
||||
},
|
||||
{
|
||||
"key": "ValidateMeshNonZeroEdgeLength",
|
||||
"label": "Validate Mesh Edge Length Non Zero"
|
||||
},
|
||||
{
|
||||
"key": "ValidateMeshNormalsUnlocked",
|
||||
"label": "ValidateMeshNormalsUnlocked"
|
||||
|
|
@ -525,6 +619,18 @@
|
|||
{
|
||||
"key": "ValidateUniqueNames",
|
||||
"label": "ValidateUniqueNames"
|
||||
},
|
||||
{
|
||||
"key": "ValidateNoVRayMesh",
|
||||
"label": "Validate No V-Ray Proxies (VRayMesh)"
|
||||
},
|
||||
{
|
||||
"key": "ValidateUnrealMeshTriangulated",
|
||||
"label": "Validate if Mesh is Triangulated"
|
||||
},
|
||||
{
|
||||
"key": "ValidateAlembicVisibleOnly",
|
||||
"label": "Validate Alembic visible node"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -573,6 +679,26 @@
|
|||
{
|
||||
"key": "ValidateRigControllers",
|
||||
"label": "Validate Rig Controllers"
|
||||
},
|
||||
{
|
||||
"key": "ValidateAnimationContent",
|
||||
"label": "Validate Animation Content"
|
||||
},
|
||||
{
|
||||
"key": "ValidateOutRelatedNodeIds",
|
||||
"label": "Validate Animation Out Set Related Node Ids"
|
||||
},
|
||||
{
|
||||
"key": "ValidateRigControllersArnoldAttributes",
|
||||
"label": "Validate Rig Controllers (Arnold Attributes)"
|
||||
},
|
||||
{
|
||||
"key": "ValidateSkeletalMeshHierarchy",
|
||||
"label": "Validate Skeletal Mesh Top Node"
|
||||
},
|
||||
{
|
||||
"key": "ValidateSkinclusterDeformerSet",
|
||||
"label": "Validate Skincluster Deformer Relationships"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -589,6 +715,11 @@
|
|||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "optional",
|
||||
"label": "Optional"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "allow_history_only",
|
||||
|
|
@ -611,9 +742,33 @@
|
|||
"key": "ValidateAssemblyName",
|
||||
"label": "Validate Assembly Name"
|
||||
},
|
||||
{
|
||||
"key": "ValidateAssemblyNamespaces",
|
||||
"label": "Validate Assembly Namespaces"
|
||||
},
|
||||
{
|
||||
"key": "ValidateAssemblyModelTransforms",
|
||||
"label": "Validate Assembly Model Transforms"
|
||||
},
|
||||
{
|
||||
"key": "ValidateAssRelativePaths",
|
||||
"label": "ValidateAssRelativePaths"
|
||||
},
|
||||
{
|
||||
"key": "ValidateInstancerContent",
|
||||
"label": "Validate Instancer Content"
|
||||
},
|
||||
{
|
||||
"key": "ValidateInstancerFrameRanges",
|
||||
"label": "Validate Instancer Cache Frame Ranges"
|
||||
},
|
||||
{
|
||||
"key": "ValidateNoDefaultCameras",
|
||||
"label": "Validate No Default Cameras"
|
||||
},
|
||||
{
|
||||
"key": "ValidateUnrealUpAxis",
|
||||
"label": "Validate Unreal Up-Axis check"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import uuid
|
||||
import html
|
||||
from Qt import QtCore, QtGui
|
||||
|
||||
import pyblish.api
|
||||
|
|
@ -45,7 +46,8 @@ class InstancesModel(QtGui.QStandardItemModel):
|
|||
all_removed = True
|
||||
for instance_item in instance_items:
|
||||
item = QtGui.QStandardItem(instance_item.label)
|
||||
item.setData(instance_item.label, ITEM_LABEL_ROLE)
|
||||
instance_label = html.escape(instance_item.label)
|
||||
item.setData(instance_label, ITEM_LABEL_ROLE)
|
||||
item.setData(instance_item.errored, ITEM_ERRORED_ROLE)
|
||||
item.setData(instance_item.id, ITEM_ID_ROLE)
|
||||
item.setData(instance_item.removed, INSTANCE_REMOVED_ROLE)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ Only one item can be selected at a time.
|
|||
|
||||
import re
|
||||
import collections
|
||||
import html
|
||||
|
||||
from Qt import QtWidgets, QtCore
|
||||
|
||||
|
|
@ -98,6 +99,7 @@ class GroupWidget(QtWidgets.QWidget):
|
|||
instances(list<CreatedInstance>): List of instances in
|
||||
CreateContext.
|
||||
"""
|
||||
|
||||
# Store instances by id and by subset name
|
||||
instances_by_id = {}
|
||||
instances_by_subset_name = collections.defaultdict(list)
|
||||
|
|
@ -142,6 +144,7 @@ class GroupWidget(QtWidgets.QWidget):
|
|||
|
||||
class CardWidget(BaseClickableFrame):
|
||||
"""Clickable card used as bigger button."""
|
||||
|
||||
selected = QtCore.Signal(str, str)
|
||||
# Group identifier of card
|
||||
# - this must be set because if send when mouse is released with card id
|
||||
|
|
@ -178,6 +181,7 @@ class ContextCardWidget(CardWidget):
|
|||
|
||||
Is not visually under group widget and is always at the top of card view.
|
||||
"""
|
||||
|
||||
def __init__(self, parent):
|
||||
super(ContextCardWidget, self).__init__(parent)
|
||||
|
||||
|
|
@ -204,13 +208,14 @@ class ContextCardWidget(CardWidget):
|
|||
|
||||
class InstanceCardWidget(CardWidget):
|
||||
"""Card widget representing instance."""
|
||||
|
||||
active_changed = QtCore.Signal()
|
||||
|
||||
def __init__(self, instance, group_icon, parent):
|
||||
super(InstanceCardWidget, self).__init__(parent)
|
||||
|
||||
self._id = instance.id
|
||||
self._group_identifier = instance.creator_label
|
||||
self._group_identifier = instance.group_label
|
||||
self._group_icon = group_icon
|
||||
|
||||
self.instance = instance
|
||||
|
|
@ -303,7 +308,7 @@ class InstanceCardWidget(CardWidget):
|
|||
self._last_variant = variant
|
||||
self._last_subset_name = subset_name
|
||||
# Make `variant` bold
|
||||
label = self.instance.label
|
||||
label = html.escape(self.instance.label)
|
||||
found_parts = set(re.findall(variant, label, re.IGNORECASE))
|
||||
if found_parts:
|
||||
for part in found_parts:
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ selection can be enabled disabled using checkbox or keyboard key presses:
|
|||
```
|
||||
"""
|
||||
import collections
|
||||
import html
|
||||
|
||||
from Qt import QtWidgets, QtCore, QtGui
|
||||
|
||||
|
|
@ -113,7 +114,9 @@ class InstanceListItemWidget(QtWidgets.QWidget):
|
|||
|
||||
self.instance = instance
|
||||
|
||||
subset_name_label = QtWidgets.QLabel(instance.label, self)
|
||||
instance_label = html.escape(instance.label)
|
||||
|
||||
subset_name_label = QtWidgets.QLabel(instance_label, self)
|
||||
subset_name_label.setObjectName("ListViewSubsetName")
|
||||
|
||||
active_checkbox = NiceCheckbox(parent=self)
|
||||
|
|
@ -178,7 +181,7 @@ class InstanceListItemWidget(QtWidgets.QWidget):
|
|||
# Check subset name
|
||||
label = self.instance.label
|
||||
if label != self._instance_label_widget.text():
|
||||
self._instance_label_widget.setText(label)
|
||||
self._instance_label_widget.setText(html.escape(label))
|
||||
# Check active state
|
||||
self.set_active(self.instance["active"])
|
||||
# Check valid states
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
from .widgets import (
|
||||
CustomTextComboBox,
|
||||
PlaceholderLineEdit,
|
||||
BaseClickableFrame,
|
||||
ClickableFrame,
|
||||
|
|
@ -28,6 +29,7 @@ from .overlay_messages import (
|
|||
|
||||
|
||||
__all__ = (
|
||||
"CustomTextComboBox",
|
||||
"PlaceholderLineEdit",
|
||||
"BaseClickableFrame",
|
||||
"ClickableFrame",
|
||||
|
|
|
|||
|
|
@ -60,31 +60,14 @@ class HostToolsHelper:
|
|||
|
||||
return self._workfiles_tool
|
||||
|
||||
def show_workfiles(self, parent=None, use_context=None, save=None):
|
||||
def show_workfiles(
|
||||
self, parent=None, use_context=None, save=None, on_top=None
|
||||
):
|
||||
"""Workfiles tool for changing context and saving workfiles."""
|
||||
if use_context is None:
|
||||
use_context = True
|
||||
|
||||
if save is None:
|
||||
save = True
|
||||
|
||||
with qt_app_context():
|
||||
workfiles_tool = self.get_workfiles_tool(parent)
|
||||
workfiles_tool.set_save_enabled(save)
|
||||
|
||||
if not workfiles_tool.isVisible():
|
||||
workfiles_tool.show()
|
||||
|
||||
if use_context:
|
||||
context = {
|
||||
"asset": legacy_io.Session["AVALON_ASSET"],
|
||||
"task": legacy_io.Session["AVALON_TASK"]
|
||||
}
|
||||
workfiles_tool.set_context(context)
|
||||
|
||||
# Pull window to the front.
|
||||
workfiles_tool.raise_()
|
||||
workfiles_tool.activateWindow()
|
||||
workfiles_tool.ensure_visible(use_context, save, on_top)
|
||||
|
||||
def get_loader_tool(self, parent):
|
||||
"""Create, cache and return loader tool window."""
|
||||
|
|
@ -395,9 +378,9 @@ def show_tool_by_name(tool_name, parent=None, *args, **kwargs):
|
|||
_SingletonPoint.show_tool_by_name(tool_name, parent, *args, **kwargs)
|
||||
|
||||
|
||||
def show_workfiles(parent=None, use_context=None, save=None):
|
||||
def show_workfiles(*args, **kwargs):
|
||||
_SingletonPoint.show_tool_by_name(
|
||||
"workfiles", parent, use_context=use_context, save=save
|
||||
"workfiles", *args, **kwargs
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,28 @@ from openpype.style import (
|
|||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CustomTextComboBox(QtWidgets.QComboBox):
|
||||
"""Combobox which can have different text showed."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._custom_text = None
|
||||
super(CustomTextComboBox, self).__init__(*args, **kwargs)
|
||||
|
||||
def set_custom_text(self, text=None):
|
||||
if self._custom_text != text:
|
||||
self._custom_text = text
|
||||
self.repaint()
|
||||
|
||||
def paintEvent(self, event):
|
||||
painter = QtWidgets.QStylePainter(self)
|
||||
option = QtWidgets.QStyleOptionComboBox()
|
||||
self.initStyleOption(option)
|
||||
if self._custom_text is not None:
|
||||
option.currentText = self._custom_text
|
||||
painter.drawComplexControl(QtWidgets.QStyle.CC_ComboBox, option)
|
||||
painter.drawControl(QtWidgets.QStyle.CE_ComboBoxLabel, option)
|
||||
|
||||
|
||||
class PlaceholderLineEdit(QtWidgets.QLineEdit):
|
||||
"""Set placeholder color of QLineEdit in Qt 5.12 and higher."""
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import os
|
||||
import datetime
|
||||
from Qt import QtCore, QtWidgets
|
||||
from Qt import QtCore, QtWidgets, QtGui
|
||||
|
||||
from openpype.client import (
|
||||
get_asset_by_id,
|
||||
|
|
@ -8,6 +8,7 @@ from openpype.client import (
|
|||
get_workfile_info,
|
||||
)
|
||||
from openpype import style
|
||||
from openpype import resources
|
||||
from openpype.lib import (
|
||||
create_workfile_doc,
|
||||
save_workfile_data_to_doc,
|
||||
|
|
@ -142,21 +143,19 @@ class SidePanelWidget(QtWidgets.QWidget):
|
|||
return self._workfile_doc, data
|
||||
|
||||
|
||||
class Window(QtWidgets.QMainWindow):
|
||||
class Window(QtWidgets.QWidget):
|
||||
"""Work Files Window"""
|
||||
title = "Work Files"
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(Window, self).__init__(parent=parent)
|
||||
self.setWindowTitle(self.title)
|
||||
window_flags = QtCore.Qt.Window | QtCore.Qt.WindowCloseButtonHint
|
||||
if not parent:
|
||||
window_flags |= QtCore.Qt.WindowStaysOnTopHint
|
||||
self.setWindowFlags(window_flags)
|
||||
icon = QtGui.QIcon(resources.get_openpype_icon_filepath())
|
||||
self.setWindowIcon(icon)
|
||||
self.setWindowFlags(self.windowFlags() | QtCore.Qt.Window)
|
||||
|
||||
# Create pages widget and set it as central widget
|
||||
pages_widget = QtWidgets.QStackedWidget(self)
|
||||
self.setCentralWidget(pages_widget)
|
||||
|
||||
home_page_widget = QtWidgets.QWidget(pages_widget)
|
||||
home_body_widget = QtWidgets.QWidget(home_page_widget)
|
||||
|
|
@ -191,6 +190,9 @@ class Window(QtWidgets.QMainWindow):
|
|||
# the files widget has a filter field which tasks does not.
|
||||
tasks_widget.setContentsMargins(0, 32, 0, 0)
|
||||
|
||||
main_layout = QtWidgets.QHBoxLayout(self)
|
||||
main_layout.addWidget(pages_widget, 1)
|
||||
|
||||
# Set context after asset widget is refreshed
|
||||
# - to do so it is necessary to wait until refresh is done
|
||||
set_context_timer = QtCore.QTimer()
|
||||
|
|
@ -227,6 +229,49 @@ class Window(QtWidgets.QMainWindow):
|
|||
self._first_show = True
|
||||
self._context_to_set = None
|
||||
|
||||
def ensure_visible(
|
||||
self, use_context=None, save=None, on_top=None
|
||||
):
|
||||
if save is None:
|
||||
save = True
|
||||
|
||||
self.set_save_enabled(save)
|
||||
|
||||
if self.isVisible():
|
||||
use_context = False
|
||||
elif use_context is None:
|
||||
use_context = True
|
||||
|
||||
if on_top is None and self._first_show:
|
||||
on_top = self.parent() is None
|
||||
|
||||
window_flags = self.windowFlags()
|
||||
new_window_flags = window_flags
|
||||
if on_top is True:
|
||||
new_window_flags = window_flags | QtCore.Qt.WindowStaysOnTopHint
|
||||
elif on_top is False:
|
||||
new_window_flags = window_flags & ~QtCore.Qt.WindowStaysOnTopHint
|
||||
|
||||
if new_window_flags != window_flags:
|
||||
# Note this is not propagated after initialization of widget in
|
||||
# some Qt builds
|
||||
self.setWindowFlags(new_window_flags)
|
||||
self.show()
|
||||
|
||||
elif not self.isVisible():
|
||||
self.show()
|
||||
|
||||
if use_context is None or use_context is True:
|
||||
context = {
|
||||
"asset": legacy_io.Session["AVALON_ASSET"],
|
||||
"task": legacy_io.Session["AVALON_TASK"]
|
||||
}
|
||||
self.set_context(context)
|
||||
|
||||
# Pull window to the front.
|
||||
self.raise_()
|
||||
self.activateWindow()
|
||||
|
||||
@property
|
||||
def project_name(self):
|
||||
return legacy_io.Session["AVALON_PROJECT"]
|
||||
|
|
@ -331,6 +376,7 @@ class Window(QtWidgets.QMainWindow):
|
|||
if self.assets_widget.refreshing:
|
||||
return
|
||||
|
||||
self._set_context_timer.stop()
|
||||
self._context_to_set, context = None, self._context_to_set
|
||||
if "asset" in context:
|
||||
asset_doc = get_asset_by_name(
|
||||
|
|
|
|||
32
openpype/vendor/python/common/capture.py
vendored
|
|
@ -403,7 +403,7 @@ def apply_view(panel, **options):
|
|||
camera_options = options.get("camera_options", {})
|
||||
_iteritems = getattr(camera_options, "iteritems", camera_options.items)
|
||||
for key, value in _iteritems:
|
||||
cmds.setAttr("{0}.{1}".format(camera, key), value)
|
||||
_safe_setAttr("{0}.{1}".format(camera, key), value)
|
||||
|
||||
# Viewport options
|
||||
viewport_options = options.get("viewport_options", {})
|
||||
|
|
@ -417,7 +417,7 @@ def apply_view(panel, **options):
|
|||
)
|
||||
for key, value in _iteritems():
|
||||
attr = "hardwareRenderingGlobals.{0}".format(key)
|
||||
cmds.setAttr(attr, value)
|
||||
_safe_setAttr(attr, value)
|
||||
|
||||
|
||||
def parse_active_panel():
|
||||
|
|
@ -551,10 +551,10 @@ def apply_scene(**options):
|
|||
cmds.playbackOptions(maxTime=options["end_frame"])
|
||||
|
||||
if "width" in options:
|
||||
cmds.setAttr("defaultResolution.width", options["width"])
|
||||
_safe_setAttr("defaultResolution.width", options["width"])
|
||||
|
||||
if "height" in options:
|
||||
cmds.setAttr("defaultResolution.height", options["height"])
|
||||
_safe_setAttr("defaultResolution.height", options["height"])
|
||||
|
||||
if "compression" in options:
|
||||
cmds.optionVar(
|
||||
|
|
@ -665,7 +665,7 @@ def _applied_camera_options(options, panel):
|
|||
|
||||
_iteritems = getattr(options, "iteritems", options.items)
|
||||
for opt, value in _iteritems():
|
||||
cmds.setAttr(camera + "." + opt, value)
|
||||
_safe_setAttr(camera + "." + opt, value)
|
||||
|
||||
try:
|
||||
yield
|
||||
|
|
@ -673,7 +673,7 @@ def _applied_camera_options(options, panel):
|
|||
if old_options:
|
||||
_iteritems = getattr(old_options, "iteritems", old_options.items)
|
||||
for opt, value in _iteritems():
|
||||
cmds.setAttr(camera + "." + opt, value)
|
||||
_safe_setAttr(camera + "." + opt, value)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
|
|
@ -760,7 +760,7 @@ def _applied_viewport2_options(options):
|
|||
# Apply settings
|
||||
_iteritems = getattr(options, "iteritems", options.items)
|
||||
for opt, value in _iteritems():
|
||||
cmds.setAttr("hardwareRenderingGlobals." + opt, value)
|
||||
_safe_setAttr("hardwareRenderingGlobals." + opt, value)
|
||||
|
||||
try:
|
||||
yield
|
||||
|
|
@ -768,7 +768,7 @@ def _applied_viewport2_options(options):
|
|||
# Restore previous settings
|
||||
_iteritems = getattr(original, "iteritems", original.items)
|
||||
for opt, value in _iteritems():
|
||||
cmds.setAttr("hardwareRenderingGlobals." + opt, value)
|
||||
_safe_setAttr("hardwareRenderingGlobals." + opt, value)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
|
|
@ -802,14 +802,14 @@ def _maintain_camera(panel, camera):
|
|||
else:
|
||||
state = dict((camera, cmds.getAttr(camera + ".rnd"))
|
||||
for camera in cmds.ls(type="camera"))
|
||||
cmds.setAttr(camera + ".rnd", True)
|
||||
_safe_setAttr(camera + ".rnd", True)
|
||||
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
_iteritems = getattr(state, "iteritems", state.items)
|
||||
for camera, renderable in _iteritems():
|
||||
cmds.setAttr(camera + ".rnd", renderable)
|
||||
_safe_setAttr(camera + ".rnd", renderable)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
|
|
@ -846,6 +846,18 @@ def _in_standalone():
|
|||
return not hasattr(cmds, "about") or cmds.about(batch=True)
|
||||
|
||||
|
||||
def _safe_setAttr(*args, **kwargs):
|
||||
"""Wrapper to handle failures when attribute is locked.
|
||||
|
||||
Temporary hotfix until better approach (store value, unlock, set new,
|
||||
return old, lock again) is implemented.
|
||||
"""
|
||||
try:
|
||||
cmds.setAttr(*args, **kwargs)
|
||||
except RuntimeError:
|
||||
print("Cannot setAttr {}!".format(args))
|
||||
|
||||
|
||||
# --------------------------------
|
||||
#
|
||||
# Apply version specific settings
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Package declaring Pype version."""
|
||||
__version__ = "3.12.1"
|
||||
__version__ = "3.12.2-nightly.2"
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ from openpype.lib.attribute_definitions import (
|
|||
UISeparatorDef,
|
||||
UILabelDef
|
||||
)
|
||||
from openpype.tools.utils import CustomTextComboBox
|
||||
from openpype.widgets.nice_checkbox import NiceCheckbox
|
||||
|
||||
from .files_widget import FilesWidget
|
||||
|
|
@ -369,8 +370,12 @@ class BoolAttrWidget(_BaseAttrDefWidget):
|
|||
|
||||
|
||||
class EnumAttrWidget(_BaseAttrDefWidget):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._multivalue = False
|
||||
super(EnumAttrWidget, self).__init__(*args, **kwargs)
|
||||
|
||||
def _ui_init(self):
|
||||
input_widget = QtWidgets.QComboBox(self)
|
||||
input_widget = CustomTextComboBox(self)
|
||||
combo_delegate = QtWidgets.QStyledItemDelegate(input_widget)
|
||||
input_widget.setItemDelegate(combo_delegate)
|
||||
|
||||
|
|
@ -394,6 +399,9 @@ class EnumAttrWidget(_BaseAttrDefWidget):
|
|||
|
||||
def _on_value_change(self):
|
||||
new_value = self.current_value()
|
||||
if self._multivalue:
|
||||
self._multivalue = False
|
||||
self._input_widget.set_custom_text(None)
|
||||
self.value_changed.emit(new_value, self.attr_def.id)
|
||||
|
||||
def current_value(self):
|
||||
|
|
@ -401,14 +409,23 @@ class EnumAttrWidget(_BaseAttrDefWidget):
|
|||
return self._input_widget.itemData(idx)
|
||||
|
||||
def set_value(self, value, multivalue=False):
|
||||
if multivalue:
|
||||
set_value = set(value)
|
||||
if len(set_value) == 1:
|
||||
multivalue = False
|
||||
value = tuple(set_value)[0]
|
||||
|
||||
if not multivalue:
|
||||
idx = self._input_widget.findData(value)
|
||||
cur_idx = self._input_widget.currentIndex()
|
||||
if idx != cur_idx and idx >= 0:
|
||||
self._input_widget.setCurrentIndex(idx)
|
||||
|
||||
else:
|
||||
self._input_widget.lineEdit().setText("Multiselection")
|
||||
custom_text = None
|
||||
if multivalue:
|
||||
custom_text = "< Multiselection >"
|
||||
self._input_widget.set_custom_text(custom_text)
|
||||
self._multivalue = multivalue
|
||||
|
||||
|
||||
class UnknownAttrWidget(_BaseAttrDefWidget):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "OpenPype"
|
||||
version = "3.12.1" # OpenPype
|
||||
version = "3.12.2-nightly.2" # OpenPype
|
||||
description = "Open VFX and Animation pipeline with support."
|
||||
authors = ["OpenPype Team <info@openpype.io>"]
|
||||
license = "MIT License"
|
||||
|
|
@ -135,7 +135,7 @@ hash = "b9950f5d2fa3720b52b8be55bacf5f56d33f9e029d38ee86534995f3d8d253d2"
|
|||
|
||||
[openpype.thirdparty.oiio.linux]
|
||||
url = "https://distribute.openpype.io/thirdparty/oiio_tools-2.2.20-linux-centos7.tgz"
|
||||
hash = "be1abf8a50e9da5913298447421af0a17829d83ed6252ae1d40da7fa36a78787"
|
||||
hash = "3894dec7e4e521463891a869586850e8605f5fd604858b674c87323bf33e273d"
|
||||
|
||||
[openpype.thirdparty.oiio.darwin]
|
||||
url = "https://distribute.openpype.io/thirdparty/oiio-2.2.0-darwin.tgz"
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ $script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
|
|||
$openpype_root = (Get-Item $script_dir).parent.FullName
|
||||
|
||||
# Install PSWriteColor to support colorized output to terminal
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\vendor\powershell"
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\tools\modules\powershell"
|
||||
|
||||
function Start-Progress {
|
||||
param([ScriptBlock]$code)
|
||||
|
|
@ -189,6 +189,8 @@ Write-Color -Text ">>> ", "Restoring current directory" -Color Green, Gray
|
|||
Set-Location -Path $current_dir
|
||||
|
||||
$endTime = [int][double]::Parse((Get-Date -UFormat %s))
|
||||
New-BurntToastNotification -AppLogo "$openpype_root/openpype/resources/icons/openpype_icon.png" -Text "OpenPype build complete!", "All done in $($endTime - $startTime) secs. You will find OpenPype and build log in build directory."
|
||||
|
||||
try
|
||||
{
|
||||
New-BurntToastNotification -AppLogo "$openpype_root/openpype/resources/icons/openpype_icon.png" -Text "OpenPype build complete!", "All done in $( $endTime - $startTime ) secs. You will find OpenPype and build log in build directory."
|
||||
} catch {}
|
||||
Write-Color -Text "*** ", "All done in ", $($endTime - $startTime), " secs. You will find OpenPype and build log in ", "'.\build'", " directory." -Color Green, Gray, White, Gray, White, Gray
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ $script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
|
|||
$openpype_root = (Get-Item $script_dir).parent.FullName
|
||||
|
||||
# Install PSWriteColor to support colorized output to terminal
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\vendor\powershell"
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\tools\modules\powershell"
|
||||
|
||||
function Start-Progress {
|
||||
param([ScriptBlock]$code)
|
||||
|
|
@ -171,7 +171,7 @@ if ($LASTEXITCODE -ne 0) {
|
|||
|
||||
Write-Color -Text ">>> ", "Restoring current directory" -Color Green, Gray
|
||||
Set-Location -Path $current_dir
|
||||
|
||||
New-BurntToastNotification -AppLogo "$openpype_root/openpype/resources/icons/openpype_icon.png" -Text "OpenPype build complete!", "All done. You will find You will find OpenPype installer in '.\build' directory."
|
||||
|
||||
try {
|
||||
New-BurntToastNotification -AppLogo "$openpype_root/openpype/resources/icons/openpype_icon.png" -Text "OpenPype build complete!", "All done. You will find You will find OpenPype installer in '.\build' directory."
|
||||
} catch {}
|
||||
Write-Color -Text "*** ", "All done. You will find OpenPype installer in ", "'.\build'", " directory." -Color Green, Gray, White, Gray
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ $openpype_root = (Get-Item $script_dir).parent.FullName
|
|||
|
||||
& git submodule update --init --recursive
|
||||
# Install PSWriteColor to support colorized output to terminal
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\vendor\powershell"
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\tools\modules\powershell"
|
||||
|
||||
|
||||
function Exit-WithCode($exitcode) {
|
||||
|
|
@ -180,7 +180,8 @@ if ($LASTEXITCODE -ne 0) {
|
|||
}
|
||||
$endTime = [int][double]::Parse((Get-Date -UFormat %s))
|
||||
Set-Location -Path $current_dir
|
||||
|
||||
New-BurntToastNotification -AppLogo "$openpype_root/openpype/resources/icons/openpype_icon.png" -Text "OpenPype", "Virtual environment created.", "All done in $($endTime - $startTime) secs."
|
||||
|
||||
try
|
||||
{
|
||||
New-BurntToastNotification -AppLogo "$openpype_root/openpype/resources/icons/openpype_icon.png" -Text "OpenPype", "Virtual environment created.", "All done in $( $endTime - $startTime ) secs."
|
||||
} catch {}
|
||||
Write-Color -Text ">>> ", "Virtual environment created." -Color Green, White
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ $script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
|
|||
$openpype_root = (Get-Item $script_dir).parent.FullName
|
||||
|
||||
# Install PSWriteColor to support colorized output to terminal
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\vendor\powershell"
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\tools\modules\powershell"
|
||||
|
||||
function Exit-WithCode($exitcode) {
|
||||
# Only exit this host process if it's a child of another PowerShell parent process...
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ $script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
|
|||
$openpype_root = (Get-Item $script_dir).parent.FullName
|
||||
|
||||
# Install PSWriteColor to support colorized output to terminal
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\vendor\powershell"
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\tools\modules\powershell"
|
||||
|
||||
$env:_INSIDE_OPENPYPE_TOOL = "1"
|
||||
|
||||
|
|
@ -38,4 +38,7 @@ $startTime = [int][double]::Parse((Get-Date -UFormat %s))
|
|||
& "$($env:POETRY_HOME)\bin\poetry" run python "$($openpype_root)\tools\fetch_thirdparty_libs.py"
|
||||
$endTime = [int][double]::Parse((Get-Date -UFormat %s))
|
||||
Set-Location -Path $current_dir
|
||||
New-BurntToastNotification -AppLogo "$openpype_root/openpype/resources/icons/openpype_icon.png" -Text "OpenPype", "Dependencies downloaded", "All done in $($endTime - $startTime) secs."
|
||||
try
|
||||
{
|
||||
New-BurntToastNotification -AppLogo "$openpype_root/openpype/resources/icons/openpype_icon.png" -Text "OpenPype", "Dependencies downloaded", "All done in $( $endTime - $startTime ) secs."
|
||||
} catch {}
|
||||
|
|
@ -49,7 +49,7 @@ $script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
|
|||
$openpype_root = (Get-Item $script_dir).parent.FullName
|
||||
|
||||
# Install PSWriteColor to support colorized output to terminal
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\vendor\powershell"
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\tools\modules\powershell"
|
||||
|
||||
Write-Host $art -ForegroundColor DarkGreen
|
||||
|
||||
|
|
|
|||
1
tools/modules/powershell/BurntToast
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit f58c9a26d6ede30ecc7998e92b26974887e945fe
|
||||
1
tools/modules/powershell/PSWriteColor
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 12eda384ebd7a7954e15855e312215c009c97114
|
||||
39
tools/pack_project.ps1
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<#
|
||||
.SYNOPSIS
|
||||
Helper script OpenPype Packing project.
|
||||
|
||||
.DESCRIPTION
|
||||
Once you are happy with the project and want to preserve it for future work, just change the project name on line 38 and copy the file into .\OpenPype\tools. Then use the cmd form .EXAMPLE
|
||||
|
||||
.EXAMPLE
|
||||
|
||||
PS> .\tools\run_pack_project.ps1
|
||||
|
||||
#>
|
||||
$current_dir = Get-Location
|
||||
$script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
|
||||
$openpype_root = (Get-Item $script_dir).parent.FullName
|
||||
|
||||
$env:_INSIDE_OPENPYPE_TOOL = "1"
|
||||
|
||||
# make sure Poetry is in PATH
|
||||
if (-not (Test-Path 'env:POETRY_HOME')) {
|
||||
$env:POETRY_HOME = "$openpype_root\.poetry"
|
||||
}
|
||||
$env:PATH = "$($env:PATH);$($env:POETRY_HOME)\bin"
|
||||
|
||||
Set-Location -Path $openpype_root
|
||||
|
||||
Write-Host ">>> " -NoNewline -ForegroundColor Green
|
||||
Write-Host "Reading Poetry ... " -NoNewline
|
||||
if (-not (Test-Path -PathType Container -Path "$($env:POETRY_HOME)\bin")) {
|
||||
Write-Host "NOT FOUND" -ForegroundColor Yellow
|
||||
Write-Host "*** " -NoNewline -ForegroundColor Yellow
|
||||
Write-Host "We need to install Poetry create virtual env first ..."
|
||||
& "$openpype_root\tools\create_env.ps1"
|
||||
} else {
|
||||
Write-Host "OK" -ForegroundColor Green
|
||||
}
|
||||
|
||||
& "$($env:POETRY_HOME)\bin\poetry" run python "$($openpype_root)\start.py" pack-project --project $ARGS
|
||||
Set-Location -Path $current_dir
|
||||
|
|
@ -16,7 +16,7 @@ $script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
|
|||
$openpype_root = (Get-Item $script_dir).parent.FullName
|
||||
|
||||
# Install PSWriteColor to support colorized output to terminal
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\vendor\powershell"
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\tools\modules\powershell"
|
||||
|
||||
$art = @"
|
||||
|
||||
|
|
@ -50,7 +50,7 @@ function Exit-WithCode($exitcode) {
|
|||
|
||||
function Find-Mongo ($preferred_version) {
|
||||
$defaultPath = "C:\Program Files\MongoDB\Server"
|
||||
Write-Color -Text ">>> ", "Detecting MongoDB ... " -Color Geen, Gray -NoNewline
|
||||
Write-Color -Text ">>> ", "Detecting MongoDB ... " -Color Green, Gray -NoNewline
|
||||
if (-not (Get-Command "mongod" -ErrorAction SilentlyContinue)) {
|
||||
if(Test-Path "$($defaultPath)\*\bin\mongod.exe" -PathType Leaf) {
|
||||
# we have mongo server installed on standard Windows location
|
||||
|
|
@ -61,7 +61,7 @@ function Find-Mongo ($preferred_version) {
|
|||
Write-Color -Text "OK" -Color Green
|
||||
$use_version = $mongoVersions[-1]
|
||||
foreach ($v in $mongoVersions) {
|
||||
Write-Color -Text " - found [ ", $v, " ]" - Color Cyan, White, Cyan -NoNewLine
|
||||
Write-Color -Text " - found [ ", $v, " ]" -Color Cyan, White, Cyan -NoNewLine
|
||||
$version = Split-Path $v -Leaf
|
||||
|
||||
if ($preferred_version -eq $version) {
|
||||
|
|
@ -110,6 +110,6 @@ $preferred_version = "5.0"
|
|||
|
||||
$mongoPath = Find-Mongo $preferred_version
|
||||
Write-Color -Text ">>> ", "Using DB path: ", "[ ", "$($dbpath)", " ]" -Color Green, Gray, Cyan, White, Cyan
|
||||
Write-Color -Text ">>> ", "Port: ", "[ ", "$($port)", " ]", -Color Green, Gray, Cyan, White, Cyan
|
||||
Write-Color -Text ">>> ", "Port: ", "[ ", "$($port)", " ]" -Color Green, Gray, Cyan, White, Cyan
|
||||
|
||||
Start-Process -FilePath $mongopath "--dbpath $($dbpath) --port $($port)" -PassThru | Out-Null
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ $script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
|
|||
$openpype_root = (Get-Item $script_dir).parent.FullName
|
||||
|
||||
# Install PSWriteColor to support colorized output to terminal
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\vendor\powershell"
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\tools\modules\powershell"
|
||||
|
||||
$env:_INSIDE_OPENPYPE_TOOL = "1"
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ $script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
|
|||
$openpype_root = (Get-Item $script_dir).parent.FullName
|
||||
|
||||
# Install PSWriteColor to support colorized output to terminal
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\vendor\powershell"
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\tools\modules\powershell"
|
||||
|
||||
$env:_INSIDE_OPENPYPE_TOOL = "1"
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ $script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
|
|||
$openpype_root = (Get-Item $script_dir).parent.FullName
|
||||
|
||||
# Install PSWriteColor to support colorized output to terminal
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\vendor\powershell"
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\tools\modules\powershell"
|
||||
|
||||
function Exit-WithCode($exitcode) {
|
||||
# Only exit this host process if it's a child of another PowerShell parent process...
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ $script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
|
|||
$openpype_root = (Get-Item $script_dir).parent.FullName
|
||||
|
||||
# Install PSWriteColor to support colorized output to terminal
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\vendor\powershell"
|
||||
$env:PSModulePath = $env:PSModulePath + ";$($openpype_root)\tools\modules\powershell"
|
||||
|
||||
$env:_INSIDE_OPENPYPE_TOOL = "1"
|
||||
|
||||
|
|
|
|||
39
tools/unpack_project.ps1
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<#
|
||||
.SYNOPSIS
|
||||
Helper script OpenPype Unpacking project.
|
||||
|
||||
.DESCRIPTION
|
||||
Make sure you had dropped the project from your db and removed the poject data in case you were having them previously. Then on line 38 change the <Path to zip> to any path where the zip with project is - usually we are having it here https://drive.google.com/drive/u/0/folders/0AKE4mxImOsAGUk9PVA . Copy the file into .\OpenPype\tools. Then use the cmd form .EXAMPLE
|
||||
|
||||
.EXAMPLE
|
||||
|
||||
PS> .\tools\run_unpack_project.ps1
|
||||
|
||||
#>
|
||||
$current_dir = Get-Location
|
||||
$script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
|
||||
$openpype_root = (Get-Item $script_dir).parent.FullName
|
||||
|
||||
$env:_INSIDE_OPENPYPE_TOOL = "1"
|
||||
|
||||
# make sure Poetry is in PATH
|
||||
if (-not (Test-Path 'env:POETRY_HOME')) {
|
||||
$env:POETRY_HOME = "$openpype_root\.poetry"
|
||||
}
|
||||
$env:PATH = "$($env:PATH);$($env:POETRY_HOME)\bin"
|
||||
|
||||
Set-Location -Path $openpype_root
|
||||
|
||||
Write-Host ">>> " -NoNewline -ForegroundColor Green
|
||||
Write-Host "Reading Poetry ... " -NoNewline
|
||||
if (-not (Test-Path -PathType Container -Path "$($env:POETRY_HOME)\bin")) {
|
||||
Write-Host "NOT FOUND" -ForegroundColor Yellow
|
||||
Write-Host "*** " -NoNewline -ForegroundColor Yellow
|
||||
Write-Host "We need to install Poetry create virtual env first ..."
|
||||
& "$openpype_root\tools\create_env.ps1"
|
||||
} else {
|
||||
Write-Host "OK" -ForegroundColor Green
|
||||
}
|
||||
|
||||
& "$($env:POETRY_HOME)\bin\poetry" run python "$($openpype_root)\start.py" unpack-project --zipfile $ARGS
|
||||
Set-Location -Path $current_dir
|
||||
0
vendor/powershell/README.md
vendored
|
|
@ -45,6 +45,7 @@ For more information [see here](admin_use.md#run-openpype).
|
|||
| publish | Pype takes JSON from provided path and use it to publish data in it. | [📑](#publish-arguments) |
|
||||
| extractenvironments | Extract environment variables for entered context to a json file. | [📑](#extractenvironments-arguments) |
|
||||
| run | Execute given python script within OpenPype environment. | [📑](#run-arguments) |
|
||||
| interactive | Start python like interactive console session. | |
|
||||
| projectmanager | Launch Project Manager UI | [📑](#projectmanager-arguments) |
|
||||
| settings | Open Settings UI | [📑](#settings-arguments) |
|
||||
| standalonepublisher | Open Standalone Publisher UI | [📑](#standalonepublisher-arguments) |
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ Another optional function is **get_current_context**. This function is handy in
|
|||
Main responsibility of create plugin is to create, update, collect and remove instance metadata and propagate changes to create context. Has access to **CreateContext** (`self.create_context`) that discovered the plugin so has also access to other creators and instances. Create plugins have a lot of responsibility so it is recommended to implement common code per host.
|
||||
|
||||
#### *BaseCreator*
|
||||
Base implementation of creator plugin. It is not recommended to use this class as base for production plugins but rather use one of **AutoCreator** and **Creator** variants.
|
||||
Base implementation of creator plugin. It is not recommended to use this class as base for production plugins but rather use one of **HiddenCreator**, **AutoCreator** and **Creator** variants.
|
||||
|
||||
**Abstractions**
|
||||
- **`family`** (class attr) - Tells what kind of instance will be created.
|
||||
|
|
@ -92,7 +92,7 @@ def collect_instances(self):
|
|||
self._add_instance_to_context(instance)
|
||||
```
|
||||
|
||||
- **`create`** (method) - Create a new object of **CreatedInstance** store its metadata to the workfile and add the instance into the created context. Failed Creating should raise **CreatorError** if an error happens that artists can fix or give them some useful information. Triggers and implementation differs for **Creator** and **AutoCreator**.
|
||||
- **`create`** (method) - Create a new object of **CreatedInstance** store its metadata to the workfile and add the instance into the created context. Failed Creating should raise **CreatorError** if an error happens that artists can fix or give them some useful information. Triggers and implementation differs for **Creator**, **HiddenCreator** and **AutoCreator**.
|
||||
|
||||
- **`update_instances`** (method) - Update data of instances. Receives tuple with **instance** and **changes**.
|
||||
```python
|
||||
|
|
@ -172,11 +172,11 @@ class RenderLayerCreator(Creator):
|
|||
icon = "fa5.building"
|
||||
```
|
||||
|
||||
- **`get_instance_attr_defs`** (method) - Attribute definitions of instance. Creator can define attribute values with default values for each instance. These attributes may affect how instances will be instance processed during publishing. Attribute defiitions can be used from `openpype.pipeline.lib.attribute_definitions` (NOTE: Will be moved to `openpype.lib.attribute_definitions` soon). Attribute definitions define basic types of values for different cases e.g. boolean, number, string, enumerator, etc. Default implementation returns **instance_attr_defs**.
|
||||
- **`get_instance_attr_defs`** (method) - Attribute definitions of instance. Creator can define attribute values with default values for each instance. These attributes may affect how instances will be instance processed during publishing. Attribute defiitions can be used from `openpype.lib.attribute_definitions`. Attribute definitions define basic types of values for different cases e.g. boolean, number, string, enumerator, etc. Default implementation returns **instance_attr_defs**.
|
||||
- **`instance_attr_defs`** (attr) - Attribute for default implementation of **get_instance_attr_defs**.
|
||||
|
||||
```python
|
||||
from openpype.pipeline import attribute_definitions
|
||||
from openpype.lib import attribute_definitions
|
||||
|
||||
|
||||
class RenderLayerCreator(Creator):
|
||||
|
|
@ -199,6 +199,20 @@ class RenderLayerCreator(Creator):
|
|||
- **`get_dynamic_data`** (method) - Can be used to extend data for subset templates which may be required in some cases.
|
||||
|
||||
|
||||
#### *HiddenCreator*
|
||||
Creator which is not showed in UI so artist can't trigger it directly but is available for other creators. This creator is primarily meant for cases when creation should create different types of instances. For example during editorial publishing where input is single edl file but should create 2 or more kind of instances each with different family, attributes and abilities. Arguments for creation were limited to `instance_data` and `source_data`. Data of `instance_data` should follow what is sent to other creators and `source_data` can be used to send custom data defined by main creator. It is expected that `HiddenCreator` has specific main or "parent" creator.
|
||||
|
||||
```python
|
||||
def create(self, instance_data, source_data):
|
||||
variant = instance_data["variant"]
|
||||
task_name = instance_data["task"]
|
||||
asset_name = instance_data["asset"]
|
||||
asset_doc = get_asset_by_name(self.project_name, asset_name)
|
||||
self.get_subset_name(
|
||||
variant, task_name, asset_doc, self.project_name, self.host_name)
|
||||
```
|
||||
|
||||
|
||||
#### *AutoCreator*
|
||||
Creator that is triggered on reset of create context. Can be used for families that are expected to be created automatically without artist interaction (e.g. **workfile**). Method `create` is triggered after collecting all creators.
|
||||
|
||||
|
|
@ -234,14 +248,14 @@ def create(self):
|
|||
# - variant can be filled from settings
|
||||
variant = self._variant_name
|
||||
# Only place where we can look for current context
|
||||
project_name = io.Session["AVALON_PROJECT"]
|
||||
asset_name = io.Session["AVALON_ASSET"]
|
||||
task_name = io.Session["AVALON_TASK"]
|
||||
host_name = io.Session["AVALON_APP"]
|
||||
project_name = self.project_name
|
||||
asset_name = legacy_io.Session["AVALON_ASSET"]
|
||||
task_name = legacy_io.Session["AVALON_TASK"]
|
||||
host_name = legacy_io.Session["AVALON_APP"]
|
||||
|
||||
# Create new instance if does not exist yet
|
||||
if existing_instance is None:
|
||||
asset_doc = io.find_one({"type": "asset", "name": asset_name})
|
||||
asset_doc = get_asset_by_name(project_name, asset_name)
|
||||
subset_name = self.get_subset_name(
|
||||
variant, task_name, asset_doc, project_name, host_name
|
||||
)
|
||||
|
|
@ -264,7 +278,7 @@ def create(self):
|
|||
existing_instance["asset"] != asset_name
|
||||
or existing_instance["task"] != task_name
|
||||
):
|
||||
asset_doc = io.find_one({"type": "asset", "name": asset_name})
|
||||
asset_doc = get_asset_by_name(project_name, asset_name)
|
||||
subset_name = self.get_subset_name(
|
||||
variant, task_name, asset_doc, project_name, host_name
|
||||
)
|
||||
|
|
@ -297,7 +311,8 @@ class BulkRenderCreator(Creator):
|
|||
- **`pre_create_attr_defs`** (attr) - Attribute for default implementation of **get_pre_create_attr_defs**.
|
||||
|
||||
```python
|
||||
from openpype.pipeline import Creator, attribute_definitions
|
||||
from openpype.lib import attribute_definitions
|
||||
from openpype.pipeline.create import Creator
|
||||
|
||||
|
||||
class CreateRender(Creator):
|
||||
|
|
@ -470,10 +485,8 @@ Possible attribute definitions can be found in `openpype/pipeline/lib/attribute_
|
|||
|
||||
```python
|
||||
import pyblish.api
|
||||
from openpype.pipeline import (
|
||||
OpenPypePyblishPluginMixin,
|
||||
attribute_definitions,
|
||||
)
|
||||
from openpype.lib import attribute_definitions
|
||||
from openpype.pipeline import OpenPypePyblishPluginMixin
|
||||
|
||||
|
||||
# Example context plugin
|
||||
|
|
|
|||
|
|
@ -196,12 +196,12 @@ html[data-theme='dark'] .header-github-link::before {
|
|||
padding: 20px
|
||||
}
|
||||
|
||||
.showcase .client {
|
||||
.showcase .studio {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.showcase .client img {
|
||||
.showcase .studio img {
|
||||
max-height: 110px;
|
||||
padding: 20px;
|
||||
max-width: 160px;
|
||||
|
|
|
|||
|
|
@ -65,13 +65,17 @@ const collab = [
|
|||
image: '/img/clothcat.png',
|
||||
infoLink: 'https://www.clothcatanimation.com/'
|
||||
}, {
|
||||
title: 'Ellipse Studio',
|
||||
image: '/img/ellipse-studio.png',
|
||||
infoLink: 'http://www.dargaudmedia.com'
|
||||
title: 'Ellipse Animation',
|
||||
image: '/img/ellipse_animation.svg',
|
||||
infoLink: 'http://www.ellipseanimation.com'
|
||||
}, {
|
||||
title: 'J Cube Inc',
|
||||
image: '/img/jcube_logo_bw.png',
|
||||
infoLink: 'https://j-cube.jp'
|
||||
}, {
|
||||
title: 'Normaal Animation',
|
||||
image: '/img/logo_normaal.png',
|
||||
infoLink: 'https://j-cube.jp'
|
||||
}
|
||||
];
|
||||
|
||||
|
|
@ -153,7 +157,32 @@ const studios = [
|
|||
title: "IGG Canada",
|
||||
image: "/img/igg-logo.png",
|
||||
infoLink: "https://www.igg.com/",
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Agora Studio",
|
||||
image: "/img/agora_studio.png",
|
||||
infoLink: "https://agora.studio/",
|
||||
},
|
||||
{
|
||||
title: "Lucan Visuals",
|
||||
image: "/img/lucan_Logo_On_White-HR.png",
|
||||
infoLink: "https://www.lucan.tv/",
|
||||
},
|
||||
{
|
||||
title: "No Ghost",
|
||||
image: "/img/noghost.png",
|
||||
infoLink: "https://www.noghost.co.uk/",
|
||||
},
|
||||
{
|
||||
title: "Static VFX",
|
||||
image: "/img/staticvfx.png",
|
||||
infoLink: "http://www.staticvfx.com/",
|
||||
},
|
||||
{
|
||||
title: "Method n Madness",
|
||||
image: "/img/methodmadness.png",
|
||||
infoLink: "https://www.methodnmadness.com/",
|
||||
}
|
||||
];
|
||||
|
||||
function Service({imageUrl, title, description}) {
|
||||
|
|
@ -166,10 +195,10 @@ function Service({imageUrl, title, description}) {
|
|||
);
|
||||
}
|
||||
|
||||
function Client({title, image, infoLink}) {
|
||||
function Studio({title, image, infoLink}) {
|
||||
const imgUrl = useBaseUrl(image);
|
||||
return (
|
||||
<a className="client" href={infoLink}>
|
||||
<a className="studio" href={infoLink}>
|
||||
<img src={image} alt="" title={title}></img>
|
||||
</a>
|
||||
);
|
||||
|
|
@ -465,7 +494,7 @@ function Home() {
|
|||
<h2>Studios using openPype</h2>
|
||||
<div className="showcase">
|
||||
{studios.map((props, idx) => (
|
||||
<Client key={idx} {...props} />
|
||||
<Studio key={idx} {...props} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
31
website/static/img/NoGhost_Logo_black.svg
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 1341 216" style="enable-background:new 0 0 1341 216;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#000000;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M132,0.3l0,18l47,81.1c3.9,7.3,2.3,16.6-4.2,22.2c-7.6,6.5-19,5.7-25.6-1.9c-0.9-1-2.2-3.2-2.2-3.2L79.7,0.3
|
||||
H39.3C17.8,0.3,0.4,17.7,0.4,39.2L0.3,215.8h83.8l0-17.9l-46.3-80.1c-4.6-7.4-3.3-17.3,3.4-23.2c5.5-4.9,13.6-5.7,20.2-2.5
|
||||
c4,1.9,6.4,4.7,8.1,7.9l66.8,115.8h40.3c21.5,0,38.9-17.4,38.9-38.9V0.3H132z"/>
|
||||
<path class="st0" d="M367.8,0.3H227.6v176c0,21.8,17.7,39.5,39.5,39.5h140.2v-176C407.3,18,389.6,0.3,367.8,0.3z M350,191.9
|
||||
c-10.1,0-18.9-5.5-23.5-13.7l0,0L261.8,66.4c-2.9-4.3-4.6-9.5-4.6-15.1c0-14.9,12.1-27,27-27c10.7,0,20,6.2,24.3,15.3l0,0
|
||||
l64.4,111.3c0.3,0.4,0.5,0.8,0.7,1.3l0.1,0.1l0,0c2,3.8,3.2,8.1,3.2,12.7C377,179.8,364.9,191.9,350,191.9z"/>
|
||||
<path class="st0" d="M984.5,0.3H844.3v176c0,21.8,17.7,39.5,39.5,39.5H1024v-176C1024,18,1006.3,0.3,984.5,0.3z M966.7,191.9
|
||||
c-10.1,0-18.9-5.5-23.5-13.7l0,0L878.6,66.4c-2.9-4.3-4.6-9.5-4.6-15.1c0-14.9,12.1-27,27-27c10.7,0,20,6.2,24.3,15.3l0,0
|
||||
l64.2,111.3c0.3,0.4,0.5,0.8,0.7,1.3l0.1,0.1l0,0c2,3.8,3.2,8.1,3.2,12.7C993.7,179.8,981.6,191.9,966.7,191.9z"/>
|
||||
<path class="st0" d="M554.5,96.5v17.9l28.7,49.7c0.3,0.4,0.5,0.8,0.7,1.3l0.1,0.2l0,0c1.2,2.4,1.9,5.2,1.9,8.1
|
||||
c0,10-8.1,18.1-18.1,18.1c-6.3,0-11.8-3.2-15.1-8l0,0l-0.7-1.3c-0.1-0.1-0.1-0.2-0.2-0.3L497.4,88l0,0c-1.8-2.8-2.8-6.1-2.8-9.7
|
||||
c0-10,8.1-18.1,18.1-18.1c0,0,0,0,0,0h95c14.9,0,26.9-12.1,26.9-26.9V0.3H529.2c0,0,0,0,0,0c-50,0-90.8,40-91.9,89.8l0,0v35.9l0,0
|
||||
c1.2,49.8,41.9,89.7,91.9,89.7h0h105.5V96.5H554.5z"/>
|
||||
<path class="st0" d="M748.6,0.3l0,18.2l26,45.1c1.3,2.5,2.1,5.4,2.1,8.4c0,10-8.1,18.1-18.1,18.1h-29.5c-10,0-18.1-8.1-18.1-18.1
|
||||
V0.3h-64.2v215.5h83.8l0-17.9l-26.4-45.7c-1.3-2.5-2-5.3-2-8.2c0-10,8.1-18.1,18.1-18.1c0,0,0,0,0,0h29.5c0,0,0,0,0,0
|
||||
c10,0,18.1,8.1,18.1,18.1l0,71.9h64.5V0.3H748.6z"/>
|
||||
<path class="st0" d="M1269.1,60.2c0.1,0,71.6,0,71.6,0v-33c0-14.9-12.1-26.9-26.9-26.9h-93.7c-1.2,0-2.4,0-3.6,0
|
||||
c-123.6,0-149.9,0-154.1,0c-14.9,0-26.9,12.1-26.9,26.9c0,5.3,1.6,10.3,4.2,14.5l71.2,123.3c1.4,2.6,2.3,5.6,2.3,8.8
|
||||
c0,10-8.1,18.1-18.1,18.1c-6.6,0-12.4-3.6-15.6-8.9l-15.7-27.1h-28.3v59.9h134.5c14.9,0,26.9-12.1,26.9-26.9c0-5-1.4-9.8-3.8-13.8
|
||||
l-71.5-123.7l0,0c-1.5-2.6-2.3-5.6-2.3-8.8c0-10,8.1-18.1,18.1-18.1c7.2,0,13.4,4.2,16.4,10.3l14.8,25.4h40.4v155.6h83.8l-0.1-60.6
|
||||
l-39.5-68c-1.5-2.6-2.3-5.6-2.3-8.8C1251,68.3,1259.1,60.2,1269.1,60.2z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
BIN
website/static/img/agora_studio.png
Normal file
|
After Width: | Height: | Size: 131 KiB |
9
website/static/img/ellipse_animation.svg
Normal file
|
After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 94 KiB |
BIN
website/static/img/logo_normaal.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
website/static/img/lucan_Logo_On_White-HR.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
website/static/img/methodmadness.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
website/static/img/noghost.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
website/static/img/staticvfx.png
Normal file
|
After Width: | Height: | Size: 13 KiB |