mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-02 00:44:52 +01:00
Merge remote-tracking branch 'origin/develop' into feature/OP-3130_unreal-5-support
This commit is contained in:
commit
35225fd866
38 changed files with 549 additions and 334 deletions
4
.github/workflows/prerelease.yml
vendored
4
.github/workflows/prerelease.yml
vendored
|
|
@ -69,16 +69,14 @@ jobs:
|
|||
run: |
|
||||
git config user.email ${{ secrets.CI_EMAIL }}
|
||||
git config user.name ${{ secrets.CI_USER }}
|
||||
cd repos/avalon-core
|
||||
git checkout main
|
||||
git pull
|
||||
cd ../..
|
||||
git add .
|
||||
git commit -m "[Automated] Bump version"
|
||||
tag_name="CI/${{ steps.version.outputs.next_tag }}"
|
||||
echo $tag_name
|
||||
git tag -a $tag_name -m "nightly build"
|
||||
|
||||
|
||||
- name: Push to protected main branch
|
||||
uses: CasperWA/push-protected@v2.10.0
|
||||
with:
|
||||
|
|
|
|||
258
CHANGELOG.md
258
CHANGELOG.md
|
|
@ -1,166 +1,158 @@
|
|||
# Changelog
|
||||
|
||||
## [3.10.0-nightly.2](https://github.com/pypeclub/OpenPype/tree/HEAD)
|
||||
## [3.10.0-nightly.5](https://github.com/pypeclub/OpenPype/tree/HEAD)
|
||||
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.9.4...HEAD)
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.9.8...HEAD)
|
||||
|
||||
### 📖 Documentation
|
||||
**🆕 New features**
|
||||
|
||||
- Docs: add all-contributors config and initial list [\#3094](https://github.com/pypeclub/OpenPype/pull/3094)
|
||||
- Nuke docs with videos [\#3052](https://github.com/pypeclub/OpenPype/pull/3052)
|
||||
- General: OpenPype modules publish plugins are registered in host [\#3180](https://github.com/pypeclub/OpenPype/pull/3180)
|
||||
- General: Creator plugins from addons can be registered [\#3179](https://github.com/pypeclub/OpenPype/pull/3179)
|
||||
- Ftrack: Single image reviewable [\#3157](https://github.com/pypeclub/OpenPype/pull/3157)
|
||||
- Nuke: Expose write attributes to settings [\#3123](https://github.com/pypeclub/OpenPype/pull/3123)
|
||||
- Hiero: Initial frame publish support [\#3106](https://github.com/pypeclub/OpenPype/pull/3106)
|
||||
|
||||
**🚀 Enhancements**
|
||||
|
||||
- Standalone publisher: add support for bgeo and vdb [\#3080](https://github.com/pypeclub/OpenPype/pull/3080)
|
||||
- Update collect\_render.py [\#3055](https://github.com/pypeclub/OpenPype/pull/3055)
|
||||
- SiteSync: Added compute\_resource\_sync\_sites to sync\_server\_module [\#2983](https://github.com/pypeclub/OpenPype/pull/2983)
|
||||
- Project Manager: Allow to paste Tasks into multiple assets at the same time [\#3226](https://github.com/pypeclub/OpenPype/pull/3226)
|
||||
- Project manager: Sped up project load [\#3216](https://github.com/pypeclub/OpenPype/pull/3216)
|
||||
- Loader UI: Speed issues of loader with sync server [\#3199](https://github.com/pypeclub/OpenPype/pull/3199)
|
||||
- Maya: added clean\_import option to Import loader [\#3181](https://github.com/pypeclub/OpenPype/pull/3181)
|
||||
- Maya: add maya 2023 to default applications [\#3167](https://github.com/pypeclub/OpenPype/pull/3167)
|
||||
- Compressed bgeo publishing in SAP and Houdini loader [\#3153](https://github.com/pypeclub/OpenPype/pull/3153)
|
||||
- General: Add 'dataclasses' to required python modules [\#3149](https://github.com/pypeclub/OpenPype/pull/3149)
|
||||
- Hooks: Tweak logging grammar [\#3147](https://github.com/pypeclub/OpenPype/pull/3147)
|
||||
- Nuke: settings for reformat node in CreateWriteRender node [\#3143](https://github.com/pypeclub/OpenPype/pull/3143)
|
||||
- Houdini: Add loader for alembic through Alembic Archive node [\#3140](https://github.com/pypeclub/OpenPype/pull/3140)
|
||||
- Publisher: UI Modifications and fixes [\#3139](https://github.com/pypeclub/OpenPype/pull/3139)
|
||||
- General: Simplified OP modules/addons import [\#3137](https://github.com/pypeclub/OpenPype/pull/3137)
|
||||
- Terminal: Tweak coloring of TrayModuleManager logging enabled states [\#3133](https://github.com/pypeclub/OpenPype/pull/3133)
|
||||
- General: Cleanup some Loader docstrings [\#3131](https://github.com/pypeclub/OpenPype/pull/3131)
|
||||
- Nuke: render instance with subset name filtered overrides [\#3117](https://github.com/pypeclub/OpenPype/pull/3117)
|
||||
- Unreal: Layout and Camera update and remove functions reimplemented and improvements [\#3116](https://github.com/pypeclub/OpenPype/pull/3116)
|
||||
- Settings: Remove environment groups from settings [\#3115](https://github.com/pypeclub/OpenPype/pull/3115)
|
||||
- TVPaint: Match renderlayer key with other hosts [\#3110](https://github.com/pypeclub/OpenPype/pull/3110)
|
||||
- Tray publisher: Simple families from settings [\#3105](https://github.com/pypeclub/OpenPype/pull/3105)
|
||||
|
||||
**🐛 Bug fixes**
|
||||
|
||||
- RoyalRender Control Submission - AVALON\_APP\_NAME default [\#3091](https://github.com/pypeclub/OpenPype/pull/3091)
|
||||
- Ftrack: Update Create Folders action [\#3089](https://github.com/pypeclub/OpenPype/pull/3089)
|
||||
- Project Manager: Avoid unnecessary updates of asset documents [\#3083](https://github.com/pypeclub/OpenPype/pull/3083)
|
||||
- Standalone publisher: Fix plugins install [\#3077](https://github.com/pypeclub/OpenPype/pull/3077)
|
||||
- General: Extract review sequence is not converted with same names [\#3076](https://github.com/pypeclub/OpenPype/pull/3076)
|
||||
- Webpublisher: Use variant value [\#3068](https://github.com/pypeclub/OpenPype/pull/3068)
|
||||
- Nuke: Add aov matching even for remainder and prerender [\#3060](https://github.com/pypeclub/OpenPype/pull/3060)
|
||||
- Ftrack: Validate that the user exists on ftrack [\#3237](https://github.com/pypeclub/OpenPype/pull/3237)
|
||||
- TVPaint: Look for more groups than 12 [\#3228](https://github.com/pypeclub/OpenPype/pull/3228)
|
||||
- Project Manager: Fix persistent editors on project change [\#3218](https://github.com/pypeclub/OpenPype/pull/3218)
|
||||
- Deadline: instance data overwrite fix [\#3214](https://github.com/pypeclub/OpenPype/pull/3214)
|
||||
- Ftrack: Push hierarchical attributes action works [\#3210](https://github.com/pypeclub/OpenPype/pull/3210)
|
||||
- Standalone Publisher: Always create new representation for thumbnail [\#3203](https://github.com/pypeclub/OpenPype/pull/3203)
|
||||
- Photoshop: skip collector when automatic testing [\#3202](https://github.com/pypeclub/OpenPype/pull/3202)
|
||||
- Nuke: render/workfile version sync doesn't work on farm [\#3185](https://github.com/pypeclub/OpenPype/pull/3185)
|
||||
- Ftrack: Review image only if there are no mp4 reviews [\#3183](https://github.com/pypeclub/OpenPype/pull/3183)
|
||||
- General: Avoid creating multiple thumbnails [\#3176](https://github.com/pypeclub/OpenPype/pull/3176)
|
||||
- General/Hiero: better clip duration calculation [\#3169](https://github.com/pypeclub/OpenPype/pull/3169)
|
||||
- General: Oiio conversion for ffmpeg checks for invalid characters [\#3166](https://github.com/pypeclub/OpenPype/pull/3166)
|
||||
- Fix for attaching render to subset [\#3164](https://github.com/pypeclub/OpenPype/pull/3164)
|
||||
- Harmony: fixed missing task name in render instance [\#3163](https://github.com/pypeclub/OpenPype/pull/3163)
|
||||
- Ftrack: Action delete old versions formatting works [\#3152](https://github.com/pypeclub/OpenPype/pull/3152)
|
||||
- Deadline: fix the output directory [\#3144](https://github.com/pypeclub/OpenPype/pull/3144)
|
||||
- General: New Session schema [\#3141](https://github.com/pypeclub/OpenPype/pull/3141)
|
||||
- General: Missing version on headless mode crash properly [\#3136](https://github.com/pypeclub/OpenPype/pull/3136)
|
||||
- TVPaint: Composite layers in reversed order [\#3135](https://github.com/pypeclub/OpenPype/pull/3135)
|
||||
- Nuke: fixing default settings for workfile builder loaders [\#3120](https://github.com/pypeclub/OpenPype/pull/3120)
|
||||
- Nuke: fix anatomy imageio regex default [\#3119](https://github.com/pypeclub/OpenPype/pull/3119)
|
||||
|
||||
**🔀 Refactored code**
|
||||
|
||||
- General: Move host install [\#3009](https://github.com/pypeclub/OpenPype/pull/3009)
|
||||
- Avalon repo removed from Jobs workflow [\#3193](https://github.com/pypeclub/OpenPype/pull/3193)
|
||||
- General: Remove remaining imports from avalon [\#3130](https://github.com/pypeclub/OpenPype/pull/3130)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Nuke: added suspend\_publish knob [\#3078](https://github.com/pypeclub/OpenPype/pull/3078)
|
||||
- Bump async from 2.6.3 to 2.6.4 in /website [\#3065](https://github.com/pypeclub/OpenPype/pull/3065)
|
||||
- Maya: added jpg to filter for Image Plane Loader [\#3223](https://github.com/pypeclub/OpenPype/pull/3223)
|
||||
- Webpublisher: replace space by underscore in subset names [\#3160](https://github.com/pypeclub/OpenPype/pull/3160)
|
||||
- StandalonePublisher: removed Extract Background plugins [\#3093](https://github.com/pypeclub/OpenPype/pull/3093)
|
||||
|
||||
## [3.9.8](https://github.com/pypeclub/OpenPype/tree/3.9.8) (2022-05-19)
|
||||
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.9.7...3.9.8)
|
||||
|
||||
**🚀 Enhancements**
|
||||
|
||||
- nuke: generate publishing nodes inside render group node [\#3206](https://github.com/pypeclub/OpenPype/pull/3206)
|
||||
- Loader UI: Speed issues of loader with sync server [\#3200](https://github.com/pypeclub/OpenPype/pull/3200)
|
||||
- Backport of fix for attaching renders to subsets [\#3195](https://github.com/pypeclub/OpenPype/pull/3195)
|
||||
|
||||
**🐛 Bug fixes**
|
||||
|
||||
- Standalone Publisher: Always create new representation for thumbnail [\#3204](https://github.com/pypeclub/OpenPype/pull/3204)
|
||||
- Nuke: render/workfile version sync doesn't work on farm [\#3184](https://github.com/pypeclub/OpenPype/pull/3184)
|
||||
- Ftrack: Review image only if there are no mp4 reviews [\#3182](https://github.com/pypeclub/OpenPype/pull/3182)
|
||||
- Ftrack: Locations deepcopy issue [\#3177](https://github.com/pypeclub/OpenPype/pull/3177)
|
||||
- Ftrack: Locations deepcopy issue [\#3175](https://github.com/pypeclub/OpenPype/pull/3175)
|
||||
- General: Avoid creating multiple thumbnails [\#3174](https://github.com/pypeclub/OpenPype/pull/3174)
|
||||
- General: TemplateResult can be copied [\#3170](https://github.com/pypeclub/OpenPype/pull/3170)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- hiero: otio p3 compatibility issue - metadata on effect use update [\#3194](https://github.com/pypeclub/OpenPype/pull/3194)
|
||||
|
||||
## [3.9.7](https://github.com/pypeclub/OpenPype/tree/3.9.7) (2022-05-11)
|
||||
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.9.6...3.9.7)
|
||||
|
||||
**🆕 New features**
|
||||
|
||||
- Ftrack: Single image reviewable [\#3158](https://github.com/pypeclub/OpenPype/pull/3158)
|
||||
|
||||
**🚀 Enhancements**
|
||||
|
||||
- Deadline output dir issue to 3.9x [\#3155](https://github.com/pypeclub/OpenPype/pull/3155)
|
||||
- nuke: removing redundant code from startup [\#3142](https://github.com/pypeclub/OpenPype/pull/3142)
|
||||
|
||||
**🐛 Bug fixes**
|
||||
|
||||
- Ftrack: Action delete old versions formatting works [\#3154](https://github.com/pypeclub/OpenPype/pull/3154)
|
||||
- nuke: adding extract thumbnail settings [\#3148](https://github.com/pypeclub/OpenPype/pull/3148)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Webpublisher: replace space by underscore in subset names [\#3159](https://github.com/pypeclub/OpenPype/pull/3159)
|
||||
|
||||
## [3.9.6](https://github.com/pypeclub/OpenPype/tree/3.9.6) (2022-05-03)
|
||||
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.9.5...3.9.6)
|
||||
|
||||
**🆕 New features**
|
||||
|
||||
- Nuke: render instance with subset name filtered overrides \(3.9.x\) [\#3125](https://github.com/pypeclub/OpenPype/pull/3125)
|
||||
|
||||
**🚀 Enhancements**
|
||||
|
||||
- TVPaint: Match renderlayer key with other hosts [\#3109](https://github.com/pypeclub/OpenPype/pull/3109)
|
||||
|
||||
**🐛 Bug fixes**
|
||||
|
||||
- TVPaint: Composite layers in reversed order [\#3134](https://github.com/pypeclub/OpenPype/pull/3134)
|
||||
- General: Python 3 compatibility in queries [\#3111](https://github.com/pypeclub/OpenPype/pull/3111)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Ftrack: AssetVersion status on publish [\#3114](https://github.com/pypeclub/OpenPype/pull/3114)
|
||||
- renderman support for 3.9.x [\#3107](https://github.com/pypeclub/OpenPype/pull/3107)
|
||||
|
||||
## [3.9.5](https://github.com/pypeclub/OpenPype/tree/3.9.5) (2022-04-25)
|
||||
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.10.0-nightly.2...3.9.5)
|
||||
|
||||
## [3.9.4](https://github.com/pypeclub/OpenPype/tree/3.9.4) (2022-04-15)
|
||||
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.9.4-nightly.2...3.9.4)
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Documentation: more info about Tasks [\#3062](https://github.com/pypeclub/OpenPype/pull/3062)
|
||||
- Documentation: Python requirements to 3.7.9 [\#3035](https://github.com/pypeclub/OpenPype/pull/3035)
|
||||
- Website Docs: Remove unused pages [\#2974](https://github.com/pypeclub/OpenPype/pull/2974)
|
||||
|
||||
**🆕 New features**
|
||||
|
||||
- General: Local overrides for environment variables [\#3045](https://github.com/pypeclub/OpenPype/pull/3045)
|
||||
|
||||
**🚀 Enhancements**
|
||||
|
||||
- TVPaint: Added init file for worker to triggers missing sound file dialog [\#3053](https://github.com/pypeclub/OpenPype/pull/3053)
|
||||
- Ftrack: Custom attributes can be filled in slate values [\#3036](https://github.com/pypeclub/OpenPype/pull/3036)
|
||||
- Resolve environment variable in google drive credential path [\#3008](https://github.com/pypeclub/OpenPype/pull/3008)
|
||||
|
||||
**🐛 Bug fixes**
|
||||
|
||||
- GitHub: Updated push-protected action in github workflow [\#3064](https://github.com/pypeclub/OpenPype/pull/3064)
|
||||
- Nuke: Typos in imports from Nuke implementation [\#3061](https://github.com/pypeclub/OpenPype/pull/3061)
|
||||
- Hotfix: fixing deadline job publishing [\#3059](https://github.com/pypeclub/OpenPype/pull/3059)
|
||||
- General: Extract Review handle invalid characters for ffmpeg [\#3050](https://github.com/pypeclub/OpenPype/pull/3050)
|
||||
- Slate Review: Support to keep format on slate concatenation [\#3049](https://github.com/pypeclub/OpenPype/pull/3049)
|
||||
- Webpublisher: fix processing of workfile [\#3048](https://github.com/pypeclub/OpenPype/pull/3048)
|
||||
- Ftrack: Integrate ftrack api fix [\#3044](https://github.com/pypeclub/OpenPype/pull/3044)
|
||||
- Webpublisher - removed wrong hardcoded family [\#3043](https://github.com/pypeclub/OpenPype/pull/3043)
|
||||
- LibraryLoader: Use current project for asset query in families filter [\#3042](https://github.com/pypeclub/OpenPype/pull/3042)
|
||||
- SiteSync: Providers ignore that site is disabled [\#3041](https://github.com/pypeclub/OpenPype/pull/3041)
|
||||
- Unreal: Creator import fixes [\#3040](https://github.com/pypeclub/OpenPype/pull/3040)
|
||||
- Settings UI: Version column can be extended so version are visible [\#3032](https://github.com/pypeclub/OpenPype/pull/3032)
|
||||
- SiteSync: fix transitive alternate sites, fix dropdown in Local Settings [\#3018](https://github.com/pypeclub/OpenPype/pull/3018)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Deadline: reworked pools assignment [\#3051](https://github.com/pypeclub/OpenPype/pull/3051)
|
||||
- Houdini: Avoid ImportError on `hdefereval` when Houdini runs without UI [\#2987](https://github.com/pypeclub/OpenPype/pull/2987)
|
||||
|
||||
## [3.9.3](https://github.com/pypeclub/OpenPype/tree/3.9.3) (2022-04-07)
|
||||
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.9.3-nightly.2...3.9.3)
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Website Docs: Manager Ftrack fix broken links [\#2979](https://github.com/pypeclub/OpenPype/pull/2979)
|
||||
|
||||
**🆕 New features**
|
||||
|
||||
- Ftrack: Add description integrator [\#3027](https://github.com/pypeclub/OpenPype/pull/3027)
|
||||
- Publishing textures for Unreal [\#2988](https://github.com/pypeclub/OpenPype/pull/2988)
|
||||
|
||||
**🚀 Enhancements**
|
||||
|
||||
- Ftrack: Add more options for note text of integrate ftrack note [\#3025](https://github.com/pypeclub/OpenPype/pull/3025)
|
||||
- Console Interpreter: Changed how console splitter size are reused on show [\#3016](https://github.com/pypeclub/OpenPype/pull/3016)
|
||||
- Deadline: Use more suitable name for sequence review logic [\#3015](https://github.com/pypeclub/OpenPype/pull/3015)
|
||||
- General: default workfile subset name for workfile [\#3011](https://github.com/pypeclub/OpenPype/pull/3011)
|
||||
- Deadline: priority configurable in Maya jobs [\#2995](https://github.com/pypeclub/OpenPype/pull/2995)
|
||||
|
||||
**🐛 Bug fixes**
|
||||
|
||||
- Deadline: Fixed default value of use sequence for review [\#3033](https://github.com/pypeclub/OpenPype/pull/3033)
|
||||
- General: Fix validate asset docs plug-in filename and class name [\#3029](https://github.com/pypeclub/OpenPype/pull/3029)
|
||||
- General: Fix import after movements [\#3028](https://github.com/pypeclub/OpenPype/pull/3028)
|
||||
- Harmony: Added creating subset name for workfile from template [\#3024](https://github.com/pypeclub/OpenPype/pull/3024)
|
||||
- AfterEffects: Added creating subset name for workfile from template [\#3023](https://github.com/pypeclub/OpenPype/pull/3023)
|
||||
- General: Add example addons to ignored [\#3022](https://github.com/pypeclub/OpenPype/pull/3022)
|
||||
- Maya: Remove missing import [\#3017](https://github.com/pypeclub/OpenPype/pull/3017)
|
||||
- Ftrack: multiple reviewable componets [\#3012](https://github.com/pypeclub/OpenPype/pull/3012)
|
||||
- Tray publisher: Fixes after code movement [\#3010](https://github.com/pypeclub/OpenPype/pull/3010)
|
||||
- Nuke: fixing unicode type detection in effect loaders [\#3002](https://github.com/pypeclub/OpenPype/pull/3002)
|
||||
- Nuke: removing redundant Ftrack asset when farm publishing [\#2996](https://github.com/pypeclub/OpenPype/pull/2996)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Maya: Allow to select invalid camera contents if no cameras found [\#3030](https://github.com/pypeclub/OpenPype/pull/3030)
|
||||
- General: adding limitations for pyright [\#2994](https://github.com/pypeclub/OpenPype/pull/2994)
|
||||
|
||||
## [3.9.2](https://github.com/pypeclub/OpenPype/tree/3.9.2) (2022-04-04)
|
||||
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.9.2-nightly.4...3.9.2)
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Documentation: Added mention of adding My Drive as a root [\#2999](https://github.com/pypeclub/OpenPype/pull/2999)
|
||||
- Docs: Added MongoDB requirements [\#2951](https://github.com/pypeclub/OpenPype/pull/2951)
|
||||
|
||||
**🆕 New features**
|
||||
|
||||
- nuke: bypass baking [\#2992](https://github.com/pypeclub/OpenPype/pull/2992)
|
||||
- Maya to Unreal: Static and Skeletal Meshes [\#2978](https://github.com/pypeclub/OpenPype/pull/2978)
|
||||
|
||||
**🚀 Enhancements**
|
||||
|
||||
- Nuke: add concurrency attr to deadline job [\#3005](https://github.com/pypeclub/OpenPype/pull/3005)
|
||||
- Photoshop: create image without instance [\#3001](https://github.com/pypeclub/OpenPype/pull/3001)
|
||||
- TVPaint: Render scene family [\#3000](https://github.com/pypeclub/OpenPype/pull/3000)
|
||||
- Nuke: ReviewDataMov Read RAW attribute [\#2985](https://github.com/pypeclub/OpenPype/pull/2985)
|
||||
- General: `METADATA\_KEYS` constant as `frozenset` for optimal immutable lookup [\#2980](https://github.com/pypeclub/OpenPype/pull/2980)
|
||||
- General: Tools with host filters [\#2975](https://github.com/pypeclub/OpenPype/pull/2975)
|
||||
- Hero versions: Use custom templates [\#2967](https://github.com/pypeclub/OpenPype/pull/2967)
|
||||
|
||||
**🐛 Bug fixes**
|
||||
|
||||
- Hosts: Remove path existence checks in 'add\_implementation\_envs' [\#3004](https://github.com/pypeclub/OpenPype/pull/3004)
|
||||
- Fix - remove doubled dot in workfile created from template [\#2998](https://github.com/pypeclub/OpenPype/pull/2998)
|
||||
- PS: fix renaming subset incorrectly in PS [\#2991](https://github.com/pypeclub/OpenPype/pull/2991)
|
||||
- Fix: Disable setuptools auto discovery [\#2990](https://github.com/pypeclub/OpenPype/pull/2990)
|
||||
- AEL: fix opening existing workfile if no scene opened [\#2989](https://github.com/pypeclub/OpenPype/pull/2989)
|
||||
- Maya: Don't do hardlinks on windows for look publishing [\#2986](https://github.com/pypeclub/OpenPype/pull/2986)
|
||||
- Settings UI: Fix version completer on linux [\#2981](https://github.com/pypeclub/OpenPype/pull/2981)
|
||||
- Photoshop: Fix creation of subset names in PS review and workfile [\#2969](https://github.com/pypeclub/OpenPype/pull/2969)
|
||||
- Slack: Added default for review\_upload\_limit for Slack [\#2965](https://github.com/pypeclub/OpenPype/pull/2965)
|
||||
- General: OIIO conversion for ffmeg can handle sequences [\#2958](https://github.com/pypeclub/OpenPype/pull/2958)
|
||||
- Settings: Conditional dictionary avoid invalid logs [\#2956](https://github.com/pypeclub/OpenPype/pull/2956)
|
||||
- General: Smaller fixes and typos [\#2950](https://github.com/pypeclub/OpenPype/pull/2950)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Bump paramiko from 2.9.2 to 2.10.1 [\#2973](https://github.com/pypeclub/OpenPype/pull/2973)
|
||||
- Bump minimist from 1.2.5 to 1.2.6 in /website [\#2954](https://github.com/pypeclub/OpenPype/pull/2954)
|
||||
- Bump node-forge from 1.2.1 to 1.3.0 in /website [\#2953](https://github.com/pypeclub/OpenPype/pull/2953)
|
||||
- Maya - added transparency into review creator [\#2952](https://github.com/pypeclub/OpenPype/pull/2952)
|
||||
|
||||
## [3.9.1](https://github.com/pypeclub/OpenPype/tree/3.9.1) (2022-03-18)
|
||||
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.9.1-nightly.3...3.9.1)
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ def create_otio_reference(clip):
|
|||
padding = media_source.filenamePadding()
|
||||
file_head = media_source.filenameHead()
|
||||
is_sequence = not media_source.singleFile()
|
||||
frame_duration = media_source.duration()
|
||||
frame_duration = media_source.duration() - 1
|
||||
fps = utils.get_rate(clip) or self.project_fps
|
||||
extension = os.path.splitext(path)[-1]
|
||||
|
||||
|
|
|
|||
|
|
@ -296,6 +296,8 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
|
|||
continue
|
||||
if otio_clip.name not in track_item.name():
|
||||
continue
|
||||
self.log.debug("__ parent_range: {}".format(parent_range))
|
||||
self.log.debug("__ timeline_range: {}".format(timeline_range))
|
||||
if openpype.lib.is_overlapping_otio_ranges(
|
||||
parent_range, timeline_range, strict=True):
|
||||
|
||||
|
|
|
|||
|
|
@ -1093,6 +1093,11 @@ class RenderProductsRenderman(ARenderProducts):
|
|||
if not enabled:
|
||||
continue
|
||||
|
||||
# Skip display types not producing any file output.
|
||||
# Is there a better way to do it?
|
||||
if not display_types.get(display["driverNode"]["type"]):
|
||||
continue
|
||||
|
||||
aov_name = name
|
||||
if aov_name == "rmanDefaultDisplay":
|
||||
aov_name = "beauty"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"""A module containing generic loader actions that will display in the Loader.
|
||||
|
||||
"""
|
||||
|
||||
import qargparse
|
||||
from openpype.pipeline import load
|
||||
from openpype.hosts.maya.api.lib import (
|
||||
maintained_selection,
|
||||
|
|
@ -98,6 +98,15 @@ class ImportMayaLoader(load.LoaderPlugin):
|
|||
icon = "arrow-circle-down"
|
||||
color = "#775555"
|
||||
|
||||
options = [
|
||||
qargparse.Boolean(
|
||||
"clean_import",
|
||||
label="Clean import",
|
||||
default=False,
|
||||
help="Should all occurences of cbId be purged?"
|
||||
)
|
||||
]
|
||||
|
||||
def load(self, context, name=None, namespace=None, data=None):
|
||||
import maya.cmds as cmds
|
||||
|
||||
|
|
@ -114,13 +123,22 @@ class ImportMayaLoader(load.LoaderPlugin):
|
|||
)
|
||||
|
||||
with maintained_selection():
|
||||
cmds.file(self.fname,
|
||||
i=True,
|
||||
preserveReferences=True,
|
||||
namespace=namespace,
|
||||
returnNewNodes=True,
|
||||
groupReference=True,
|
||||
groupName="{}:{}".format(namespace, name))
|
||||
nodes = cmds.file(self.fname,
|
||||
i=True,
|
||||
preserveReferences=True,
|
||||
namespace=namespace,
|
||||
returnNewNodes=True,
|
||||
groupReference=True,
|
||||
groupName="{}:{}".format(namespace, name))
|
||||
|
||||
if data.get("clean_import", False):
|
||||
remove_attributes = ["cbId"]
|
||||
for node in nodes:
|
||||
for attr in remove_attributes:
|
||||
if cmds.attributeQuery(attr, node=node, exists=True):
|
||||
full_attr = "{}.{}".format(node, attr)
|
||||
print("Removing {}".format(full_attr))
|
||||
cmds.deleteAttr(full_attr)
|
||||
|
||||
# We do not containerize imported content, it remains unmanaged
|
||||
return
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ class ImagePlaneLoader(load.LoaderPlugin):
|
|||
|
||||
families = ["image", "plate", "render"]
|
||||
label = "Load imagePlane"
|
||||
representations = ["mov", "exr", "preview", "png"]
|
||||
representations = ["mov", "exr", "preview", "png", "jpg"]
|
||||
icon = "image"
|
||||
color = "orange"
|
||||
|
||||
|
|
|
|||
|
|
@ -22,10 +22,46 @@ RENDERER_NODE_TYPES = [
|
|||
# redshift
|
||||
"RedshiftMeshParameters"
|
||||
]
|
||||
|
||||
SHAPE_ATTRS = set(SHAPE_ATTRS)
|
||||
|
||||
|
||||
def get_pxr_multitexture_file_attrs(node):
|
||||
attrs = []
|
||||
for i in range(9):
|
||||
if cmds.attributeQuery("filename{}".format(i), node):
|
||||
file = cmds.getAttr("{}.filename{}".format(node, i))
|
||||
if file:
|
||||
attrs.append("filename{}".format(i))
|
||||
return attrs
|
||||
|
||||
|
||||
FILE_NODES = {
|
||||
"file": "fileTextureName",
|
||||
|
||||
"aiImage": "filename",
|
||||
|
||||
"RedshiftNormalMap": "text0",
|
||||
|
||||
"PxrBump": "filename",
|
||||
"PxrNormalMap": "filename",
|
||||
"PxrMultiTexture": get_pxr_multitexture_file_attrs,
|
||||
"PxrPtexture": "filename",
|
||||
"PxrTexture": "filename"
|
||||
}
|
||||
|
||||
|
||||
def get_attributes(dictionary, attr):
|
||||
# type: (dict, str) -> list
|
||||
if callable(dictionary[attr]):
|
||||
val = dictionary[attr]()
|
||||
else:
|
||||
val = dictionary.get(attr, [])
|
||||
|
||||
if not isinstance(val, list):
|
||||
return [val]
|
||||
return val
|
||||
|
||||
|
||||
def get_look_attrs(node):
|
||||
"""Returns attributes of a node that are important for the look.
|
||||
|
||||
|
|
@ -51,15 +87,14 @@ def get_look_attrs(node):
|
|||
if cmds.objectType(node, isAType="shape"):
|
||||
attrs = cmds.listAttr(node, changedSinceFileOpen=True) or []
|
||||
for attr in attrs:
|
||||
if attr in SHAPE_ATTRS:
|
||||
if attr in SHAPE_ATTRS or \
|
||||
attr not in SHAPE_ATTRS and attr.startswith('ai'):
|
||||
result.append(attr)
|
||||
elif attr.startswith('ai'):
|
||||
result.append(attr)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def node_uses_image_sequence(node):
|
||||
def node_uses_image_sequence(node, node_path):
|
||||
# type: (str) -> bool
|
||||
"""Return whether file node uses an image sequence or single image.
|
||||
|
||||
Determine if a node uses an image sequence or just a single image,
|
||||
|
|
@ -74,12 +109,15 @@ def node_uses_image_sequence(node):
|
|||
"""
|
||||
|
||||
# useFrameExtension indicates an explicit image sequence
|
||||
node_path = get_file_node_path(node).lower()
|
||||
|
||||
# The following tokens imply a sequence
|
||||
patterns = ["<udim>", "<tile>", "<uvtile>", "u<u>_v<v>", "<frame0"]
|
||||
patterns = ["<udim>", "<tile>", "<uvtile>",
|
||||
"u<u>_v<v>", "<frame0", "<f4>"]
|
||||
try:
|
||||
use_frame_extension = cmds.getAttr('%s.useFrameExtension' % node)
|
||||
except ValueError:
|
||||
use_frame_extension = False
|
||||
|
||||
return (cmds.getAttr('%s.useFrameExtension' % node) or
|
||||
return (use_frame_extension or
|
||||
any(pattern in node_path for pattern in patterns))
|
||||
|
||||
|
||||
|
|
@ -137,14 +175,15 @@ def seq_to_glob(path):
|
|||
return path
|
||||
|
||||
|
||||
def get_file_node_path(node):
|
||||
def get_file_node_paths(node):
|
||||
# type: (str) -> list
|
||||
"""Get the file path used by a Maya file node.
|
||||
|
||||
Args:
|
||||
node (str): Name of the Maya file node
|
||||
|
||||
Returns:
|
||||
str: the file path in use
|
||||
list: the file paths in use
|
||||
|
||||
"""
|
||||
# if the path appears to be sequence, use computedFileTextureNamePattern,
|
||||
|
|
@ -163,15 +202,19 @@ def get_file_node_path(node):
|
|||
"<uvtile>"]
|
||||
lower = texture_pattern.lower()
|
||||
if any(pattern in lower for pattern in patterns):
|
||||
return texture_pattern
|
||||
return [texture_pattern]
|
||||
|
||||
if cmds.nodeType(node) == 'aiImage':
|
||||
return cmds.getAttr('{0}.filename'.format(node))
|
||||
if cmds.nodeType(node) == 'RedshiftNormalMap':
|
||||
return cmds.getAttr('{}.tex0'.format(node))
|
||||
try:
|
||||
file_attributes = get_attributes(FILE_NODES, cmds.nodeType(node))
|
||||
except AttributeError:
|
||||
file_attributes = "fileTextureName"
|
||||
|
||||
# otherwise use fileTextureName
|
||||
return cmds.getAttr('{0}.fileTextureName'.format(node))
|
||||
files = []
|
||||
for file_attr in file_attributes:
|
||||
if cmds.attributeQuery(file_attr, node=node, exists=True):
|
||||
files.append(cmds.getAttr("{}.{}".format(node, file_attr)))
|
||||
|
||||
return files
|
||||
|
||||
|
||||
def get_file_node_files(node):
|
||||
|
|
@ -185,16 +228,21 @@ def get_file_node_files(node):
|
|||
list: List of full file paths.
|
||||
|
||||
"""
|
||||
paths = get_file_node_paths(node)
|
||||
sequences = []
|
||||
replaces = []
|
||||
for index, path in enumerate(paths):
|
||||
if node_uses_image_sequence(node, path):
|
||||
glob_pattern = seq_to_glob(path)
|
||||
sequences.extend(glob.glob(glob_pattern))
|
||||
replaces.append(index)
|
||||
|
||||
path = get_file_node_path(node)
|
||||
path = cmds.workspace(expandName=path)
|
||||
if node_uses_image_sequence(node):
|
||||
glob_pattern = seq_to_glob(path)
|
||||
return glob.glob(glob_pattern)
|
||||
elif os.path.exists(path):
|
||||
return [path]
|
||||
else:
|
||||
return []
|
||||
for index in replaces:
|
||||
paths.pop(index)
|
||||
|
||||
paths.extend(sequences)
|
||||
|
||||
return [p for p in paths if os.path.exists(p)]
|
||||
|
||||
|
||||
class CollectLook(pyblish.api.InstancePlugin):
|
||||
|
|
@ -238,13 +286,13 @@ class CollectLook(pyblish.api.InstancePlugin):
|
|||
"for %s" % instance.data['name'])
|
||||
|
||||
# Discover related object sets
|
||||
self.log.info("Gathering sets..")
|
||||
self.log.info("Gathering sets ...")
|
||||
sets = self.collect_sets(instance)
|
||||
|
||||
# Lookup set (optimization)
|
||||
instance_lookup = set(cmds.ls(instance, long=True))
|
||||
|
||||
self.log.info("Gathering set relations..")
|
||||
self.log.info("Gathering set relations ...")
|
||||
# Ensure iteration happen in a list so we can remove keys from the
|
||||
# dict within the loop
|
||||
|
||||
|
|
@ -326,7 +374,10 @@ class CollectLook(pyblish.api.InstancePlugin):
|
|||
"volumeShader",
|
||||
"displacementShader",
|
||||
"aiSurfaceShader",
|
||||
"aiVolumeShader"]
|
||||
"aiVolumeShader",
|
||||
"rman__surface",
|
||||
"rman__displacement"
|
||||
]
|
||||
if look_sets:
|
||||
materials = []
|
||||
|
||||
|
|
@ -374,9 +425,10 @@ class CollectLook(pyblish.api.InstancePlugin):
|
|||
or []
|
||||
)
|
||||
|
||||
files = cmds.ls(history, type="file", long=True)
|
||||
files.extend(cmds.ls(history, type="aiImage", long=True))
|
||||
files.extend(cmds.ls(history, type="RedshiftNormalMap", long=True))
|
||||
all_supported_nodes = FILE_NODES.keys()
|
||||
files = []
|
||||
for node_type in all_supported_nodes:
|
||||
files.extend(cmds.ls(history, type=node_type, long=True))
|
||||
|
||||
self.log.info("Collected file nodes:\n{}".format(files))
|
||||
# Collect textures if any file nodes are found
|
||||
|
|
@ -510,27 +562,24 @@ class CollectLook(pyblish.api.InstancePlugin):
|
|||
Returns:
|
||||
dict
|
||||
"""
|
||||
|
||||
self.log.debug("processing: {}".format(node))
|
||||
if cmds.nodeType(node) not in ["file", "aiImage", "RedshiftNormalMap"]:
|
||||
all_supported_nodes = FILE_NODES.keys()
|
||||
if cmds.nodeType(node) not in all_supported_nodes:
|
||||
self.log.error(
|
||||
"Unsupported file node: {}".format(cmds.nodeType(node)))
|
||||
raise AssertionError("Unsupported file node")
|
||||
|
||||
if cmds.nodeType(node) == 'file':
|
||||
self.log.debug(" - file node")
|
||||
attribute = "{}.fileTextureName".format(node)
|
||||
computed_attribute = "{}.computedFileTextureNamePattern".format(node)
|
||||
elif cmds.nodeType(node) == 'aiImage':
|
||||
self.log.debug("aiImage node")
|
||||
attribute = "{}.filename".format(node)
|
||||
computed_attribute = attribute
|
||||
elif cmds.nodeType(node) == 'RedshiftNormalMap':
|
||||
self.log.debug("RedshiftNormalMap node")
|
||||
attribute = "{}.tex0".format(node)
|
||||
computed_attribute = attribute
|
||||
self.log.debug(" - got {}".format(cmds.nodeType(node)))
|
||||
|
||||
attribute = FILE_NODES.get(cmds.nodeType(node))
|
||||
source = cmds.getAttr("{}.{}".format(
|
||||
node,
|
||||
attribute
|
||||
))
|
||||
computed_attribute = "{}.{}".format(node, attribute)
|
||||
if attribute == "fileTextureName":
|
||||
computed_attribute = node + ".computedFileTextureNamePattern"
|
||||
|
||||
source = cmds.getAttr(attribute)
|
||||
self.log.info(" - file source: {}".format(source))
|
||||
color_space_attr = "{}.colorSpace".format(node)
|
||||
try:
|
||||
|
|
@ -567,11 +616,15 @@ class CollectLook(pyblish.api.InstancePlugin):
|
|||
self.log.info(" - color space: {}".format(color_space))
|
||||
|
||||
# Define the resource
|
||||
return {"node": node,
|
||||
"attribute": attribute,
|
||||
"source": source, # required for resources
|
||||
"files": files,
|
||||
"color_space": color_space} # required for resources
|
||||
return {
|
||||
"node": node,
|
||||
# here we are passing not only attribute, but with node again
|
||||
# this should be simplified and changed extractor.
|
||||
"attribute": "{}.{}".format(node, attribute),
|
||||
"source": source, # required for resources
|
||||
"files": files,
|
||||
"color_space": color_space
|
||||
} # required for resources
|
||||
|
||||
|
||||
class CollectModelRenderSets(CollectLook):
|
||||
|
|
|
|||
|
|
@ -339,9 +339,15 @@ class CollectMayaRender(pyblish.api.ContextPlugin):
|
|||
"source": filepath,
|
||||
"expectedFiles": full_exp_files,
|
||||
"publishRenderMetadataFolder": common_publish_meta_path,
|
||||
"resolutionWidth": cmds.getAttr("defaultResolution.width"),
|
||||
"resolutionHeight": cmds.getAttr("defaultResolution.height"),
|
||||
"pixelAspect": cmds.getAttr("defaultResolution.pixelAspect"),
|
||||
"resolutionWidth": lib.get_attr_in_layer(
|
||||
"defaultResolution.height", layer=layer_name
|
||||
),
|
||||
"resolutionHeight": lib.get_attr_in_layer(
|
||||
"defaultResolution.width", layer=layer_name
|
||||
),
|
||||
"pixelAspect": lib.get_attr_in_layer(
|
||||
"defaultResolution.pixelAspect", layer=layer_name
|
||||
),
|
||||
"tileRendering": render_instance.data.get("tileRendering") or False, # noqa: E501
|
||||
"tilesX": render_instance.data.get("tilesX") or 2,
|
||||
"tilesY": render_instance.data.get("tilesY") or 2,
|
||||
|
|
|
|||
|
|
@ -124,9 +124,15 @@ class CollectVrayScene(pyblish.api.InstancePlugin):
|
|||
# Add source to allow tracing back to the scene from
|
||||
# which was submitted originally
|
||||
"source": context.data["currentFile"].replace("\\", "/"),
|
||||
"resolutionWidth": cmds.getAttr("defaultResolution.width"),
|
||||
"resolutionHeight": cmds.getAttr("defaultResolution.height"),
|
||||
"pixelAspect": cmds.getAttr("defaultResolution.pixelAspect"),
|
||||
"resolutionWidth": lib.get_attr_in_layer(
|
||||
"defaultResolution.height", layer=layer_name
|
||||
),
|
||||
"resolutionHeight": lib.get_attr_in_layer(
|
||||
"defaultResolution.width", layer=layer_name
|
||||
),
|
||||
"pixelAspect": lib.get_attr_in_layer(
|
||||
"defaultResolution.pixelAspect", layer=layer_name
|
||||
),
|
||||
"priority": instance.data.get("priority"),
|
||||
"useMultipleSceneFiles": instance.data.get(
|
||||
"vraySceneMultipleFiles")
|
||||
|
|
|
|||
|
|
@ -372,10 +372,12 @@ class ExtractLook(openpype.api.Extractor):
|
|||
|
||||
if mode == COPY:
|
||||
transfers.append((source, destination))
|
||||
self.log.info('copying')
|
||||
self.log.info('file will be copied {} -> {}'.format(
|
||||
source, destination))
|
||||
elif mode == HARDLINK:
|
||||
hardlinks.append((source, destination))
|
||||
self.log.info('hardlinking')
|
||||
self.log.info('file will be hardlinked {} -> {}'.format(
|
||||
source, destination))
|
||||
|
||||
# Store the hashes from hash to destination to include in the
|
||||
# database
|
||||
|
|
|
|||
|
|
@ -39,6 +39,9 @@ class CollectBatchData(pyblish.api.ContextPlugin):
|
|||
def process(self, context):
|
||||
self.log.info("CollectBatchData")
|
||||
batch_dir = os.environ.get("OPENPYPE_PUBLISH_DATA")
|
||||
if os.environ.get("IS_TEST"):
|
||||
self.log.debug("Automatic testing, no batch data, skipping")
|
||||
return
|
||||
|
||||
assert batch_dir, (
|
||||
"Missing `OPENPYPE_PUBLISH_DATA`")
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ class CollectColorCodedInstances(pyblish.api.ContextPlugin):
|
|||
"variant": variant,
|
||||
"family": resolved_family,
|
||||
"task": task_name,
|
||||
"layer": layer.name
|
||||
"layer": layer.clean_name
|
||||
}
|
||||
|
||||
subset = resolved_subset_template.format(
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import openpype.api
|
|||
from openpype.lib import (
|
||||
get_ffmpeg_tool_path,
|
||||
get_ffprobe_streams,
|
||||
path_to_subprocess_arg,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -37,82 +38,69 @@ class ExtractThumbnailSP(pyblish.api.InstancePlugin):
|
|||
if not thumbnail_repre:
|
||||
return
|
||||
|
||||
thumbnail_repre.pop("thumbnail")
|
||||
files = thumbnail_repre.get("files")
|
||||
if not files:
|
||||
return
|
||||
|
||||
if isinstance(files, list):
|
||||
files_len = len(files)
|
||||
file = str(files[0])
|
||||
first_filename = str(files[0])
|
||||
else:
|
||||
files_len = 1
|
||||
file = files
|
||||
first_filename = files
|
||||
|
||||
staging_dir = None
|
||||
is_jpeg = False
|
||||
if file.endswith(".jpeg") or file.endswith(".jpg"):
|
||||
is_jpeg = True
|
||||
|
||||
if is_jpeg and files_len == 1:
|
||||
# skip if already is single jpeg file
|
||||
return
|
||||
# Convert to jpeg if not yet
|
||||
full_input_path = os.path.join(
|
||||
thumbnail_repre["stagingDir"], first_filename
|
||||
)
|
||||
self.log.info("input {}".format(full_input_path))
|
||||
with tempfile.NamedTemporaryFile(suffix=".jpg") as tmp:
|
||||
full_thumbnail_path = tmp.name
|
||||
|
||||
elif is_jpeg:
|
||||
# use first frame as thumbnail if is sequence of jpegs
|
||||
full_thumbnail_path = os.path.join(
|
||||
thumbnail_repre["stagingDir"], file
|
||||
)
|
||||
self.log.info(
|
||||
"For thumbnail is used file: {}".format(full_thumbnail_path)
|
||||
)
|
||||
self.log.info("output {}".format(full_thumbnail_path))
|
||||
|
||||
else:
|
||||
# Convert to jpeg if not yet
|
||||
full_input_path = os.path.join(thumbnail_repre["stagingDir"], file)
|
||||
self.log.info("input {}".format(full_input_path))
|
||||
instance.context.data["cleanupFullPaths"].append(full_thumbnail_path)
|
||||
|
||||
full_thumbnail_path = tempfile.mkstemp(suffix=".jpg")[1]
|
||||
self.log.info("output {}".format(full_thumbnail_path))
|
||||
ffmpeg_path = get_ffmpeg_tool_path("ffmpeg")
|
||||
|
||||
ffmpeg_path = get_ffmpeg_tool_path("ffmpeg")
|
||||
ffmpeg_args = self.ffmpeg_args or {}
|
||||
|
||||
ffmpeg_args = self.ffmpeg_args or {}
|
||||
jpeg_items = [
|
||||
path_to_subprocess_arg(ffmpeg_path),
|
||||
# override file if already exists
|
||||
"-y"
|
||||
]
|
||||
|
||||
jpeg_items = [
|
||||
"\"{}\"".format(ffmpeg_path),
|
||||
# override file if already exists
|
||||
"-y"
|
||||
]
|
||||
|
||||
# add input filters from peresets
|
||||
jpeg_items.extend(ffmpeg_args.get("input") or [])
|
||||
# input file
|
||||
jpeg_items.append("-i \"{}\"".format(full_input_path))
|
||||
# add input filters from peresets
|
||||
jpeg_items.extend(ffmpeg_args.get("input") or [])
|
||||
# input file
|
||||
jpeg_items.extend([
|
||||
"-i", path_to_subprocess_arg(full_input_path),
|
||||
# extract only single file
|
||||
jpeg_items.append("-frames:v 1")
|
||||
"-frames:v", "1",
|
||||
# Add black background for transparent images
|
||||
jpeg_items.append((
|
||||
"-filter_complex"
|
||||
" \"color=black,format=rgb24[c]"
|
||||
"-filter_complex", (
|
||||
"\"color=black,format=rgb24[c]"
|
||||
";[c][0]scale2ref[c][i]"
|
||||
";[c][i]overlay=format=auto:shortest=1,setsar=1\""
|
||||
))
|
||||
),
|
||||
])
|
||||
|
||||
jpeg_items.extend(ffmpeg_args.get("output") or [])
|
||||
jpeg_items.extend(ffmpeg_args.get("output") or [])
|
||||
|
||||
# output file
|
||||
jpeg_items.append("\"{}\"".format(full_thumbnail_path))
|
||||
# output file
|
||||
jpeg_items.append(path_to_subprocess_arg(full_thumbnail_path))
|
||||
|
||||
subprocess_jpeg = " ".join(jpeg_items)
|
||||
subprocess_jpeg = " ".join(jpeg_items)
|
||||
|
||||
# run subprocess
|
||||
self.log.debug("Executing: {}".format(subprocess_jpeg))
|
||||
openpype.api.run_subprocess(
|
||||
subprocess_jpeg, shell=True, logger=self.log
|
||||
)
|
||||
# run subprocess
|
||||
self.log.debug("Executing: {}".format(subprocess_jpeg))
|
||||
openpype.api.run_subprocess(
|
||||
subprocess_jpeg, shell=True, logger=self.log
|
||||
)
|
||||
|
||||
# remove thumbnail key from origin repre
|
||||
thumbnail_repre.pop("thumbnail")
|
||||
streams = get_ffprobe_streams(full_thumbnail_path)
|
||||
width = height = None
|
||||
for stream in streams:
|
||||
|
|
@ -121,8 +109,7 @@ class ExtractThumbnailSP(pyblish.api.InstancePlugin):
|
|||
height = stream["height"]
|
||||
break
|
||||
|
||||
filename = os.path.basename(full_thumbnail_path)
|
||||
staging_dir = staging_dir or os.path.dirname(full_thumbnail_path)
|
||||
staging_dir, filename = os.path.split(full_thumbnail_path)
|
||||
|
||||
# create new thumbnail representation
|
||||
representation = {
|
||||
|
|
@ -130,15 +117,11 @@ class ExtractThumbnailSP(pyblish.api.InstancePlugin):
|
|||
'ext': 'jpg',
|
||||
'files': filename,
|
||||
"stagingDir": staging_dir,
|
||||
"tags": ["thumbnail"],
|
||||
"tags": ["thumbnail", "delete"],
|
||||
}
|
||||
if width and height:
|
||||
representation["width"] = width
|
||||
representation["height"] = height
|
||||
|
||||
# # add Delete tag when temp file was rendered
|
||||
if not is_jpeg:
|
||||
representation["tags"].append("delete")
|
||||
|
||||
self.log.info(f"New representation {representation}")
|
||||
instance.data["representations"].append(representation)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ from .pipeline import (
|
|||
|
||||
class TrayPublishCreator(Creator):
|
||||
create_allow_context_change = True
|
||||
host_name = "traypublisher"
|
||||
|
||||
def collect_instances(self):
|
||||
for instance_data in list_instances():
|
||||
|
|
|
|||
|
|
@ -165,12 +165,12 @@ def parse_group_data(data):
|
|||
if not group_raw:
|
||||
continue
|
||||
|
||||
parts = group_raw.split(" ")
|
||||
parts = group_raw.split("|")
|
||||
# Check for length and concatenate 2 last items until length match
|
||||
# - this happens if name contain spaces
|
||||
while len(parts) > 6:
|
||||
last_item = parts.pop(-1)
|
||||
parts[-1] = " ".join([parts[-1], last_item])
|
||||
parts[-1] = "|".join([parts[-1], last_item])
|
||||
clip_id, group_id, red, green, blue, name = parts
|
||||
|
||||
group = {
|
||||
|
|
@ -201,11 +201,16 @@ def get_groups_data(communicator=None):
|
|||
george_script_lines = (
|
||||
# Variable containing full path to output file
|
||||
"output_path = \"{}\"".format(output_filepath),
|
||||
"loop = 1",
|
||||
"FOR idx = 1 TO 12",
|
||||
"empty = 0",
|
||||
# Loop over 100 groups
|
||||
"FOR idx = 1 TO 100",
|
||||
# Receive information about groups
|
||||
"tv_layercolor \"getcolor\" 0 idx",
|
||||
"tv_writetextfile \"strict\" \"append\" '\"'output_path'\"' result",
|
||||
"END"
|
||||
"PARSE result clip_id group_index c_red c_green c_blue group_name",
|
||||
# Create and add line to output file
|
||||
"line = clip_id'|'group_index'|'c_red'|'c_green'|'c_blue'|'group_name",
|
||||
"tv_writetextfile \"strict\" \"append\" '\"'output_path'\"' line",
|
||||
"END",
|
||||
)
|
||||
george_script = "\n".join(george_script_lines)
|
||||
execute_george_through_file(george_script, communicator)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ def otio_range_to_frame_range(otio_range):
|
|||
start = _ot.to_frames(
|
||||
otio_range.start_time, otio_range.start_time.rate)
|
||||
end = start + _ot.to_frames(
|
||||
otio_range.duration, otio_range.duration.rate) - 1
|
||||
otio_range.duration, otio_range.duration.rate)
|
||||
return start, end
|
||||
|
||||
|
||||
|
|
@ -254,7 +254,7 @@ def get_media_range_with_retimes(otio_clip, handle_start, handle_end):
|
|||
media_in + source_in + offset_in)
|
||||
media_out_trimmed = (
|
||||
media_in + source_in + (
|
||||
((source_range.duration.value - 1) * abs(
|
||||
(source_range.duration.value * abs(
|
||||
time_scalar)) + offset_out))
|
||||
|
||||
# calculate available handles
|
||||
|
|
|
|||
|
|
@ -702,6 +702,32 @@ class ModulesManager:
|
|||
).format(expected_keys, " | ".join(msg_items)))
|
||||
return output
|
||||
|
||||
def collect_creator_plugin_paths(self, host_name):
|
||||
"""Helper to collect creator plugin paths from modules.
|
||||
|
||||
Args:
|
||||
host_name (str): For which host are creators meants.
|
||||
|
||||
Returns:
|
||||
list: List of creator plugin paths.
|
||||
"""
|
||||
# Output structure
|
||||
from openpype_interfaces import IPluginPaths
|
||||
|
||||
output = []
|
||||
for module in self.get_enabled_modules():
|
||||
# Skip module that do not inherit from `IPluginPaths`
|
||||
if not isinstance(module, IPluginPaths):
|
||||
continue
|
||||
|
||||
paths = module.get_creator_plugin_paths(host_name)
|
||||
if paths:
|
||||
# Convert to list if value is not list
|
||||
if not isinstance(paths, (list, tuple, set)):
|
||||
paths = [paths]
|
||||
output.extend(paths)
|
||||
return output
|
||||
|
||||
def collect_launch_hook_paths(self):
|
||||
"""Helper to collect hooks from modules inherited ILaunchHookPaths.
|
||||
|
||||
|
|
|
|||
|
|
@ -466,7 +466,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
|
|||
if instance_data.get("multipartExr"):
|
||||
preview = True
|
||||
|
||||
new_instance = copy(instance_data)
|
||||
new_instance = deepcopy(instance_data)
|
||||
new_instance["subset"] = subset_name
|
||||
new_instance["subsetGroup"] = group_name
|
||||
if preview:
|
||||
|
|
@ -883,8 +883,10 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
|
|||
new_i = copy(i)
|
||||
new_i["version"] = at.get("version")
|
||||
new_i["subset"] = at.get("subset")
|
||||
new_i["family"] = at.get("family")
|
||||
new_i["append"] = True
|
||||
new_i["families"].append(at.get("family"))
|
||||
# don't set subsetGroup if we are attaching
|
||||
new_i.pop("subsetGroup")
|
||||
new_instances.append(new_i)
|
||||
self.log.info(" - {} / v{}".format(
|
||||
at.get("subset"), at.get("version")))
|
||||
|
|
|
|||
|
|
@ -356,7 +356,7 @@ class PushHierValuesToNonHier(ServerAction):
|
|||
values_per_entity_id[entity_id][key] = None
|
||||
|
||||
values = query_custom_attributes(
|
||||
session, all_ids_with_parents, hier_attr_ids, True
|
||||
session, hier_attr_ids, all_ids_with_parents, True
|
||||
)
|
||||
for item in values:
|
||||
entity_id = item["entity_id"]
|
||||
|
|
|
|||
|
|
@ -92,14 +92,18 @@ def check_credentials(username, api_key, ftrack_server=None):
|
|||
if not ftrack_server or not username or not api_key:
|
||||
return False
|
||||
|
||||
user_exists = False
|
||||
try:
|
||||
session = ftrack_api.Session(
|
||||
server_url=ftrack_server,
|
||||
api_key=api_key,
|
||||
api_user=username
|
||||
)
|
||||
# Validated that the username actually exists
|
||||
user = session.query("User where username is \"{}\"".format(username))
|
||||
user_exists = user is not None
|
||||
session.close()
|
||||
|
||||
except Exception:
|
||||
return False
|
||||
return True
|
||||
pass
|
||||
return user_exists
|
||||
|
|
|
|||
|
|
@ -14,11 +14,38 @@ class IPluginPaths(OpenPypeInterface):
|
|||
"publish": ["path/to/publish_plugins"]
|
||||
}
|
||||
"""
|
||||
# TODO validation of an output
|
||||
|
||||
@abstractmethod
|
||||
def get_plugin_paths(self):
|
||||
pass
|
||||
|
||||
def get_creator_plugin_paths(self, host_name):
|
||||
"""Retreive creator plugin paths.
|
||||
|
||||
Give addons ability to add creator plugin paths based on host name.
|
||||
|
||||
NOTES:
|
||||
- Default implementation uses 'get_plugin_paths' and always return
|
||||
all creator plugins.
|
||||
- Host name may help to organize plugins by host, but each creator
|
||||
alsomay have host filtering.
|
||||
|
||||
Args:
|
||||
host_name (str): For which host are the plugins meant.
|
||||
"""
|
||||
|
||||
paths = self.get_plugin_paths()
|
||||
if not paths or "create" not in paths:
|
||||
return []
|
||||
|
||||
create_paths = paths["create"]
|
||||
if not create_paths:
|
||||
return []
|
||||
|
||||
if not isinstance(create_paths, (list, tuple, set)):
|
||||
create_paths = [create_paths]
|
||||
return create_paths
|
||||
|
||||
|
||||
class ILaunchHookPaths(OpenPypeInterface):
|
||||
"""Module has launch hook paths to return.
|
||||
|
|
|
|||
|
|
@ -921,12 +921,18 @@ class SyncServerModule(OpenPypeModule, ITrayModule):
|
|||
if self.enabled:
|
||||
for project in self.connection.projects(projection={"name": 1}):
|
||||
project_name = project["name"]
|
||||
project_settings = self.get_sync_project_setting(project_name)
|
||||
if project_settings and project_settings.get("enabled"):
|
||||
if self.is_project_enabled(project_name):
|
||||
enabled_projects.append(project_name)
|
||||
|
||||
return enabled_projects
|
||||
|
||||
def is_project_enabled(self, project_name):
|
||||
if self.enabled:
|
||||
project_settings = self.get_sync_project_setting(project_name)
|
||||
if project_settings and project_settings.get("enabled"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def handle_alternate_site(self, collection, representation, processed_site,
|
||||
file_id, synced_file_id):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import pyblish.api
|
|||
from pyblish.lib import MessageHandler
|
||||
|
||||
import openpype
|
||||
from openpype.modules import load_modules
|
||||
from openpype.modules import load_modules, ModulesManager
|
||||
from openpype.settings import get_project_settings
|
||||
from openpype.lib import (
|
||||
Anatomy,
|
||||
|
|
@ -107,7 +107,7 @@ def install_host(host):
|
|||
install_openpype_plugins()
|
||||
|
||||
|
||||
def install_openpype_plugins(project_name=None):
|
||||
def install_openpype_plugins(project_name=None, host_name=None):
|
||||
# Make sure modules are loaded
|
||||
load_modules()
|
||||
|
||||
|
|
@ -116,6 +116,18 @@ def install_openpype_plugins(project_name=None):
|
|||
pyblish.api.register_discovery_filter(filter_pyblish_plugins)
|
||||
register_loader_plugin_path(LOAD_PATH)
|
||||
|
||||
modules_manager = ModulesManager()
|
||||
publish_plugin_dirs = modules_manager.collect_plugin_paths()["publish"]
|
||||
for path in publish_plugin_dirs:
|
||||
pyblish.api.register_plugin_path(path)
|
||||
|
||||
if host_name is None:
|
||||
host_name = os.environ.get("AVALON_APP")
|
||||
|
||||
creator_paths = modules_manager.collect_creator_plugin_paths(host_name)
|
||||
for creator_path in creator_paths:
|
||||
register_creator_plugin_path(creator_path)
|
||||
|
||||
if project_name is None:
|
||||
project_name = os.environ.get("AVALON_PROJECT")
|
||||
|
||||
|
|
|
|||
|
|
@ -749,6 +749,10 @@ class CreateContext:
|
|||
"""Is host valid for creation."""
|
||||
return self._host_is_valid
|
||||
|
||||
@property
|
||||
def host_name(self):
|
||||
return os.environ["AVALON_APP"]
|
||||
|
||||
@property
|
||||
def log(self):
|
||||
"""Dynamic access to logger."""
|
||||
|
|
@ -861,6 +865,17 @@ class CreateContext:
|
|||
"Using first and skipping following"
|
||||
))
|
||||
continue
|
||||
|
||||
# Filter by host name
|
||||
if (
|
||||
creator_class.host_name
|
||||
and creator_class.host_name != self.host_name
|
||||
):
|
||||
self.log.info((
|
||||
"Creator's host name is not supported for current host {}"
|
||||
).format(creator_class.host_name, self.host_name))
|
||||
continue
|
||||
|
||||
creator = creator_class(
|
||||
self,
|
||||
system_settings,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,12 @@ class BaseCreator:
|
|||
# `openpype.pipeline.attribute_definitions`
|
||||
instance_attr_defs = []
|
||||
|
||||
# Filtering by host name - can be used to be filtered by host name
|
||||
# - used on all hosts when set to 'None' for Backwards compatibility
|
||||
# - was added afterwards
|
||||
# QUESTION make this required?
|
||||
host_name = None
|
||||
|
||||
def __init__(
|
||||
self, create_context, system_settings, project_settings, headless=False
|
||||
):
|
||||
|
|
|
|||
|
|
@ -98,4 +98,4 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -87,7 +87,8 @@
|
|||
"camera",
|
||||
"gizmo",
|
||||
"source",
|
||||
"render"
|
||||
"render",
|
||||
"write"
|
||||
]
|
||||
},
|
||||
"ValidateInstanceInContext": {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@
|
|||
},
|
||||
{
|
||||
"render": "render"
|
||||
},
|
||||
{
|
||||
"write": "write"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import copy
|
||||
import re
|
||||
import math
|
||||
import time
|
||||
from uuid import uuid4
|
||||
|
||||
from Qt import QtCore, QtGui
|
||||
|
|
@ -38,6 +39,14 @@ def is_filtering_recursible():
|
|||
|
||||
class BaseRepresentationModel(object):
|
||||
"""Methods for SyncServer useful in multiple models"""
|
||||
# Cheap & hackish way how to avoid refreshing of whole sync server module
|
||||
# on each selection change
|
||||
_last_project = None
|
||||
_modules_manager = None
|
||||
_last_project_cache = 0
|
||||
_last_manager_cache = 0
|
||||
_max_project_cache_time = 30
|
||||
_max_manager_cache_time = 60
|
||||
|
||||
def reset_sync_server(self, project_name=None):
|
||||
"""Sets/Resets sync server vars after every change (refresh.)"""
|
||||
|
|
@ -47,28 +56,53 @@ class BaseRepresentationModel(object):
|
|||
remote_site = remote_provider = None
|
||||
|
||||
if not project_name:
|
||||
project_name = self.dbcon.Session["AVALON_PROJECT"]
|
||||
project_name = self.dbcon.Session.get("AVALON_PROJECT")
|
||||
else:
|
||||
self.dbcon.Session["AVALON_PROJECT"] = project_name
|
||||
|
||||
if project_name:
|
||||
manager = ModulesManager()
|
||||
sync_server = manager.modules_by_name["sync_server"]
|
||||
if not project_name:
|
||||
self.repre_icons = repre_icons
|
||||
self.sync_server = sync_server
|
||||
self.active_site = active_site
|
||||
self.active_provider = active_provider
|
||||
self.remote_site = remote_site
|
||||
self.remote_provider = remote_provider
|
||||
return
|
||||
|
||||
if project_name in sync_server.get_enabled_projects():
|
||||
active_site = sync_server.get_active_site(project_name)
|
||||
active_provider = sync_server.get_provider_for_site(
|
||||
project_name, active_site)
|
||||
if active_site == 'studio': # for studio use explicit icon
|
||||
active_provider = 'studio'
|
||||
now_time = time.time()
|
||||
project_cache_diff = now_time - self._last_project_cache
|
||||
if project_cache_diff > self._max_project_cache_time:
|
||||
self._last_project = None
|
||||
|
||||
remote_site = sync_server.get_remote_site(project_name)
|
||||
remote_provider = sync_server.get_provider_for_site(
|
||||
project_name, remote_site)
|
||||
if remote_site == 'studio': # for studio use explicit icon
|
||||
remote_provider = 'studio'
|
||||
if project_name == self._last_project:
|
||||
return
|
||||
|
||||
repre_icons = lib.get_repre_icons()
|
||||
self._last_project = project_name
|
||||
self._last_project_cache = now_time
|
||||
|
||||
manager_cache_diff = now_time - self._last_manager_cache
|
||||
if manager_cache_diff > self._max_manager_cache_time:
|
||||
self._modules_manager = None
|
||||
|
||||
if self._modules_manager is None:
|
||||
self._modules_manager = ModulesManager()
|
||||
self._last_manager_cache = now_time
|
||||
|
||||
sync_server = self._modules_manager.modules_by_name["sync_server"]
|
||||
if sync_server.is_project_enabled(project_name):
|
||||
active_site = sync_server.get_active_site(project_name)
|
||||
active_provider = sync_server.get_provider_for_site(
|
||||
project_name, active_site)
|
||||
if active_site == 'studio': # for studio use explicit icon
|
||||
active_provider = 'studio'
|
||||
|
||||
remote_site = sync_server.get_remote_site(project_name)
|
||||
remote_provider = sync_server.get_provider_for_site(
|
||||
project_name, remote_site)
|
||||
if remote_site == 'studio': # for studio use explicit icon
|
||||
remote_provider = 'studio'
|
||||
|
||||
repre_icons = lib.get_repre_icons()
|
||||
|
||||
self.repre_icons = repre_icons
|
||||
self.sync_server = sync_server
|
||||
|
|
|
|||
|
|
@ -1472,12 +1472,7 @@ class HierarchyModel(QtCore.QAbstractItemModel):
|
|||
mimedata.setData("application/copy_task", encoded_data)
|
||||
return mimedata
|
||||
|
||||
def paste_mime_data(self, index, mime_data):
|
||||
if not index.isValid():
|
||||
return
|
||||
|
||||
item_id = index.data(IDENTIFIER_ROLE)
|
||||
item = self._items_by_id[item_id]
|
||||
def _paste_mime_data(self, item, mime_data):
|
||||
if not isinstance(item, (AssetItem, TaskItem)):
|
||||
return
|
||||
|
||||
|
|
@ -1511,6 +1506,25 @@ class HierarchyModel(QtCore.QAbstractItemModel):
|
|||
task_item = TaskItem(task_data, True)
|
||||
self.add_item(task_item, parent)
|
||||
|
||||
def paste(self, indexes, mime_data):
|
||||
|
||||
# Get the selected Assets uniquely
|
||||
items = set()
|
||||
for index in indexes:
|
||||
if not index.isValid():
|
||||
return
|
||||
item_id = index.data(IDENTIFIER_ROLE)
|
||||
item = self._items_by_id[item_id]
|
||||
|
||||
# Do not copy into the Task Item so get parent Asset instead
|
||||
if isinstance(item, TaskItem):
|
||||
item = item.parent()
|
||||
|
||||
items.add(item)
|
||||
|
||||
for item in items:
|
||||
self._paste_mime_data(item, mime_data)
|
||||
|
||||
|
||||
class BaseItem:
|
||||
"""Base item for HierarchyModel.
|
||||
|
|
|
|||
|
|
@ -195,13 +195,13 @@ class HierarchyView(QtWidgets.QTreeView):
|
|||
for idx, width in widths_by_idx.items():
|
||||
self.setColumnWidth(idx, width)
|
||||
|
||||
def set_project(self, project_name):
|
||||
def set_project(self, project_name, force=False):
|
||||
# Trigger helpers first
|
||||
self._project_doc_cache.set_project(project_name)
|
||||
self._tools_cache.refresh()
|
||||
|
||||
# Trigger update of model after all data for delegates are filled
|
||||
self._source_model.set_project(project_name)
|
||||
self._source_model.set_project(project_name, force)
|
||||
|
||||
def _on_project_reset(self):
|
||||
self.header_init()
|
||||
|
|
@ -365,20 +365,24 @@ class HierarchyView(QtWidgets.QTreeView):
|
|||
event.accept()
|
||||
|
||||
def _copy_items(self, indexes=None):
|
||||
clipboard = QtWidgets.QApplication.clipboard()
|
||||
try:
|
||||
if indexes is None:
|
||||
indexes = self.selectedIndexes()
|
||||
mime_data = self._source_model.copy_mime_data(indexes)
|
||||
|
||||
QtWidgets.QApplication.clipboard().setMimeData(mime_data)
|
||||
clipboard.setMimeData(mime_data)
|
||||
self._show_message("Tasks copied")
|
||||
except ValueError as exc:
|
||||
# Change clipboard to contain empty data
|
||||
empty_mime_data = QtCore.QMimeData()
|
||||
clipboard.setMimeData(empty_mime_data)
|
||||
self._show_message(str(exc))
|
||||
|
||||
def _paste_items(self):
|
||||
index = self.currentIndex()
|
||||
mime_data = QtWidgets.QApplication.clipboard().mimeData()
|
||||
self._source_model.paste_mime_data(index, mime_data)
|
||||
rows = self.selectionModel().selectedRows()
|
||||
self._source_model.paste(rows, mime_data)
|
||||
|
||||
def _delete_items(self, indexes=None):
|
||||
if indexes is None:
|
||||
|
|
|
|||
|
|
@ -184,14 +184,14 @@ class ProjectManagerWindow(QtWidgets.QWidget):
|
|||
self.resize(1200, 600)
|
||||
self.setStyleSheet(load_stylesheet())
|
||||
|
||||
def _set_project(self, project_name=None):
|
||||
def _set_project(self, project_name=None, force=False):
|
||||
self._create_folders_btn.setEnabled(project_name is not None)
|
||||
self._remove_projects_btn.setEnabled(project_name is not None)
|
||||
self._add_asset_btn.setEnabled(project_name is not None)
|
||||
self._add_task_btn.setEnabled(project_name is not None)
|
||||
self._save_btn.setEnabled(project_name is not None)
|
||||
self._project_proxy_model.set_filter_default(project_name is not None)
|
||||
self.hierarchy_view.set_project(project_name)
|
||||
self.hierarchy_view.set_project(project_name, force)
|
||||
|
||||
def _current_project(self):
|
||||
row = self._project_combobox.currentIndex()
|
||||
|
|
@ -229,11 +229,11 @@ class ProjectManagerWindow(QtWidgets.QWidget):
|
|||
self._project_combobox.setCurrentIndex(row)
|
||||
|
||||
selected_project = self._current_project()
|
||||
self._set_project(selected_project)
|
||||
self._set_project(selected_project, True)
|
||||
|
||||
def _on_project_change(self):
|
||||
selected_project = self._current_project()
|
||||
self._set_project(selected_project)
|
||||
self._set_project(selected_project, False)
|
||||
|
||||
def _on_project_refresh(self):
|
||||
self.refresh_projects()
|
||||
|
|
|
|||
|
|
@ -202,6 +202,7 @@ def cli_publish(data, publish_paths, gui=True):
|
|||
if os.path.exists(json_data_path):
|
||||
with open(json_data_path, "r") as f:
|
||||
result = json.load(f)
|
||||
os.remove(json_data_path)
|
||||
|
||||
log.info(f"Publish result: {result}")
|
||||
|
||||
|
|
|
|||
|
|
@ -494,8 +494,6 @@ class AssetModel(QtGui.QStandardItemModel):
|
|||
# Remove cache of removed items
|
||||
for asset_id in removed_asset_ids:
|
||||
self._items_by_asset_id.pop(asset_id)
|
||||
if asset_id in self._items_with_color_by_id:
|
||||
self._items_with_color_by_id.pop(asset_id)
|
||||
|
||||
# Refresh data
|
||||
# - all items refresh all data except id
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Package declaring Pype version."""
|
||||
__version__ = "3.10.0-nightly.2"
|
||||
__version__ = "3.10.0-nightly.5"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "OpenPype"
|
||||
version = "3.10.0-nightly.2" # OpenPype
|
||||
version = "3.10.0-nightly.5" # OpenPype
|
||||
description = "Open VFX and Animation pipeline with support."
|
||||
authors = ["OpenPype Team <info@openpype.io>"]
|
||||
license = "MIT License"
|
||||
|
|
|
|||
12
start.py
12
start.py
|
|
@ -386,18 +386,6 @@ def set_modules_environments():
|
|||
modules_manager = ModulesManager()
|
||||
|
||||
module_envs = modules_manager.collect_global_environments()
|
||||
publish_plugin_dirs = modules_manager.collect_plugin_paths()["publish"]
|
||||
|
||||
# Set pyblish plugins paths if any module want to register them
|
||||
if publish_plugin_dirs:
|
||||
publish_paths_str = os.environ.get("PYBLISHPLUGINPATH") or ""
|
||||
publish_paths = publish_paths_str.split(os.pathsep)
|
||||
_publish_paths = {
|
||||
os.path.normpath(path) for path in publish_paths if path
|
||||
}
|
||||
for path in publish_plugin_dirs:
|
||||
_publish_paths.add(os.path.normpath(path))
|
||||
module_envs["PYBLISHPLUGINPATH"] = os.pathsep.join(_publish_paths)
|
||||
|
||||
# Merge environments with current environments and update values
|
||||
if module_envs:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue